TileEngine(​properties)

A tile engine for managing and drawing tilesets.

Tileset to create an overworld map in various seasons.
Tileset image courtesy of Kenney.

TileEngine Parameters

properties

Object. Properties of the tile engine.

properties.width

Number. Width of the tile map (in number of tiles).

properties.height

Number. Height of the tile map (in number of tiles).

properties.tilewidth

Number. Width of a single tile (in pixels).

properties.tileheight

Number. Height of a single tile (in pixels).

properties.context Optional

CanvasRenderingContext2D. The context the tile engine should draw to. Defaults to core.getContext()

properties.tilesets

An Array of Objects. Array of tileset objects.

properties.<tilesetN>.firstgid

Number. First tile index of the tileset. The first tileset will have a firstgid of 1 as 0 represents an empty tile.

properties.<tilesetN>.image

String or HTMLImageElement. Relative path to the HTMLImageElement or an HTMLImageElement. If passing a relative path, the image file must have been loaded first.

properties.<tilesetN>.spacing Optional

Number. The amount of whitespace between each tile (in pixels). Defaults to 0.

properties.<tilesetN>.margin Optional

Number. The amount of whitespace border around the entire tileset image (in pixels). Defaults to 0.

properties.<tilesetN>.tilewidth Optional

Number. Width of the tileset (in pixels). Defaults to properties.tilewidth.

properties.<tilesetN>.tileheight Optional

Number. Height of the tileset (in pixels). Defaults to properties.tileheight.

properties.<tilesetN>.source Optional

String. Relative path to the source JSON file. The source JSON file must have been loaded first.

properties.<tilesetN>.columns Optional

Number. Number of columns in the tileset image.

properties.layers

An Array of Objects. Array of layer objects.

properties.<layerN>.name

String. Unique name of the layer.

properties.<layerN>.data

An Array of Numbers. 1D array of tile indices.

properties.<layerN>.visible Optional

Boolean. If the layer should be drawn or not. Defaults to true.

properties.<layerN>.opacity Optional

Number. Percent opacity of the layer. Defaults to 1.

Table of Contents

Basic Use

Creating a tile map requires three things:

  1. Dimensions of the tile map and a tile
  2. At least one tileset with an image
  3. At least one layer with data

To set up the tile engine, you'll need to pass it the width and height of a tile (in pixels) and the width and height of the map (in number of tiles).

You'll then need to add at least one tileset with an image as well as firstgid, or first tile index of the tileset. The first tileset will always have a firstgid of 1 as 0 represents an empty tile.

Lastly, you'll need to add at least one named layer with data. A layer tells the tile engine which tiles from the tileset image to use at what position on the map.

Once all tileset images and all layers have been added, you can render the tile engine by calling its render() function.

let { TileEngine } = kontra

let img = new Image();
img.src = 'assets/imgs/mapPack_tilesheet.png';
img.onload = function() {
  let tileEngine = TileEngine({
    // tile size
    tilewidth: 64,
    tileheight: 64,

    // map size in tiles
    width: 9,
    height: 9,

    // tileset object
    tilesets: [{
      firstgid: 1,
      image: img
    }],

    // layer object
    layers: [{
      name: 'ground',
      data: [ 0,  0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  6,  7,  7,  8,  0,  0,  0,
              0,  6,  27, 24, 24, 25, 0,  0,  0,
              0,  23, 24, 24, 24, 26, 8,  0,  0,
              0,  23, 24, 24, 24, 24, 26, 8,  0,
              0,  23, 24, 24, 24, 24, 24, 25, 0,
              0,  40, 41, 41, 10, 24, 24, 25, 0,
              0,  0,  0,  0,  40, 41, 41, 42, 0,
              0,  0,  0,  0,  0,  0,  0,  0,  0 ]
    }]
  });

  tileEngine.render();
}
import { TileEngine } from 'path/to/kontra.mjs'

