Tutorial: How to make a tile-based 2D scrolling game world in JavaScript

Lesson 1) The journey ahead

Don't stop - be readin'

Since you're on lesson 1, you must have completed lessons 1 to 6 of the How to make a top-down shooter in JavaScript tutorial. So now you have a red square that can move around a green game area with the WASD keys, just like this:

In this set up you have a static game area, and we update the player's x and y coordinates when we detect the relevant key-press inputs. To make him move around a world that's larger than the screen, we're going to lock the player into the center of the screen, and move all the other game elements around him.

So one way to do this would be, when we detect the S key being pressed, instead of increasing y coordinate of the player, we decrease the y coordinates of everything else.

This would have the desired effect, but imagine we have a huge, sprawling GTA-style game world - we'd have to loop though potentially thousands of objects multiple times per second! It could get very expensive - there's a better way.

On tiles, cameras, and hedgehogs

One solution is to use a camera, and to break the game world into tiles. This is the system used in classic games like Mario and Sonic the Hedgehog.

When the player moves, we update his x and y coordinates as usual. But we also have a camera object, give it a width and height equal to the game area, and center it over the player. Every game loop, we update the position of the camera so that it remains exactly centered over the player.

Then we just check the x, y, height, and width of the camera, and compare that to each of our game elements. If our game elements collide with the camera (in other words, if they are on screen), we draw them. If not, we don't.

We won't need to move every single game element around the player when he moves - only the ones inside the camera's boundary. This will save a lot of processing power, but we still need to loop through every element to check whether it's inside the camera or not! We need a way to check which objects are within the camera's boundaries without looping through every single one of them - this is where the tiles come in.

We'll break our game world into tiles, say 32x32 pixels, or 64x64, or 50x50 - any size you want. These tiles will actually be objects stored in nested arrays. Each array will represent one row of tiles in our game map. The objects will contain information on what's in that bit of the map - maybe it's a wall, a bad guy, a power up, lava floor - whatever.

Once we've done that, we can determine which elements are on screen with some basic maths. For example, let's assume the following:
The result could look like the below. The upper-left is x=0, y=0 and the lower-right is x=4000, y=2000. The red square is the player and the red border is the camera boundary.

Mock-up of a tiled game area showing the player and the camera boundary

It looks like our hero is visiting a seaside town - we've got a beach, the sea, some grass, the brown things are supposed to be buildings, a paved area, and some water features, maybe those are swimming pools or fountains or something.

The player is standing at x=2000 by y=700. So because each tile is 50 pixels wide, we can just divide the player coordinates by 50 and round down to get the coordinates of the tile he's standing on, in this case tile x=40, y=14.

We know the camera is 800 pixels wide, which is 16 tiles. So within the camera, there are 8 tiles to the left and 8 to the right of the player.

The camera is 600 pixels high, which is 12 tiles. So likewise, there are 6 tiles above and 6 below the player at any given time on the screen.

Therefore, we can determine the upper-left tile on the screen by deducting 8 and 6 from the player's x and y tile coordinates respectively. And we can determine the coordinates of the lower-right tile by adding 8 and 6 to the current tile's x and y coordinates in the map array.

Since he's x=40, y=14, the range of tiles inside the camera area go from an upper-left of x=32, y=8 to a lower-right of x=48, y=20.

Our nested arrays will act like a database table, listing every tile and telling us what's on it. Every game loop, we check which tiles are within the camera boundary by doing the maths above. Then look up these tiles in our table to see what elements are in that location, and draw them on the screen. So instead of drawing the whole world, we're actually only rendering this:

Mock-up of a tiled game area showing the player and the camera boundary

To summarise, the process goes like this:
So as we wanted, the player's graphic will be stationary and the rest of the map will move around the player - but thanks to our tile system we only have to render a small portion of the map.

Let's table this for now

So that's what we're going to do, in the next lesson we'll move on to the how, starting with that reference table of tiles I was just talking about.

Go to Lesson 2 - Building a map