• Skip to main content
  • Select language
  • Skip to search
MDN Web Docs
  • Technologies
    • HTML
    • CSS
    • JavaScript
    • Graphics
    • HTTP
    • APIs / DOM
    • WebExtensions
    • MathML
  • References & Guides
    • Learn web development
    • Tutorials
    • References
    • Developer Guides
    • Accessibility
    • Game development
    • ...more docs
Game development
  1. MDN
  2. Game development
  3. Techniques for game development
  4. Tiles and tilemaps overview
  5. Square tilemaps implementation: Scrolling maps

Square tilemaps implementation: Scrolling maps

In This Article
  1. The camera
  2. Rendering the map
  3. Demo

This article covers how to implement scrolling square tilemaps using the Canvas API.

Note: When writing this article, we assumed previous reader knowledge of canvas basics such as how get a 2D canvas context, load images, etc., which is all explained in the Canvas API tutorial, as well as the basic information included in our Tilemaps introduction article. This article also builds upon implenting static square tilemaps — you should read that too if you've not done so already.

The camera

The camera is an object that holds information about which section of the game world or level is currently being shown. Cameras can either be free-form, controlled by the player (such as in strategy games) or follow an object (such as the main character in platform games.)

Regardless of the type of camera, we would always need information regarding its current position, viewport size, etc. In the demo provided along with this article, these are the parameters the camera has:

  • x and y: The current position of the camera. In this implementation, we are assuming that (x,y) points to the top left corner of visible portion of the map.
  • width and height: The size of the camera's viewport.
  • maxX and maxY: The limit for the camera's position — The lower limit will nearly always be (0,0), and in this case the upper limit is equal to the size of the world minus the size of the camera's viewport.

Rendering the map

There are two main differences between rendering scrolling maps versus static maps:

  • Partial tiles might be shown. In static maps, usually the rendering starts at the top left corner of a tile situated at the top left corner of a viewport. While rendering scrolling tilemaps, the first tile will often be clipped.

TODO: show a diagram here explaining this.

  • Only a section of the map will be rendered. If the map is bigger than the viewport, we can obviously only dispart a part of it at a time, whereas non-scrolling maps are usually rendered wholly.

To handle these issues, we need to slightly modify the rendering algorithm. Let's imagine that we have the camera pointing at (5,10). That means that the first tile would be 0x0. In the demo code, the starting point is stored at startCol and startRow. It's convenient to also pre-calculate the last tile to be rendered.

    var startCol = Math.floor(this.camera.x / map.tsize);
    var endCol = startCol + (this.camera.width / map.tsize);
    var startRow = Math.floor(this.camera.y / map.tsize);
    var endRow = startRow + (this.camera.height / map.tsize);

Once we have the first tile, we need to calculate how much its rendering (and therefore the rendering of the other tiles) is offset by. Since the camera  is pointing at (5, 10), we know that the first tile should be shifted by (-5,-10) pixels. In our demo the shifting amount is stored in the offsetX and offsetY variables.

    var offsetX = -this.camera.x + startCol * map.tsize;
    var offsetY = -this.camera.y + startRow * map.tsize;

With these values in place, the loop that renders the map is quite similar to the one used for rendering static tilemaps. The main difference is that we are adding the offsetX and offsetY values to the target x and y coordinates, and these values are rounded, to avoid artifacts that would result from the camera pointing at positions with floating point numbers.

for (var c = startCol; c <= endCol; c++) {
        for (var r = startRow; r <= endRow; r++) {
            var tile = map.getTile(c, r);
            var x = (c - startCol) * map.tsize + offsetX;
            var y = (r - startRow) * map.tsize + offsetY;
            if (tile !== 0) { // 0 => empty tile
                this.ctx.drawImage(
                    this.tileAtlas, // image
                    (tile - 1) * map.tsize, // source x
                    0, // source y
                    map.tsize, // source width
                    map.tsize, // source height
                    Math.round(x),  // target x
                    Math.round(y), // target y
                    map.tsize, // target width
                    map.tsize // target height
                );
            }
        }
    }

Demo

Our scrolling tilemap implementation demo pulls the above code together to show what an implementation of this map looks like. You can take a look at a live demo, and see its source code.

There's another demo available, that shows how to make the camera follow a character.

Document Tags and Contributors

Tags: 
  • atlas
  • Canvas
  • Games
  • JavaScript
  • scrolling
  • spritesheet
  • tilemap
  • tiles
 Contributors to this page: chrisdavidmills, ladybenko
 Last updated by: chrisdavidmills, Oct 14, 2015, 11:35:40 AM
  1. Introduction
    1. Introduction to game development for the Web
    2. Anatomy of a video game
    3. Examples
  2. APIs for game development
    1. Canvas
    2. CSS
    3. Full Screen
    4. Gamepad
    5. IndexedDB
    6. JavaScript
    7. Pointer Lock
    8. SVG
    9. Typed Arrays
    10. Web Audio
    11. WebGL
    12. WebRTC
    13. Web Sockets
    14. WebVR
    15. Web Workers
    16. XmlHttpRequest
  3. Techniques
    1. Using async scripts for asm.js
    2. Optimizing startup performance
    3. Using WebRTC peer-to-peer data channels
    4. Efficient animation for web games
    5. 3D games on the Web
      1. 3D games on the Web overview
      2. Explaining basic 3D theory
      3. Building up a basic demo with A-Frame
      4. Building up a basic demo with Babylon.js
      5. Building up a basic demo with PlayCanvas
      6. Building up a basic demo with Three.js
      7. Building up a basic demo with Whitestorm.js
      8. WebVR

    6. Audio for Web Games
    7. 2D collision detection
    8. 3D collision detection
      1. 3D collision detection overview
      2. Bounding volume collision detection with THREE.js
    9. Tiles and tilemaps
      1. Tiles and tilemaps overview
      2. Static maps
      3. Scrolling maps
    10. Implementing game control mechanisms
      1. Game control mechanisms overview
      2. Mobile touch controls
      3. Desktop mouse and keyboard controls
      4. Desktop gamepad controls
      5. Unconventional controls
  4. Tutorials
    1. 2D breakout game using pure JavaScript
    2. 2D breakout game using Phaser
    3. 2D maze game with device orientation
    4. 2D platform game using Phaser
  5. Publishing games
    1. Publishing games overview
    2. Game distribution
    3. Game promotion
    4. Game monetization