let img = new Image();
img.src = 'assets/imgs/mapPack_tilesheet.png';
img.onload = function() {
  let tileEngine = TileEngine({
    // tile size
    tilewidth: 64,
    tileheight: 64,

    // map size in tiles
    width: 9,
    height: 9,

    // tileset object
    tilesets: [{
      firstgid: 1,
      image: img
    }],

    // layer object
    layers: [{
      name: 'ground',
      data: [ 0,  0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  6,  7,  7,  8,  0,  0,  0,
              0,  6,  27, 24, 24, 25, 0,  0,  0,
              0,  23, 24, 24, 24, 26, 8,  0,  0,
              0,  23, 24, 24, 24, 24, 26, 8,  0,
              0,  23, 24, 24, 24, 24, 24, 25, 0,
              0,  40, 41, 41, 10, 24, 24, 25, 0,
              0,  0,  0,  0,  40, 41, 41, 42, 0,
              0,  0,  0,  0,  0,  0,  0,  0,  0 ]
    }]
  });

  tileEngine.render();
}
import { TileEngine } from 'kontra';

let img = new Image();
img.src = 'assets/imgs/mapPack_tilesheet.png';
img.onload = function() {
  let tileEngine = TileEngine({
    // tile size
    tilewidth: 64,
    tileheight: 64,

    // map size in tiles
    width: 9,
    height: 9,

    // tileset object
    tilesets: [{
      firstgid: 1,
      image: img
    }],

    // layer object
    layers: [{
      name: 'ground',
      data: [ 0,  0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  6,  7,  7,  8,  0,  0,  0,
              0,  6,  27, 24, 24, 25, 0,  0,  0,
              0,  23, 24, 24, 24, 26, 8,  0,  0,
              0,  23, 24, 24, 24, 24, 26, 8,  0,
              0,  23, 24, 24, 24, 24, 24, 25, 0,
              0,  40, 41, 41, 10, 24, 24, 25, 0,
              0,  0,  0,  0,  40, 41, 41, 42, 0,
              0,  0,  0,  0,  0,  0,  0,  0,  0 ]
    }]
  });

  tileEngine.render();
}

Advance Use

Adding all the tileset images and layers to a tile engine can be tedious, especially if you have multiple layers. If you want a simpler way to create a tile engine, Kontra has been written to work directly with the JSON output of the Tiled Map Editor.

The one requirement is that you must preload all of the tileset images and tileset sources using the appropriate asset loader functions before you create the tile engine.

Note: The Layer Format must be set to CSV (not Base64) and any source files must also be JSON files (not XML or TMX).

let { load, TileEngine, dataAssets } = kontra

load('assets/imgs/mapPack_tilesheet.png', 'assets/data/tile_engine_basic.json')
  .then(assets => {
    let tileEngine = TileEngine(dataAssets['assets/data/tile_engine_basic']);
    tileEngine.render();
  });
import { load, TileEngine, dataAssets } from 'path/to/kontra.mjs'

load('assets/imgs/mapPack_tilesheet.png', 'assets/data/tile_engine_basic.json')
  .then(assets => {
    let tileEngine = TileEngine(dataAssets['assets/data/tile_engine_basic']);
    tileEngine.render();
  });
import { load, TileEngine, dataAssets } from 'kontra';

load('assets/imgs/mapPack_tilesheet.png', 'assets/data/tile_engine_basic.json')
  .then(assets => {
    let tileEngine = TileEngine(dataAssets['assets/data/tile_engine_basic']);
    tileEngine.render();
  });

Moving the Camera

If your tilemap is larger than the canvas size, you can move the tilemap camera to change how the tilemap is drawn. Use the tile engines sx and sy properties to move the camera. Just like drawing an image, the cameras coordinates are the top left corner.

The sx and sy coordinates will never draw the tile map below 0 or beyond the last row or column of the tile map.

let { load, TileEngine, dataAssets, GameLoop } = kontra

load('assets/imgs/mapPack_tilesheet.png', 'assets/data/tile_engine_camera.json')
  .then(function() {
    let tileEngine = TileEngine(dataAssets['assets/data/tile_engine_camera']);

    let sx = 1;
    let loop = GameLoop({
      update: function() {
        tileEngine.sx += sx;

        if (tileEngine.sx <= 0 || tileEngine.sx >= 320) {
          sx = -sx;
        }
      },
      render: function() {
        tileEngine.render();
      }
    });

    loop.start();
  });
import { load, TileEngine, dataAssets, GameLoop } from 'path/to/kontra.mjs'

