Game Dev 101
Progress
0/22

Lesson 3 of 22, in world 1: Foundations

Delta Time & Fixed Timesteps

Time
About 15 min
Builds on
The Game Loop

Frames don’t arrive at a perfectly steady pace. One frame takes 16 ms, the next 21 ms, and a player on a 144 Hz monitor gets more than twice as many frames as one on a 60 Hz laptop. If you move things “a bit per frame”, your game runs at a different speed on every computer. The fix is delta time.

What is delta time?

Delta time (dt) is the number of seconds since the previous frame — about 0.0167 at 60 FPS. Instead of “move 2 pixels per frame”, you say “move 130 pixels per second” and multiply by how many seconds actually passed:

JavaScript
let last = performance.now()
function loop(now) {
  const dt = (now - last) / 1000  // milliseconds → seconds
  last = now
  player.x += player.speed * dt   // speed is in pixels per SECOND
  render()
  requestAnimationFrame(loop)
}
LiveFrame-based vs. time-based movement

Both racers are tuned to cross the track in 4 seconds on a 60 FPS machine. Drag the slider to simulate a slow laptop (15 FPS) or a gaming monitor (144 FPS). The pink racer's speed depends on the machine; the cyan one is always on time.

Timers are just numbers

JavaScript
let cooldown = 0
function update(dt) {
  cooldown -= dt                    // counts down in real seconds
  if (input.fire && cooldown <= 0) {
    spawnBullet()
    cooldown = 0.25                 // 4 shots per second, on any machine
  }
}

When variable dt goes wrong: tunnelling

If a frame takes a long time (a hitch, a slow machine, a background tab), dt becomes large, and fast objects take huge steps. A bullet can be in front of a wall in one frame and behind it the next, so the collision check never sees an overlap. Physics also becomes less accurate and less repeatable.

LiveTunnelling and the fixed timestep

Bullets fly at 900 px/s toward a 10 px wall. With a big delta time a bullet can jump from one side of the wall to the other in a single step and never 'touch' it. A fixed timestep runs physics in small, equal steps (1/120 s) no matter how slowly the screen renders.

The fixed timestep

The standard fix: keep rendering as fast as the screen allows, but run the simulation in small, constant steps. Accumulate real time, and spend it in fixed slices:

JavaScript
const STEP = 1 / 60   // physics always advances in exact 1/60 s steps
let accumulator = 0

function loop(now) {
  const frameTime = Math.min((now - last) / 1000, 0.25) // clamp huge hitches
  last = now
  accumulator += frameTime
  while (accumulator >= STEP) {
    physicsUpdate(STEP)       // deterministic, same on every machine
    accumulator -= STEP
  }
  render()
  requestAnimationFrame(loop)
}

Key takeaways

  • dt = seconds since last frame. Express speeds in units per second and multiply by dt.
  • Timers, cooldowns and animations are numbers that count down by dt.
  • Large dt causes tunnelling and unstable physics. Clamp dt, and use a fixed timestep for physics.

Check yourself

Q1. A ship moves at 200 px/s. The frame took 0.05 s. How far should it move this frame?

Q2. Why does "x += 3" every frame run faster on a 144 Hz monitor?

Q3. What does a fixed timestep give you?

Exercises

  1. In the race demo, at what FPS does the pink racer finish at exactly the same time as the cyan one? Why?
  2. In the tunnelling demo, find the lowest frame rate at which bullets still hit the wall without the fixed timestep.
  3. Write a "flash every 0.5 seconds" blinking text using only a timer variable and dt.