{"schemaVersion":1,"record":{"key":"lesson/game-loop","type":"lesson","id":"game-loop","lang":"en","title":"The game loop and time","summary":"Separate simulation speed from frame rate and verify pauses, frame drops, and focus changes.","updatedAt":"2026-10-20","status":"active","url":"https://gamemechanics.pro/en/lessons/game-loop/","jsonUrl":"https://gamemechanics.pro/api/v1/knowledge/en/lesson/game-loop.json","markdownUrl":"https://gamemechanics.pro/content/knowledge/en/lesson/game-loop.md","aliases":[],"tags":["game-loop","time","simulation"],"sourceIds":["source-4794cbcf5206cc3d","source-61d9bfebd277d850","source-e55fb78e3762cd48"],"sources":[{"id":"source-4794cbcf5206cc3d","title":"Robert Nystrom: Game Loop","url":"https://gameprogrammingpatterns.com/game-loop.html","verifiedAt":null},{"id":"source-61d9bfebd277d850","title":"MDN: requestAnimationFrame","url":"https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame","verifiedAt":null},{"id":"source-e55fb78e3762cd48","title":"Glenn Fiedler: Fix Your Timestep!","url":"https://github.com/mas-bandwidth/gafferongames/blob/main/content/post/fix_your_timestep.md","verifiedAt":null}],"sections":[{"id":"prerequisites","title":"Prerequisites","body":"You only need variables, functions, and coordinates. By the end, you should be able to identify what updates the world, state the units of movement speed, and explain why a rendered frame is not necessarily one simulation step."},{"id":"principle","title":"The principle","body":"A game loop connects input, state updates, and presentation. The world can keep changing while the player stands still. An engine already owns this loop; connect your behavior to its appropriate update callbacks. [Game Loop](https://gameprogrammingpatterns.com/game-loop.html) explains this basic model.\n\nThe expression `x += 3` moves three units per call. More calls therefore produce more movement. The expression `x += speed * dt` describes movement through elapsed time, with speed in units per second and `dt` in seconds. This does not make every physics simulation stable for arbitrary time steps.\n\nA simulation sensitive to step size can use a fixed update interval. Accumulated real time is consumed in equal simulation steps, while rendering happens independently. Limiting catch-up steps requires a deliberate overload policy, such as letting simulation time fall behind. [Fix Your Timestep!](https://github.com/mas-bandwidth/gafferongames/blob/main/content/post/fix_your_timestep.md) explores that tradeoff.\n\n<span id=\"a-concrete-exercise\"></span>"},{"id":"example","title":"Practical example","body":"### A concrete exercise\n\nStart with one square and no collisions. Give it a speed of 120 units per second. After two seconds of uninterrupted movement, it should travel 240 units, regardless of how many frames were displayed.\n\n```text\nupdate(dtSeconds, input):\n    if input.moveRight:\n        player.x += 120 * dtSeconds\n\nrender():\n    drawSquare(player.x, player.y)\n```\n\nThis is teaching pseudocode, not a complete engine loop. Call `update` 120 times using `1/60`, then run a fresh case with 60 calls using `1/30`. Compare final positions with a small numerical tolerance. Finally, try uneven intervals whose sum is still two seconds.\n\nIn a browser, `requestAnimationFrame` schedules a callback (a function run by the browser) before repainting and normally pauses in background tabs. Its timestamp uses milliseconds; see the [MDN reference](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame). Define a resume policy. For this exercise, discard the old timestamp when focus returns so that the square continues from a paused position."},{"id":"mistakes","title":"Common mistakes","body":"Do not modify movement in both physics and presentation callbacks. Do not multiply by elapsed time twice when an engine method already handles it. Do not start another loop whenever the level restarts. Hiding a tab is also not a complete pause implementation: audio, network events, and timers may follow different lifecycles.\n\nCheck raw movement before introducing interpolation. Once the simulation is correct, add visual smoothing as a separate change. A smooth picture can otherwise conceal incorrect speed or update order."},{"id":"checks","title":"Verify it","body":"- Equal simulation time produces equal travel at different update frequencies.\n- Pausing stops the intended systems while keeping the menu usable.\n- Returning from a background tab does not teleport the player.\n- Restarting the scene does not double movement speed.\n- Variable names or comments make time and speed units explicit."},{"id":"agent-task","title":"Prompt for an AI agent","body":"> Locate the owner of the game loop and every place that changes player position. Explain the units of speed and elapsed time. Propose the smallest fix for frame-rate-dependent movement, then check travel over two seconds with several dt sequences. State pause and focus-resume behavior separately. Do not replace the physics backend without evidence that it is necessary."}],"relations":[{"type":"requires","direction":"outgoing","label":"Before you start","key":"lesson/scope-and-prototype","title":"Scope and a testable prototype","url":"https://gamemechanics.pro/en/lessons/scope-and-prototype/","jsonUrl":"https://gamemechanics.pro/api/v1/knowledge/en/lesson/scope-and-prototype.json","markdownUrl":"https://gamemechanics.pro/content/knowledge/en/lesson/scope-and-prototype.md"},{"type":"requires","direction":"incoming","label":"Continue learning","key":"lesson/input-and-feedback","title":"Input and feedback","url":"https://gamemechanics.pro/en/lessons/input-and-feedback/","jsonUrl":"https://gamemechanics.pro/api/v1/knowledge/en/lesson/input-and-feedback.json","markdownUrl":"https://gamemechanics.pro/content/knowledge/en/lesson/input-and-feedback.md"},{"type":"requires","direction":"incoming","label":"Continue learning","key":"lesson/collision-basics","title":"Collision fundamentals","url":"https://gamemechanics.pro/en/lessons/collision-basics/","jsonUrl":"https://gamemechanics.pro/api/v1/knowledge/en/lesson/collision-basics.json","markdownUrl":"https://gamemechanics.pro/content/knowledge/en/lesson/collision-basics.md"},{"type":"requires","direction":"incoming","label":"Continue learning","key":"lesson/performance-budget","title":"A performance budget","url":"https://gamemechanics.pro/en/lessons/performance-budget/","jsonUrl":"https://gamemechanics.pro/api/v1/knowledge/en/lesson/performance-budget.json","markdownUrl":"https://gamemechanics.pro/content/knowledge/en/lesson/performance-budget.md"},{"type":"contains","direction":"incoming","label":"Learning paths","key":"path/first-prototype","title":"Your first verifiable prototype","url":"https://gamemechanics.pro/en/learn/first-prototype/","jsonUrl":"https://gamemechanics.pro/api/v1/knowledge/en/path/first-prototype.json","markdownUrl":"https://gamemechanics.pro/content/knowledge/en/path/first-prototype.md"},{"type":"requires","direction":"incoming","label":"Continue learning","key":"path/npc-behavior","title":"NPC behavior","url":"https://gamemechanics.pro/en/learn/npc-behavior/","jsonUrl":"https://gamemechanics.pro/api/v1/knowledge/en/path/npc-behavior.json","markdownUrl":"https://gamemechanics.pro/content/knowledge/en/path/npc-behavior.md"},{"type":"uses","direction":"outgoing","label":"Sources in the selection","key":"resource/game-loop-pattern","title":"Game Loop: Game Programming Patterns","url":"https://gamemechanics.pro/en/resources/#resource-game-loop-pattern","jsonUrl":"https://gamemechanics.pro/api/v1/knowledge/en/resource/game-loop-pattern.json","markdownUrl":"https://gamemechanics.pro/content/knowledge/en/resource/game-loop-pattern.md"},{"type":"uses","direction":"outgoing","label":"Sources in the selection","key":"resource/animation-frame","title":"requestAnimationFrame on MDN","url":"https://gamemechanics.pro/en/resources/#resource-animation-frame","jsonUrl":"https://gamemechanics.pro/api/v1/knowledge/en/resource/animation-frame.json","markdownUrl":"https://gamemechanics.pro/content/knowledge/en/resource/animation-frame.md"},{"type":"uses","direction":"outgoing","label":"Sources in the selection","key":"resource/fixed-timestep","title":"Fix Your Timestep!","url":"https://gamemechanics.pro/en/resources/#resource-fixed-timestep","jsonUrl":"https://gamemechanics.pro/api/v1/knowledge/en/resource/fixed-timestep.json","markdownUrl":"https://gamemechanics.pro/content/knowledge/en/resource/fixed-timestep.md"}],"placements":[],"supersededBy":[],"attributes":{"category":"foundations","level":"beginner","minutes":6},"endsAt":null,"provenance":"Original gamemechanics.pro material. Check illustrative examples in your own project.","license":"CC-BY-4.0","codeLicense":"MIT","attribution":"gamemechanics.pro contributors"}}