Skip to main content
← Make a Platformer

Lesson 4 of 4

A Camera That Follows

The world is now wider than the screen. You move the view instead of the player.

What you will learn

  • World and screen positions
  • ctx.save and ctx.restore
  • ctx.translate
  • Limiting the camera
  • A deadzone

Before you start

Platforms and Collisions. The level now goes past the right edge of the canvas.

What this stage does

Walk to the right. The view follows you. Walk back to the start and the view stops at the edge of the world. Jump high and the view moves up. It only moves after you leave the middle of the screen.

Two sets of positions

NameWhat it means
World positionWhere a thing really is. The world is 2000 wide. A platform at x: 1500 is always at 1500.
Screen positionWhere a thing appears on the 800 pixel canvas.

The camera is the difference between the two. camera.x and camera.y say where the bottom-left corner of the screen sits in the world. The screen is just another rectangle. The camera costs three lines in draw(). Everything drawn between save() and restore() is shifted by the camera. Everything drawn outside them stays still. That is what you want for a sky.

// Sky first, not shifted, so it never scrolls
ctx.fillStyle = "skyblue";
ctx.fillRect(0, 0, canvas.width, canvas.height);

ctx.save();
ctx.translate(-camera.x, camera.y);

//   ...draw the platforms and the player at their WORLD positions...

ctx.restore();   // put the camera back, ready for the next frame

Left and right: centre, then limit

// Try to keep the player in the middle of the screen
camera.x = player.x + player.width / 2 - canvas.width / 2;

// Do not scroll past either edge of the world
if (camera.x < 0) camera.x = 0;
if (camera.x > worldWidth - canvas.width)
    camera.x = worldWidth - canvas.width;

Without the two limits, you walk to the start of the level and see empty space beside the world. This is the same two-line pattern from stage 1. There you kept the player on screen. Here you use it on the view.

Up and down: the deadzone

You could centre the view up and down as well. Then the view jumps on every hop. That is unpleasant to play. Instead, the camera only moves when the player leaves a band in the middle of the screen. deadzoneY is how tall that band is, above and below the centre. Small hops do not move the view. Climbing high pulls the view along.

The camera's numbers

Set the deadzone to 0 and jump. The view lurches on every jump. Put it back to 80 and jump again.

80px

How far you can move up or down before the view follows. Set it to 0 and jump. That is the version with no deadzone.

2000px

How far right you can walk before the view stops.

15

Jump high enough to push past the deadzone.

const playerMiddleY = player.y + player.height / 2;
const screenMiddleY = camera.y + canvas.height / 2;

// Went above the band: pull the camera up
if (playerMiddleY > screenMiddleY + camera.deadzoneY) {
    camera.y = playerMiddleY - canvas.height / 2 - camera.deadzoneY;
}

// Went below the band: push the camera down
if (playerMiddleY < screenMiddleY - camera.deadzoneY) {
    camera.y = playerMiddleY - canvas.height / 2 + camera.deadzoneY;
}

// Do not scroll below the bottom of the world.
// The sky above has no limit, so there is no top edge to stop at.
if (camera.y < 0) camera.y = 0;

The left edge of the world is 0. The bottom of the world is 0 too. Both limits are the same line of code with a different letter in it.

Build it step by step

  1. Make the world too big

    Add platforms past x: 800 and set worldWidth to 2000. Change the player's limit from canvas.width to worldWidth. Play. You can walk off the right of the screen and vanish. The level is there. You just cannot see it.

  2. Move the view by hand

    Add const camera = { x: 0, y: 0 }. Add the save, translate, and restore lines to draw(). Set camera.x = 400 by hand and reload. The world slides across. Nothing follows the player yet. You can still see how it works.

  3. Follow the player

    Replace your hand-set value with the centring line in update(). The view now follows you. It also scrolls past the ends of the world.

  4. Limit the camera

    Add the two if statements for left and right. Walk to both ends and check that the view stops.

  5. Add vertical follow, twice

    First set camera.y with the same centring line you used for camera.x. Jump. The whole screen lurches every time. Now replace that line with the deadzone version. Jump again. Trying both versions teaches you more than any explanation.

Try these changes

Make these changes in the files beside this guide. Each one only uses what this lesson has already covered. Tick each one when it works.

Check yourself

Three quick questions on this lesson. Get them all right to finish the lesson and earn a pack.

Loading your answers

Teacher's versionHow to run this lesson, what to check, and any answers. Students do not need this.

How to teach it

  • Slow down on step 2. Setting camera.x by hand separates two questions. One is "what does translate do". The other is "how does following work". Students get lost when you teach both at once.
  • The signs confuse almost everyone. Stand at the board and move a piece of paper left. As you move it, say "the camera went right". Students learn from the gesture faster than from an explanation. Do the same gesture upward for the up and down camera. That one uses a plus sign because drawRect has already turned the picture over.
  • Do step 5 in the wrong order on purpose. A camera that lurches feels unpleasant within two jumps. The student then asks for the deadzone themselves.
  • Draw the deadzone as a horizontal band on the board. Mark the player inside it, above it, and below it. The two if statements match that picture exactly.