load('assets/imgs/mapPack_tilesheet.png', 'assets/data/tile_engine_camera.json')
  .then(function() {
    let tileEngine = TileEngine(dataAssets['assets/data/tile_engine_camera']);

    let sx = 1;
    let loop = GameLoop({
      update: function() {
        tileEngine.sx += sx;

        if (tileEngine.sx <= 0 || tileEngine.sx >= 320) {
          sx = -sx;
        }
      },
      render: function() {
        tileEngine.render();
      }
    });

    loop.start();
  });
import { load, TileEngine, dataAssets, GameLoop } from 'kontra';

load('assets/imgs/mapPack_tilesheet.png', 'assets/data/tile_engine_camera.json')
  .then(function() {
    let tileEngine = TileEngine(dataAssets['assets/data/tile_engine_camera']);

    let sx = 1;
    let loop = GameLoop({
      update: function() {
        tileEngine.sx += sx;

        if (tileEngine.sx <= 0 || tileEngine.sx >= 320) {
          sx = -sx;
        }
      },
      render: function() {
        tileEngine.render();
      }
    });

    loop.start();
  });

Adding Objects to the TileMap

Managing the correct x and y position of sprites on a large tile map can be tricky. You can add objects to the tile map and the tile map will render each object with the correct camera position.

let { load, TileEngine, dataAssets, imageAssets, SpriteSheet, Sprite, GameLoop } = kontra

load('assets/imgs/mapPack_tilesheet.png', 'assets/data/tile_engine_add.json')
  .then(function() {
    let tileEngine = TileEngine(dataAssets['assets/data/tile_engine_add']);

    let spriteSheet = SpriteSheet({
      image: imageAssets['assets/imgs/mapPack_tilesheet.png'],
      frameWidth: 64,
      frameHeight: 64,
      animations: {
        player: {
          frames: 168,
          frameRate: 1
        }
      }
    });

    // draw the pink alien on the tile map at position {192,128}
    let sprite = Sprite({
      x: 192,
      y: 128,
      animations: spriteSheet.animations
    });

    // sync the tile map camera and the sprite
    tileEngine.add(sprite);

    let sx = 1;
    let loop = GameLoop({
      update: function() {
        tileEngine.sx += sx;

        if (tileEngine.sx <= 0 || tileEngine.sx >= 256) {
          sx = -sx;
        }
      },
      render: function() {
        // the alien will now draw to the correct spot even while the camera moves
        tileEngine.render();
      }
    });

    loop.start();
  });
import { load, TileEngine, dataAssets, imageAssets, SpriteSheet, Sprite, GameLoop } from 'path/to/kontra.mjs'

load('assets/imgs/mapPack_tilesheet.png', 'assets/data/tile_engine_add.json')
  .then(function() {
    let tileEngine = TileEngine(dataAssets['assets/data/tile_engine_add']);

    let spriteSheet = SpriteSheet({
      image: imageAssets['assets/imgs/mapPack_tilesheet.png'],
      frameWidth: 64,
      frameHeight: 64,
      animations: {
        player: {
          frames: 168,
          frameRate: 1
        }
      }
    });

    // draw the pink alien on the tile map at position {192,128}
    let sprite = Sprite({
      x: 192,
      y: 128,
      animations: spriteSheet.animations
    });

    // sync the tile map camera and the sprite
    tileEngine.add(sprite);

    let sx = 1;
    let loop = GameLoop({
      update: function() {
        tileEngine.sx += sx;

        if (tileEngine.sx <= 0 || tileEngine.sx >= 256) {
          sx = -sx;
        }
      },
      render: function() {
        // the alien will now draw to the correct spot even while the camera moves
        tileEngine.render();
      }
    });

    loop.start();
  });
import { load, TileEngine, dataAssets, imageAssets, SpriteSheet, Sprite, GameLoop } from 'kontra';

load('assets/imgs/mapPack_tilesheet.png', 'assets/data/tile_engine_add.json')
  .then(function() {
    let tileEngine = TileEngine(dataAssets['assets/data/tile_engine_add']);

    let spriteSheet = SpriteSheet({
      image: imageAssets['assets/imgs/mapPack_tilesheet.png'],
      frameWidth: 64,
      frameHeight: 64,
      animations: {
        player: {
          frames: 168,
          frameRate: 1
        }
      }
    });

    // draw the pink alien on the tile map at position {192,128}
    let sprite = Sprite({
      x: 192,
      y: 128,
      animations: spriteSheet.animations
    });

    // sync the tile map camera and the sprite
    tileEngine.add(sprite);

    let sx = 1;
    let loop = GameLoop({
      update: function() {
        tileEngine.sx += sx;

        if (tileEngine.sx <= 0 || tileEngine.sx >= 256) {
          sx = -sx;
        }
      },
      render: function() {
        // the alien will now draw to the correct spot even while the camera moves
        tileEngine.render();
      }
    });

    loop.start();
  });

