Game Loop

Create a fixed time step Game Loop

Game Loop

What’s a Game Loop ? If you’ve read the tutorials Graphics Window and OpenGL Window, you know about the Infinite Loop that maintains your game window visible. Most of your game will happen inside that loop, this is why we call it the Game Loop.  Inside that loop, you perform three actions at each frame of your game

  • Capture the user Inputs
  • Update the Game
  • Render the Game
Let’s take the game Super Mario for example, when you press the right-arrow of your D-Pad, Mario will walk right. How is that happening ?
  • First, the game will capture your inputs (pressing on the right-arrow of the D-Pad).
  • Then, the game will update Mario’s position and animation to make it move to the right.
  • Finally, the game will draw Mario at its new position with the correct animation pose.
Those three operations Capture Inputs, Update and Render happen at each frame of your Game. If you have a game running at 60 FPS (Frame Per Second) then those three operations happen 60 times during one second, If you have a game running at 120 FPS, those operations will happen 120 times during one second. I’ve oversimplified the idea here, but if you never heard about a game loop, that’s the best way to picture it.
 
The code below shows a really simple Game Loop.
bool gameRunning = true;
while(gameRunning)
{
    captureInputs(); //Keyboard, Mouse, GamePad, etc.
    updateGame(); //update object position, animations, health bar, etc.
    renderGame(); //draw all game objects
}

Fixed Time Step

The code above shows an oversimplified Game Loop. Depending on the situation, such a game loop will be inefficient. The main problem here is if you run that same game loop on different computers, the loop may cycle at a different speed for each computer depending on their power. A powerful computer (with more CPU/GPU/Ram) will run the game faster than a less powerful computer, which means that the people playing your game will have a different experience, like if they are not playing the same game. How do we make sure that the game runs at the same speed for everyone ?
 
The code below shows how we can compute the time passed during each loop cycle and force the game to run at the speed we desire. The idea is pretty simple
 
  • Step 1 : Let’s suppose we want to run our game at 60 FPS, which means each frame should last 1/60 seconds (or 0.0166). We call that time Fixed Time
  • Step 2 : We start a clock and measure the time that passes and store it into a variable called Time Passed.
  • Step 3 : When Time Passed equals Fixed Time (1/60 seconds here), we perform the game loop operations (capture inputs, update, and render)
  • Step 4 : Then we set Time Passed at zero and repeat the process again and again.
It’s quite difficult to check if Time Passed equal exactly 1/60 seconds (or 0.0166). Instead of checking the equality, the code below checks if Time Passed is superior to Fixed Time. In this case Step 3 and Step 4 become the followings:
  • Step 3 : When Time Passed is superior to Fixed Time (1/60 seconds here), we perform the game loop operations (capture inputs, update and render)
  • Step 4 : We subtract Fixed Time from Time Passed in order to get the time overflow, this overflow is reported to the next frame. For example, if Time Passed is 0.018 seconds, it’s superior to Fixed Time (0.0166), we update the game, then we compute the overflow (0.018 – 0.0166 =  0.0014). Those 0.0014 seconds will be counted for the next frame.
//Start a clock
Clock clock;
clock.start();
//Save the time that passes
Time timePassed = 0;
bool gameRunning = true;
while(gameRunning)
{
    //Get the time measure by the clock
    Time clockTime = clock.getTime();
    clock.reset();
    //Accumulate the time that passes
    timePassed += clockTime;
    //When the time that passes is over the Fixed Time, perform the game operations
    if(timePassed > FIXED_TIME)
    {
        //remove FIXED_TIME and keep the overflow for the next frame
        timePassed - FIXED_TIME;
        captureInputs(); //Keyboard, Mouse, GamePad etc
        updateGame(FIXED_TIME); //update object position, animations, health bar etc.
        renderGame(); //draw all game objects
    }
}

More about Game Loops

There isn’t a single way to create a Game Loop. Depending on your needs a Game Loop can be really simple or become complicated. If you want to learn more about Game Loops, you can read this article : Game Loop Patterns. In this article, the authors present different Game Loop techniques and how to choose between them:

  • Pattern 1 : Run, run as fast as you can (Our oversimplified game loop)
  • Pattern 2 : Take a little nap (Pattern 1 with sleep)
  • Pattern 3 : One small step, one giant step (Use a clock, resemble the one we created above)
  • Pattern 4 : Play catch up (Use a clock, resemble the one we created above but more complicated)

SFML Game Loop

Let’s create an actual Game Loop with SFML. We will use the pattern presented above (Fixed Time Step) but with a little difference. Only the first two game loop operations (Capture Inputs and Update) will happen at Fixed Time (60 FPS in this case). The Render operation will happen as fast as the computer running the game can handle it. This is the Game Loop that we will be using during the rest of this Tutorial Series

//Create our fixed time for 60 FPS (0.0166 seconds)
sf::Time FIXED_FRAME_TIME = sf::seconds(1/60.f);
//Variable to store the time that passes
sf::Time timePassed = sf::Time::Zero;
//Create a clock, the clock starts automatically
sf::Clock clock;
//Entering the game loop
while(graphicsWindow.isOpen())
{
    //Retrieve the clock time and reset the clock at the same time
    sf::Time clockTime = clock.restart();
    //Accumulate the time passing in our variable (this happens at each cycle of the while loop)
    timePassed += clockTime;
    //When the time passing is over our Fixed Time only Capture Inputs and Update the Game
    while(timePassed > FIXED_FRAME_TIME)
    {
        //Remove (0.0166) seconds from the passing time
        //Only the overflow will remain for the next frame
        timePassed -= FIXED_FRAME_TIME;
        //capture the user inputs using SFML Events
        handleEvent();
        //update the game at the fixed time frame of (0.0166 second)
        update(FIXED_FRAME_TIME);
    }
    //Render the game
    //We do not render the game at 60 FPS, only the update happens at 60 FPS
    render();
}