This article was peer reviewed by Andrew Ray and Sebastian Seitz. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

The “game loop” is a name given to a technique used to render animations and games with changing state over time. At its heart is a function that runs as many times as possible, taking user input, updating the state for the elapsed time, and then drawing the frame.

In this short article you’ll learn how this fundamental technique works and you’ll be able to start making your own browser based games and animations.

Here’s what game loop in JavaScript looks like:

function update ( progress ) { } function draw ( ) { } function loop ( timestamp ) { var progress = timestamp - lastRender update ( progress ) draw ( ) lastRender = timestamp window . requestAnimationFrame ( loop ) } var lastRender = 0 window . requestAnimationFrame ( loop )

The requestAnimationFrame method requests that the browser call a specified function as soon as it can before the next repaint occurs. It’s an API specifically for rendering animations but you can also use setTimeout with a short timeout for a similar result. requestAnimationFrame is passed a timestamp of when the callback started firing, it contains the number of milliseconds since the window loaded and is equal to performance.now().

The progress value, or time between renders is crucial for creating smooth animations. By using it to adjust the x and y positions in our update function, we ensure our animations move at a consistent speed.

Updating the Position

Our first animation will be super simple. A red square that moves to the right until it reaches the edge of the canvas and loops back around to the start.

We’ll need to store the square’s position and increment the x position in our update function. When we hit a boundary we can subtract the canvas width to loop back around.

var width = 800 var height = 200 var state = { x : width / 2 , y : height / 2 } function update ( progress ) { state . x += progress if ( state . x > width ) { state . x -= width } }

Drawing the New Frame

This example uses the <canvas> element for rendering the graphics but the game loop can be used with other outputs like HTML or SVG documents too.

The draw function simply renders the current state of the world. On each frame we’ll clear the canvas and then draw a 10px red square with its center at the position stored in our state object.

var canvas = document . getElementById ( "canvas" ) var width = canvas . width var height = canvas . height var ctx = canvas . getContext ( "2d" ) ctx . fillStyle = "red" function draw ( ) { ctx . clearRect ( 0 , 0 , width , height ) ctx . fillRect ( state . x - 5 , state . y - 5 , 10 , 10 ) }

And we have movement!

See the Pen Game Loop in JavaScript: Basic Movement by SitePoint (@SitePoint) on CodePen.

Note: In the demo you might notice that the size of the canvas has been set in both the CSS and via width and height attributes on the HTML element. The CSS styles set the actual size of the canvas element that will be drawn to the page, the HTML attributes set the size of the coordinate system or ‘grid’ that the canvas API will use. See this Stack Overflow question for more information.

Responding to User Input

Next we’ll get keyboard input to control the position of our object, state.pressedKeys will keep track of which keys are pressed.

var state = { x : ( width / 2 ) , y : ( height / 2 ) , pressedKeys : { left : false , right : false , up : false , down : false } }

Let’s listen to all keydown and keyup events and update state.pressedKeys accordingly. The keys I’ll be using are D for right, A for left, W for up and S for down. You can find a list of key codes here.

var keyMap = { 68 : 'right' , 65 : 'left' , 87 : 'up' , 83 : 'down' } function keydown ( event ) { var key = keyMap [ event . keyCode ] state . pressedKeys [ key ] = true } function keyup ( event ) { var key = keyMap [ event . keyCode ] state . pressedKeys [ key ] = false } window . addEventListener ( "keydown" , keydown , false ) window . addEventListener ( "keyup" , keyup , false )

Then we just need to update the x and y values based on the pressed keys and ensure that we keep our object within the boundaries.

function update ( progress ) { if ( state . pressedKeys . left ) { state . x -= progress } if ( state . pressedKeys . right ) { state . x += progress } if ( state . pressedKeys . up ) { state . y -= progress } if ( state . pressedKeys . down ) { state . y += progress } if ( state . x > width ) { state . x -= width } else if ( state . x < 0 ) { state . x += width } if ( state . y > height ) { state . y -= height } else if ( state . y < 0 ) { state . y += height } }

And we have user input!

See the Pen Game Loop in Javascript: Dealing with User Input by SitePoint (@SitePoint) on CodePen.

Asteroids

Now that we have the fundamentals under our belt we can do something more interesting.

It’s not that much more complex to make a ship like was seen in the classic game Asteroids.

Our state needs to store an additional vector(an x,y pair) for movement as well as a rotation for the ships direction.

var state = { position : { x : ( width / 2 ) , y : ( height / 2 ) } , movement : { x : 0 , y : 0 } , rotation : 0 , pressedKeys : { left : false , right : false , up : false , down : false } }

Our update function needs to update three things:

rotation based on the left/right pressed keys

movement based on the up/down keys and rotation

position based on the movement vector and the boundaries of the canvas

function update ( progress ) { var p = progress / 16 updateRotation ( p ) updateMovement ( p ) updatePosition ( p ) } function updateRotation ( p ) { if ( state . pressedKeys . left ) { state . rotation -= p * 5 } else if ( state . pressedKeys . right ) { state . rotation += p * 5 } } function updateMovement ( p ) { var accelerationVector = { x : p * .3 * Math . cos ( ( state . rotation - 90 ) * ( Math . PI / 180 ) ) , y : p * .3 * Math . sin ( ( state . rotation - 90 ) * ( Math . PI / 180 ) ) } if ( state . pressedKeys . up ) { state . movement . x += accelerationVector . x state . movement . y += accelerationVector . y } else if ( state . pressedKeys . down ) { state . movement . x -= accelerationVector . x state . movement . y -= accelerationVector . y } if ( state . movement . x > 40 ) { state . movement . x = 40 } else if ( state . movement . x < - 40 ) { state . movement . x = - 40 } if ( state . movement . y > 40 ) { state . movement . y = 40 } else if ( state . movement . y < - 40 ) { state . movement . y = - 40 } } function updatePosition ( p ) { state . position . x += state . movement . x state . position . y += state . movement . y if ( state . position . x > width ) { state . position . x -= width } else if ( state . position . x < 0 ) { state . position . x += width } if ( state . position . y > height ) { state . position . y -= height } else if ( state . position . y < 0 ) { state . position . y += height } }

The draw function translates and rotates the canvas origin before drawing the arrow shape.

function draw ( ) { ctx . clearRect ( 0 , 0 , width , height ) ctx . save ( ) ctx . translate ( state . position . x , state . position . y ) ctx . rotate ( ( Math . PI / 180 ) * state . rotation ) ctx . strokeStyle = 'white' ctx . lineWidth = 2 ctx . beginPath ( ) ctx . moveTo ( 0 , 0 ) ctx . lineTo ( 10 , 10 ) ctx . lineTo ( 0 , - 20 ) ctx . lineTo ( - 10 , 10 ) ctx . lineTo ( 0 , 0 ) ctx . closePath ( ) ctx . stroke ( ) ctx . restore ( ) }

That’s all the code that we need to re-create a ship like in Asteroids. The keys for this demo are the same as in the previous one ( D for right, A for left, W for up and S for down).

See the Pen Game Loop in JavaScript: Recreating Asteroids by SitePoint (@SitePoint) on CodePen.

I’ll leave it to you to add the asteroids, bullets and collision detection 😉

Level Up

If you have found this article interesting you will enjoy watching Mary Rose Cook live-code Space Invaders from scratch for a more complex example, it’s a few years old now but is an excellent intro to building games in the browser. Enjoy!