TileEngine​.add(​...objects)

Add an object to the tile engine.

add Parameters

...objects

A list of (Object or Array of Objects). Object to add to the tile engine. Can be a single object, an array of objects, or a comma-separated list of objects.

TileEngine​.context

CanvasRenderingContext2D. The context the tile engine will draw to.

TileEngine​.getPosition(​event)

Get the tile position of a pointer event.

let { initPointer, track, TileEngine } = kontra;

initPointer();
let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }],
  onDown(evt) {
    // row and col is the tile position that was clicked
    let { row, col } = this.getPosition(evt);
  }
});

track(tileEngine);
import { initPointer, track, TileEngine } from 'path/to/kontra.mjs';

initPointer();
let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }],
  onDown(evt) {
    // row and col is the tile position that was clicked
    let { row, col } = this.getPosition(evt);
  }
});

track(tileEngine);
import { initPointer, track, TileEngine } from 'kontra';

initPointer();
let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }],
  onDown(evt) {
    // row and col is the tile position that was clicked
    let { row, col } = this.getPosition(evt);
  }
});

track(tileEngine);

getPosition Parameters

event

Object. The pointer event with x and y properties.

getPosition Return value

Object. The x, y, row, and col of the pointer event within the tile engine.

TileEngine​.height

Number. The height of tile map (in tiles).

TileEngine​.layerCollidesWith(​name, object)

Check if the object collides with the layer (shares a gird coordinate with any positive tile index in layers data). The object being checked must have the properties x, y, width, and height so that its position in the grid can be calculated. Sprite defines these properties for you.

let { TileEngine, Sprite } = kontra;

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }]
});

let sprite = Sprite({
  x: 50,
  y: 20,
  width: 5,
  height: 5
});

tileEngine.layerCollidesWith('collision', sprite);  //=> false

sprite.y = 28;

tileEngine.layerCollidesWith('collision', sprite);  //=> true
import { TileEngine, Sprite } from 'path/to/kontra.mjs';

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }]
});

let sprite = Sprite({
  x: 50,
  y: 20,
  width: 5,
  height: 5
});

tileEngine.layerCollidesWith('collision', sprite);  //=> false

sprite.y = 28;

tileEngine.layerCollidesWith('collision', sprite);  //=> true
import { TileEngine, Sprite } from 'kontra';

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }]
});

let sprite = Sprite({
  x: 50,
  y: 20,
  width: 5,
  height: 5
});

tileEngine.layerCollidesWith('collision', sprite);  //=> false

sprite.y = 28;

tileEngine.layerCollidesWith('collision', sprite);  //=> true

layerCollidesWith Parameters

name

String. The name of the layer to check for collision.

object

Object. Object to check collision against.

layerCollidesWith Return value

Boolean. true if the object collides with a tile, false otherwise.

TileEngine​.layers

An Array of Objects. Array of all layers of the tile engine.

TileEngine​.mapheight

Number. The height of the tile map (in pixels).

TileEngine​.mapwidth

Number. The width of the tile map (in pixels).

TileEngine​.remove(​...objects)

Remove an object from the tile engine.

remove Parameters

...objects

A list of (Object or Array of Objects). Object to remove from the tile engine. Can be a single object, an array of objects, or a comma-separated list of objects.

TileEngine​.render(​)

Render all visible layers.

TileEngine​.renderLayer(​name)

Render a specific layer by name.

renderLayer Parameters

name

String. Name of the layer to render.

TileEngine​.setLayer(​name, data)

Set the data at the specified layer.

let { TileEngine } = kontra;

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 2,
  height: 2,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,1,
            2,3 ]
  }]
});

