Making a Lunar Lander in JavaScript

Animating Shapes

In this lesson, we will explain how animations are usually made on computers and how you can implement one yourself in HTML5 canvas.

Frames

Did you know that any animation you see on a screen today is just pictures changing really quickly? Well, it is. Most of it. It's your brain that's smart (or stupid?) and connects these pictures together to make it seem like something is actually moving.

We call each of these pictures a frame.

Framerate

If you've played any games you might've heard the term framerate. The framerate is a measurement that tells us how many frames are painted in one second—in other words, how many times the picture changes in one second.

So, in order to animate, we have to redraw our canvas many times per second. The framerate at which most monitors run today is 60 frames per second, which means there are 16.666... milliseconds (that's 0.016 seconds!) to draw a single frame. However, our program is likely to finish drawing in much less time, even as little as 1 millisecond. This is much quicker than the screen can refresh, so it is really useless to keep executing all that code, we simply waste processing power for nothing. Luckily, there is a simple solution to this problem.

requestAnimationFrame()

The requestAnimationFrame() function is available in every browser and allows us to execute a function whenever canvas needs to be redrawn:

requestAnimationFrame(your_function);

So if we pass our function that draws on the canvas, it will postpone its execution until a new frame has to be created. And if we do that again it postpone that function again. So we keep doing this in order to get a smooth animation without wasting any processing power.

Our first animation

Here's how we can make a circle move across the screen:

var canvas = document.getElementById("game");
var context = canvas.getContext("2d");

var x = 0;

function draw() {

  // clearing the canvas
  context.clearRect(0, 0, canvas.width, canvas.height);

  // drawing a black circle
  context.beginPath();
  context.arc(x, 100, 25, 0, 2*Math.PI);
  context.fillStyle = "black";
  context.fill();

  // incrementing the x coordinate by one on each frame
  x = x + 1;

  // if x coordinate exceeds the width, reset it to 0.
  if (x > canvas.width) x = 0;

  // call draw() again when a new frame needs to be drawn
  requestAnimationFrame(draw);
}

draw();

Notice that we have to run our function at the end in order to start the whole process. We could've also replaced the last line:

draw();

with:

requestAnimationFrame(draw);

and we would still get the same thing.

We can now move to the most fun part of the game—creating the spaceship!