Sean Latham
Sean Latham

Reputation: 250

FPS stutter - game running at double FPS specified?

I have managed to create a system that allows game objects to move according to the change in time (rather than the change in number of frames). I am now, for practise's sake, trying to impose a FPS limiter.

The problem I'm having is that double the amount of game loops are occurring than what I expect. For example, if I try to limit the number of frames to 1 FPS, 2 frames will pass in that one second - one very long frame (~1 second) and 1 extremely short frame (~15 milliseconds). This can be shown by outputting the difference in time (in milliseconds) between each game loop - an example output might be 993, 17, 993, 16...

I have tried changing the code such that delta time is calculated before the FPS is limited, but to no avail.

Timer class:

#include "Timer.h"
#include <SDL.h>

Timer::Timer(void)
{
    _currentTicks = 0;
    _previousTicks = 0;
    _deltaTicks = 0;

    _numberOfLoops = 0;
}

void Timer::LoopStart()
{
    //Store the previous and current number of ticks and calculate the
    //difference. If this is the first loop, then no time has passed (thus
    //previous ticks == current ticks).
    if (_numberOfLoops == 0)
        _previousTicks = SDL_GetTicks();
    else
        _previousTicks = _currentTicks;

    _currentTicks = SDL_GetTicks();

    //Calculate the difference in time.
    _deltaTicks = _currentTicks - _previousTicks;

    //Increment the number of loops.
    _numberOfLoops++;
}

void Timer::LimitFPS(int targetFps)
{ 
    //If the framerate is too high, compute the amount of delay needed and
    //delay.
    if (_deltaTicks < (unsigned)(1000 / targetFps))
        SDL_Delay((unsigned)(1000 / targetFps) - _deltaTicks);
}

(Part of the) game loop:

//The timer object.
Timer* _timer = new Timer();

//Start the game loop and continue.
while (true)
{
    //Restart the timer.
    _timer->LoopStart();

    //Game logic omitted

    //Limit the frames per second.
    _timer->LimitFPS(1);
}

Note: I am calculating the FPS using a SMA; this code has been omitted.

Upvotes: 0

Views: 374

Answers (2)

Matt Kaes
Matt Kaes

Reputation: 198

The problem is part of how your timer structure is setup.

_deltaTicks = _currentTicks - _previousTicks;

I looked though the code a few times and based on how you have the timer setup this seems to be the problem line.

Walking though it at the start of your code _currentTicks will equal 0 and _previousTicks will equal 0 so for the first loop your _deltaTicks will be 0. This means regardless of your game logic LimitFPS will misbehave.

void Timer::LimitFPS(int targetFps)
{ 
    if (_deltaTicks < (unsigned)(1000 / targetFps))
        SDL_Delay((unsigned)(1000 / targetFps) - _deltaTicks);
}

We just calculated that _deltaTicks was 0 at the start of the loop, thus we wait the full 1000ms regardless of what happens in your game logic.

On the next frame we have this, _previousTicks will equal 0 and _currentTicks will now equal approximately 1000ms. This means the _deltaTicks will be equal to 1000.

Again we hit the LimitFPS function but this time with a _deltaTicks of 1000 which makes it so we wait for 0ms.

This behavior will constantly flip like this.

wait 1000ms
wait 0ms
wait 1000ms
wait 0ms
...

those wait 0ms essentially double your FPS.

You need to test for time at the start and end of your game logic.

//The timer object.
Timer* _timer = new Timer();

//Start the game loop and continue.
while (true)
{
    //Restart the timer.
    _timer->LoopStart();

    //Game logic omitted

    //Obtain the end time
    _timer->LoopEnd();

    //Now you can calculate the delta based on your start and end times.
    _timer->CaculateDelta();

    //Limit the frames per second.
    _timer->LimitFPS(1);
}

Hope that helps.

Upvotes: 1

pag3faul7
pag3faul7

Reputation: 428

Assuming your gameloop is triggered only when SDL_Delay() expired wouldn't it be enough to write:

void Timer::LimitFPS(int targetFps)
{
    SDL_Delay((unsigned)(1000 / targetFps));
}

to delay your gameloop by the right amount of milliseconds depending on the requested target FPS?

Upvotes: -1

Related Questions