Tilemap
A tile-grid node: an atlas texture sliced into cells, laid out on a uniform grid, uploaded once
and rendered natively with per-frame view culling — draw a large level as one node. Extends
Node2D, so it has the full transform, hierarchy, and layer surface.
At a glance
const tiles = await Texture2D.load(asset('./tiles.png'))
const map = new Tilemap({
texture: tiles,
cols: 20, rows: 5, // map size in tiles
tile: 32, // each cell 32×32 world units
atlas: [8, 4], // the texture holds 8×4 tiles
data: [ // row 0 = TOP row; -1 = empty
-1, -1, -1, /* … cols*rows entries … */
0, 1, 1, /* … */
],
})
map.position = [0, 0] // the map's BOTTOM-LEFT corner
scene.add(map)Creating
new Tilemap(options: {
texture: Texture2D
cols: number // map width in tiles
rows: number // map height in tiles
tile: number | [w, h] // on-screen cell size in world units (number = square)
atlas: [atlasCols, atlasRows] // how the texture is sliced into tiles
data: number[] | Int32Array // row-major atlas indices, length cols*rows; -1 = empty
})
map.cols, map.rows // readonlydatais row-major with row 0 at the top of the map (reads like level text in source code), even though world Y points up.- Atlas indices also count row-major through the atlas grid: 0 is the atlas's top-left tile.
- The node's
positionis the map's bottom-left corner.
Editing cells
map.setTile(x: number, y: number, index: number): this // grid coords as in data (row 0 = top)Sets one cell to an atlas index (-1 clears it). Cheap — the grid lives natively.
Limits
The tilemap is a static uniform grid. Not provided (as of the current source):
- animated tiles — swap cells yourself with
setTileif needed - per-tile collision — build level collision separately, e.g. invisible
Node2Ds withShape2Dboxes/segments and staticPhysics2Dbodies - per-tile flip/rotate — bake mirrored/rotated variants into the atlas
See also
- Node2D — transform, layer (inherited)
- Texture2D — loading the atlas
- 2D physics — static collision geometry for levels
- Scene2D — layers, Y-sort