Skip to content
Lesson 2 of 14

Step 1 of 5 · Reading · ~3 min

Read

Game Loop

The Game Loop

The loop is where an engine decides how much simulated time passes for each frame it draws. After this lesson your program will run a fixed-timestep loop: for every rendered frame it works out how many simulation steps to run, then says where to draw a moving body between the last two steps.

Why the step cannot just be the frame time

The naive loop reads input, updates, draws, and repeats as fast as it can. Feeding the measured frame time into the update (a variable timestep) makes motion frame-rate independent, but it has costs:

  • Different machines, different results. The same inputs integrate over different step sizes, so replays, tests and lockstep networking diverge.
  • Instability. Physics that is stable at 16 ms can explode at 80 ms, because integration error grows with the step.
  • Tunnelling. A longer step moves a body further, so it jumps over thin walls.

A fixed timestep removes all three: the simulation only ever advances in steps of exactly step milliseconds, however long the frame took.

The accumulator

Frames take arbitrary time, but the simulation wants whole steps. Keep a bank of real time that has passed but has not been simulated yet. Each frame, add the frame time to the bank; then, while the bank holds at least one step, simulate one step and take one step out of the bank. The remainder stays for the next frame.

Pseudocode:

bank += min(frame_time, max_frame)
while bank >= step:
    advance the world by one step
    bank -= step

A frame can therefore run zero steps (fast frame), one (typical) or several (slow frame). Over a second the total is the same: simulated time tracks real time.

Drawing between steps

After spending, the bank holds between 0 and step milliseconds: how far real time has moved past the last simulated state. The ratio alpha = bank / step says how far through the next step the display is. Keep the body's position before the last step and after it, and draw at

draw = before + (after - before) * alpha

Without this, a run of frames with 0, 2, 1, 0, 2 steps shows the body standing still, then jumping, and the motion judders even though the simulation is perfect. The price is that you always draw slightly in the past, by up to one step.

The spiral of death

If one step costs more real time to compute than the step it simulates, each frame falls further behind, so the next frame needs more steps, which takes longer still, and the game freezes. The standard fix is to clamp the frame time before banking it (max_frame). The simulation then runs in slow motion under load instead of hanging.

Worked trace

step = 10, max_frame = 50, the body moves 3 units per step, and frames take 7, 7, 25 and 120 ms:

frame    banked   steps   bank left   before->after   alpha   draw
  7         7       0         7          0 -> 0         0.7     0.0
  7        14       1         4          0 -> 3         0.4     1.2
 25        29       2         9          6 -> 9         0.9     8.7
120->50    59       5         9         21 -> 24        0.9    23.7

Row 3 ran two steps but interpolates only across the last one (6 to 9). Row 4's 120 ms frame was clamped to 50, so 70 ms of real time was dropped.

Common mistakes

  • Running at most one step per frame. A 60 ms frame with a 20 ms step needs three.
  • Resetting the bank to zero after stepping. The remainder is lost every frame and the world runs slow.
  • Interpolating from where the body was at the start of the frame. Use the state before the last step.
  • Drawing the current state with no alpha. Frames with zero steps then repeat the previous picture exactly.
  • Clamping after banking, or not at all.

Your exercise

Implement the loop described in the exercise. The starter parses the script and prints each frame; you write the clamp, the bank and the stepping. The most likely mistake is interpolating from the wrong state.

Up nextInput HandlingGame Loop

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…