Game Loops

In order for real-time games to present an unfolding and dynamic world to the player, they must update and render the world frequently, independent of player input. This updating needs to occur fast enough to cause the human brain to perceive on-screen animations as a moving scene, rather than a series of pictures.

Generally speaking, this means at least 16 frames need to be displayed every second, though higher numbers can create a smoother feel. Most games use either 30 or 60 frames per second, as this aligns with the refresh rate of most monitors. The game loop itself can be clamped to this rate (a fixed timestep) or can run as fast as possible (a variable time step). Good practice is to limit your game loop to the highest expected monitor refresh rate - this allows you to gain the benefits of more visible frames without doing excessive calculations (and the corresponding power consumption and heat generation).

The basic structure of a game loop is:

var gameNotOver = true while(gameNotOver) { processInput(); update(); render(); }

JavaScript Game Loops

However, there is tremendous variability possible in this simple pattern. In JavaScript, best practice is to use the requestAnimationFrame global function. This function takes a callback which it invokes when browser repaints. In many cases, this will be synchronized with the monitor refresh rate. Or, in some cases it may be invoked less frequency to preserve battery life, etc.

This approach requires us to refactor our game loop into a callback function:

function loop() { processInput(); update(); render(); requestAnimationFrame(loop); } requestAnimationFrame(loop);

Note the loop is refactored into a recursive function call; but otherwise it is pretty much the same. However, while the invocation is invoked at the same rate as the browser's repainting cycle, it is not necessarily fixed, nor will it necessarily be the same rate given the browser and hardware it is running on. For this reason, the callback function is supplied with a high-resolution timestamp (in milliseconds). We can calculate the elapsed time between frames from this timestamp:

var start = null; function loop(timestamp) { if(!start) start = timestamp; var elapsedTime = timestamp - start; start = timestamp; processInput(); update(elapsedTime); render(elapsedTime); requestAnimationFrame(loop); } requestAnimationFrame(loop);

We can then pass the elapsedTime into the update() and render() functions to compute accurate physics and animations. In actuality, we are looking at the time that elapsed during the previous frame, but in practice this can serve as a good stand-in for the current frame's speed.