tileEngine.setLayer('collision', [ 4,5,6,7]);
tileEngine.tileAtLayer('collision', {row: 0, col: 0});  //=> 4
tileEngine.tileAtLayer('collision', {row: 0, col: 1});  //=> 5
tileEngine.tileAtLayer('collision', {row: 1, col: 0});  //=> 6
tileEngine.tileAtLayer('collision', {row: 1, col: 1});  //=> 7
import { TileEngine } from 'path/to/kontra.mjs';

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 2,
  height: 2,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,1,
            2,3 ]
  }]
});

tileEngine.setLayer('collision', [ 4,5,6,7]);
tileEngine.tileAtLayer('collision', {row: 0, col: 0});  //=> 4
tileEngine.tileAtLayer('collision', {row: 0, col: 1});  //=> 5
tileEngine.tileAtLayer('collision', {row: 1, col: 0});  //=> 6
tileEngine.tileAtLayer('collision', {row: 1, col: 1});  //=> 7
import { TileEngine } from 'kontra';

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 2,
  height: 2,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,1,
            2,3 ]
  }]
});

tileEngine.setLayer('collision', [ 4,5,6,7]);
tileEngine.tileAtLayer('collision', {row: 0, col: 0});  //=> 4
tileEngine.tileAtLayer('collision', {row: 0, col: 1});  //=> 5
tileEngine.tileAtLayer('collision', {row: 1, col: 0});  //=> 6
tileEngine.tileAtLayer('collision', {row: 1, col: 1});  //=> 7

setLayer Parameters

name

String. Name of the layer.

data

An Array of Numbers. 1D array of tile indices.

TileEngine​.setTileAtLayer(​name, position, tile)

Set the tile at the specified layer using either x and y coordinates or row and column coordinates.

let { TileEngine } = kontra;

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }]
});

tileEngine.setTileAtLayer('collision', {row: 2, col: 1}, 10);
tileEngine.tileAtLayer('collision', {row: 2, col: 1});  //=> 10
import { TileEngine } from 'path/to/kontra.mjs';

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }]
});

tileEngine.setTileAtLayer('collision', {row: 2, col: 1}, 10);
tileEngine.tileAtLayer('collision', {row: 2, col: 1});  //=> 10
import { TileEngine } from 'kontra';

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }]
});

tileEngine.setTileAtLayer('collision', {row: 2, col: 1}, 10);
tileEngine.tileAtLayer('collision', {row: 2, col: 1});  //=> 10

setTileAtLayer Parameters

name

String. Name of the layer.

position

Object. Position of the tile in either {x, y} or {row, col} coordinates.

tile

Number. Tile index to set.

TileEngine​.sx

Number. X coordinate of the tile map camera.

TileEngine​.sy

Number. Y coordinate of the tile map camera.

TileEngine​.tileAtLayer(​name, position)

Get the tile at the specified layer using either x and y coordinates or row and column coordinates.

let { TileEngine } = kontra;

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }]
});

tileEngine.tileAtLayer('collision', {x: 50, y: 50});  //=> 1
tileEngine.tileAtLayer('collision', {row: 2, col: 1});  //=> 2
import { TileEngine } from 'path/to/kontra.mjs';

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }]
});

tileEngine.tileAtLayer('collision', {x: 50, y: 50});  //=> 1
tileEngine.tileAtLayer('collision', {row: 2, col: 1});  //=> 2
import { TileEngine } from 'kontra';

let tileEngine = TileEngine({
  tilewidth: 32,
  tileheight: 32,
  width: 4,
  height: 4,
  tilesets: [{
    // ...
  }],
  layers: [{
    name: 'collision',
    data: [ 0,0,0,0,
            0,1,4,0,
            0,2,5,0,
            0,0,0,0 ]
  }]
});

tileEngine.tileAtLayer('collision', {x: 50, y: 50});  //=> 1
tileEngine.tileAtLayer('collision', {row: 2, col: 1});  //=> 2

tileAtLayer Parameters

name

String. Name of the layer.

position

Object. Position of the tile in either {x, y} or {row, col} coordinates.

tileAtLayer Return value

Number. The tile index. Will return -1 if no layer exists by the provided name.

TileEngine​.tileheight

Number. The height of a tile (in pixels).

TileEngine​.tilesets

An Array of Objects. Array of all tilesets of the tile engine.

TileEngine​.tilewidth

Number. The width a tile (in pixels).

TileEngine​.width

Number. The width of tile map (in tiles).