Search code examples
c++loopssdl

Why does this elapsed time (frametime) calculation lockup my game


currently I am trying to implement a fixed-step game loop but somehow my code seems to lockup my game.


Uint32 SDL_GetTicks(void) : Returns an unsigned 32-bit value representing the number of milliseconds since the SDL library initialized.

This works:

1.cc)

Uint32 FPS = 60;
Uint32 MS_PER_SEC = 1000 / FPS;
Uint32 current_time, last_time, elapsed_time;
current_time = last_time = elapsed_time = 0;

while(Platform.Poll())
{
    current_time = SDL_GetTicks(); // Get time of frame begin

    // Clear Window
    Renderer.Clear();

    // Update Input
    //...

    // Draw
    Renderer.Draw();

    // Update Window
    Renderer.Update();

    last_time = SDL_GetTicks(); // Get time of frame end
    elapsed_time = last_time - current_time; // calculate frametime

    SDL_Delay(MS_PER_SEC - elapsed_time);
}

However this does not:

2.cc)

Uint32 FPS = 60;
Uint32 MS_PER_SEC = 1000 / FPS;
Uint32 current_time, last_time, elapsed_time;
current_time = elapsed_time = 0;

last_time = SDL_GetTicks();

// Poll for Input
while(Platform.Poll())
{
    current_time = SDL_GetTicks();
    elapsed_time = current_time - last_time;

    // Clear Window
    Renderer.Clear();

    // Update Input
    //...

    // Draw
    Renderer.Draw();

    // Update Window
    Renderer.Update();

    last_time = current_time;
    SDL_Delay(MS_PER_SEC - elapsed_time);
}

I expect the results of 1.cc and 2.cc to be the same, meaning that SDL_Delay(MS_PER_SEC - elapsed_time) does delay by a fixed time minus frametime (here 16 - frametime). But 2.cc does lockup my game.

Is not the elapsed_time (frametime) calculation from 2.cc equivalent to 1.cc ?


Solution

  • Let's unroll the loop a little...

    // First iteration
    
    last_time = SDL_GetTicks();
    current_time = SDL_GetTicks();
    elapsed_time = current_time - last_time; // Probably zero
    
    ...
    
    SDL_Delay(MS_PER_SEC - elapsed_time);    // Probably a whole second
    
    // Second iteration
    
    current_time = SDL_GetTicks();
    elapsed_time = current_time - last_time; // Probably slightly more than a whole second
    
    ...
    
    SDL_Delay(MS_PER_SEC - elapsed_time);    // Probably negative (4 billion milliseconds)