Tilemap
The tilemap system loads Tiled maps (.tmj / .json) and renders tile layers with automatic camera culling, per-layer tint/opacity, parallax scrolling, and collision generation.
Editor Tilemap Creation
You can create and paint tilemaps entirely within the editor — no external tools required.
Creating a Tilemap
- Right-click in the Hierarchy panel → Create → Tilemap
- In the creation dialog, set the tile size and choose between Finite or Infinite map mode
- Assign a tileset image in the Tilemap component Inspector
Tile Palette
The Tile Palette panel opens automatically when a tilemap entity is selected. It provides 5 tools:
| Tool | Shortcut | Description |
|---|---|---|
| Brush | B | Paint individual tiles or stamp multi-tile regions |
| Rectangle | R | Drag to fill a rectangular area |
| Bucket | G | Flood-fill connected tiles of the same type |
| Eraser | E | Remove tiles (also available via right-click with any tool) |
| Picker | I | Sample a tile from the map to use as the current brush |
Stamp selection: drag in the palette grid to select a multi-tile region, then paint with the brush tool to stamp the entire selection.
Flip: use the toolbar buttons to flip tiles horizontally or vertically before painting.
Infinite Maps
Infinite maps use sparse chunk storage — only painted areas consume memory. The renderer uses 16×16 tile chunks with:
- Dirty flags: only chunks with changed tiles rebuild vertices each frame
- Chunk-level culling: off-screen chunks are skipped entirely
- Animated tile tracking: chunks without animated tiles skip rebuild checks
Layer Management
Add, remove, rename, and reorder layers via the layer dropdown in the Tile Palette. Each layer has independent tile data and a visibility toggle.
Quick Start
The simplest way to use tilemaps is through the editor:
- Export your map from Tiled as JSON (
.tmj) - Place the
.tmjfile and tileset images in your project assets folder - Add a Tilemap component to an entity and set the Source to your
.tmjfile
The scene loader automatically parses the map, loads tileset textures via the AssetServer, and registers everything for rendering.
Components
Tilemap
A marker component that references a Tiled map source file. The scene loader reads this field to preload map data and tileset textures before the scene is instantiated.
| Property | Type | Default | Description |
|---|---|---|---|
source | string | '' | Path to the .tmj / .json map file |
TilemapLayer
Describes a single tile layer for rendering. Each visible layer in a Tiled map creates one entity with this component.
| Property | Type | Default | Description |
|---|---|---|---|
width | number | 10 | Layer width in tiles |
height | number | 10 | Layer height in tiles |
tileWidth | number | 32 | Tile width in pixels |
tileHeight | number | 32 | Tile height in pixels |
texture | number | 0 | Tileset texture handle |
tilesetColumns | number | 1 | Number of columns in the tileset image |
layer | number | 0 | Sort layer index |
tiles | number[] | [] | Flat array of tile IDs (row-major) |
tint | Color | {r:1,g:1,b:1,a:1} | Per-layer tint color |
opacity | number | 1 | Layer opacity (0–1) |
visible | boolean | true | Whether the layer is rendered |
parallaxFactor | Vec2 | {x:1,y:1} | Parallax scroll factor |
How It Works
Scene Loading Pipeline
When a scene contains an entity with a Tilemap component, the scene loader:
- Reads the
sourcefield (e.g.,maps/level1.tmj) - Loads the JSON via the
AssetServerand parses it withparseTmjJson - Resolves tileset image paths relative to the
.tmjfile - Loads tileset textures via
AssetServer.loadTexture()and registers their dimensions - Caches the parsed map data with
registerTilemapSource()
At runtime, the TilemapPlugin reads the cache and submits visible layers for rendering each frame.
Build Targets
The tilemap asset pipeline works across all build targets:
- Editor preview: Loads via
AssetServerover the preview HTTP server - WeChat MiniGame / Playable Ads: Loads via
RuntimeAssetProviderusing the bundled assets - Web build: Same as editor preview, assets served from the build output
Programmatic Loading
For cases where you need to load a tilemap from code (outside the scene loader), use the lower-level APIs:
import { parseTmjJson, loadTiledMap, registerTextureDimensions } from 'esengine';
// Parse Tiled JSON dataconst mapData = parseTmjJson(jsonObject);
// Load tileset textures through the AssetServerconst textureHandles = new Map<string, number>();for (const tileset of mapData.tilesets) { const info = await assetServer.loadTexture(tileset.image); textureHandles.set(tileset.image, info.handle); registerTextureDimensions(info.handle, info.width, info.height);}
// Spawn tilemap layer entities into the worldconst entities = loadTiledMap(world, mapData, textureHandles);C++ Parser (WASM)
For maps with external tilesets (.tsj files), use parseTiledMap which delegates to the C++ parser:
import { parseTiledMap } from 'esengine';
const mapData = await parseTiledMap(jsonString, async (source) => { // Resolve external tileset files return await assetServer.loadText(source);});loadTiledMap Options
| Option | Type | Default | Description |
|---|---|---|---|
generateObjectCollision | boolean | true | Create colliders from Tiled object layers |
collisionTileIds | number[] | auto-detected | Tile IDs that should generate collision bodies |
Collision Generation
Object Layer Collision
Tiled object layers are automatically converted to physics bodies. Supported shapes:
- Rectangle →
BoxColliderwith matching half-extents - Ellipse →
CircleColliderwith the larger axis as radius - Polygon / Polyline →
BoxColliderfitted to the bounding box - Point → skipped
Each collision object creates a static RigidBody entity with the appropriate collider.
Tile Collision
Mark tiles as collidable in Tiled by adding a custom property collision = true to the tile in the tileset. The loader reads these IDs and generates merged collision rectangles:
const entities = loadTiledMap(world, mapData, textureHandles, { collisionTileIds: [1, 2, 3],});Collision Merging
Adjacent collision tiles are automatically merged into larger rectangles to reduce physics body count. The algorithm scans row by row, expanding each rectangle rightward and downward as far as possible:
Before merge: [1][1][1] After merge: [ 1 ] [1][1][1] [ 1 ]This produces fewer, larger BoxCollider bodies for better physics performance.
TilemapAPI
Low-level API for runtime tile manipulation:
| Method | Description |
|---|---|
TilemapAPI.initLayer(entity, w, h, tw, th) | Initialize a tile layer for an entity |
TilemapAPI.destroyLayer(entity) | Destroy a tile layer |
TilemapAPI.setTile(entity, x, y, tileId) | Set a single tile |
TilemapAPI.getTile(entity, x, y) | Get a tile ID |
TilemapAPI.fillRect(entity, x, y, w, h, tileId) | Fill a rectangle with a tile |
TilemapAPI.setTiles(entity, tiles) | Set all tiles from a Uint16Array |
TilemapAPI.hasLayer(entity) | Check if an entity has an initialized layer |
Editor Workflow
You can create tilemaps in two ways:
Option A — Paint natively in the editor (recommended for new projects):
- Right-click in the Hierarchy → Create → Tilemap (see Editor Tilemap Creation above)
- Use the Tile Palette to paint, erase, and manage layers directly in the Scene View
Option B — Import from Tiled:
- Add a Tilemap component to an entity in the Hierarchy
- Set the Source field to a
.tmjor.jsonTiled map file using the asset picker - The editor automatically loads the map, resolves tileset textures, and renders the layers
- Collision objects are visualized as gizmo overlays
Layer Properties
Tiled layer properties map directly to TilemapLayer fields:
| Tiled Property | TilemapLayer Field | Description |
|---|---|---|
opacity | opacity | Layer transparency |
tintcolor | tint | Hex color string (#AARRGGBB or #RRGGBB) |
parallaxx | parallaxFactor.x | Horizontal parallax factor |
parallaxy | parallaxFactor.y | Vertical parallax factor |
visible | visible | Layer visibility |
Next Steps
- Physics — collision components and events
- Sprite — sprite rendering alongside tilemaps
- Rendering Overview — camera, transform, render order