| name | dev-phaser-tilemaps |
| description | Tilemap loading, parsing, layers, and collision detection |
Phaser Tilemaps
"Build expansive worlds with tile-based maps from Tiled."
Before/After: Manual Level Building vs Tiled Integration
❌ Before: Manual Level Data Management
interface Tile {
x: number;
y: number;
type: string;
solid: boolean;
}
interface Level {
tiles: Tile[];
width: number;
height: number;
spawn: { x: number; y: number };
}
const level1: Level = {
tiles: [
{ x: 0, y: 0, type: 'grass', solid: false },
{ x: 1, y: 0, type: 'grass', solid: false },
{ x: 2, y: 0, type: 'wall', solid: true },
],
width: 50,
height: 50,
spawn: { x: 100, y: 100 }
};
class LevelRenderer {
private tileImages: Map<string, HTMLImageElement> = new Map();
constructor(private canvas: HTMLCanvasElement) {
this.loadTile('grass', 'assets/tiles/grass.png');
this.loadTile('wall', 'assets/tiles/wall.png');
this.loadTile('water', 'assets/tiles/water.png');
}
async loadTile(type: string, path: string) {
const img = new Image();
img.src = path;
await new Promise(resolve => img.onload = resolve);
this.tileImages.set(type, img);
}
render(level: Level, cameraX: number, cameraY: number) {
const ctx = this.canvas.getContext('2d')!;
for (const tile of level.tiles) {
const screenX = tile.x * 32 - cameraX;
const screenY = tile.y * 32 - cameraY;
if (screenX < -32 || screenX > this.canvas.width ||
screenY < -32 || screenY > this.canvas.height) {
continue;
}
const img = this.tileImages.get(tile.type);
if (img) {
ctx.drawImage(img, screenX, screenY);
}
}
}
getTileAt(x: number, y: number, level: Level): Tile | null {
const tileX = Math.floor(x / 32);
const tileY = Math.floor(y / 32);
return level.tiles.find(t => t.x === tileX && t.y === tileY) || null;
}
isSolid(x: number, y: number, level: Level): boolean {
const tile = this.getTileAt(x, y, level);
return tile?.solid || false;
}
}
✅ After: Tiled + Phaser Tilemap System
export class GameScene extends Phaser.Scene {
private map!: Phaser.Tilemaps.Tilemap;
preload() {
this.load.tilemapTiledJSON('dungeon', 'assets/tilemaps/dungeon.json');
this.load.image('dungeon_tiles', 'assets/tilesets/dungeon.png');
}
create() {
this.map = this.make.tilemap({ key: 'dungeon' });
const tileset = this.map.addTilesetImage('Dungeon Tiles', 'dungeon_tiles');
const bgLayer = this.map.createLayer('Background', tileset);
const wallsLayer = this..(, tileset);
fgLayer = ..(, tileset);
wallsLayer.({ : });
...(., wallsLayer);
spawnPoint = ..(, obj. === );
..(spawnPoint., spawnPoint.);
..(, , {
: ,
:
});
bgLayer.();
wallsLayer.();
fgLayer.();
...(
, ,
..,
..
);
}
}
When to Use This Skill
Use when:
- Creating platformer levels
- Building isometric worlds
- Designing large game environments
- Working with Tiled Map Editor
- Implementing tile-based collision
Quick Start
preload() {
this.load.tilemapTiledJSON('map', 'assets/level1.json');
this.load.image('tiles', 'assets/tileset.png');
}
create() {
const map = this.make.tilemap({ key: 'map' });
const tileset = map.addTilesetImage('ground', 'tiles');
const layer = map.createLayer('Ground', tileset);
layer.setCollisionByExclusion([-1]);
}
Decision Framework
| Need | Use |
|---|
| Tiled JSON export | load.tilemapTiledJSON() |
| Collision layer | setCollisionByExclusion([-1]) |
| Tile properties | setTileIndexCallback() |
| Isometric view | Tiled isometric orientation |
| Object layer | map.createFromObjects() |
Progressive Guide
Level 1: Basic Tilemap Loading
export class GameScene extends Phaser.Scene {
private map!: Phaser.Tilemaps.Tilemap;
private tileset!: Phaser.Tilemaps.Tileset;
private groundLayer!: Phaser.Tilemaps.DynamicTilemapLayer;
private wallsLayer!: Phaser.Tilemaps.DynamicTilemapLayer;
preload() {
this.load.tilemapTiledJSON("dungeon", "assets/tilemaps/dungeon.json");
this.load.image("dungeon_tiles", "assets/tilesets/dungeon.png");
}
create() {
this.map = this.make.tilemap({ key: "dungeon" });
this.tileset = this..(, );
. = ..(, .);
. = ..(, .);
}
}
Level 2: Tile Collision
create() {
this.map = this.make.tilemap({ key: 'dungeon' });
this.tileset = this.map.addTilesetImage('Dungeon Tiles', 'dungeon_tiles');
const walls = this.map.createLayer('Walls', this.tileset);
walls.setCollisionByProperty({ collides: true });
walls.setCollisionByExclusion([-1]);
walls.setCollision([1, 2, 3, 4]);
const player = this.physics.add.sprite(100, 100, 'player');
player.setCollideWorldBounds(true);
...(player, walls);
}
Level 3: Tile Properties and Callbacks
create() {
this.map = this.make.tilemap({ key: 'level' });
this.tileset = this.map.addTilesetImage('tiles', 'tiles');
const worldLayer = this.map.createLayer('World', this.tileset);
worldLayer.setCollisionByProperty({ collides: true });
worldLayer.setTileIndexCallback(
5,
this.lavaCallback,
this
);
worldLayer.setTileLocationCallback(
10, 10,
5, 5,
this.coinCallback,
this
);
}
lavaCallback(sprite: Phaser.Types..., : ..) {
player = sprite ...;
.(player);
}
() {
layer = tile.;
layer.(tile., tile.);
. += ;
}
Level 4: Object Layers
create() {
this.map = this.make.tilemap({ key: 'level' });
this.tileset = this.map.addTilesetImage('tiles', 'tiles');
const objects = this.map.getObjectLayer('Objects');
if (objects) {
objects.objects.forEach((obj: any) => {
if (obj.type === 'player') {
this.spawnPlayer(obj.x, obj.y);
} else if (obj.type === 'enemy') {
this.spawnEnemy(obj.x, obj.y, obj.properties);
} else if (obj.type === 'coin') {
this.spawnCoin(obj., obj.);
}
});
}
coins = ..(, , {
: ,
:
});
...(coins);
}
Level 5: Advanced Tilemap Techniques
export class GameScene extends Phaser.Scene {
private map!: Phaser.Tilemaps.Tilemap;
private layers: Phaser.Tilemaps.DynamicTilemapLayer[] = [];
create() {
this.map = this.make.tilemap({ key: "large_level" });
this.tileset = this.map.addTilesetImage("tiles", "tiles");
const bgLayer = this.map.createLayer("Background", this.tileset);
const decorLayer = this.map.createLayer("Decoration", this.tileset);
const mainLayer = this.map.createLayer("Main", this.tileset);
fgLayer = ..(, .);
bgLayer.();
decorLayer.();
mainLayer.();
fgLayer.();
mainLayer.({ : });
fgLayer.({ : });
player = ...(, , );
...(player, mainLayer);
...(player, fgLayer);
.(mainLayer, player);
...(
,
,
..,
..,
);
}
() {
..(, {
tile = layer.(pointer., pointer.);
(tile) {
.(, tile., , tile.);
(tile..) {
layer.(tile., tile.);
.(tile., tile.);
}
}
});
animatedTiles = [{ : , : [, , ], : }];
animatedTiles.( {
..[anim.] = {
: anim..( ({
frame,
: anim.,
})),
};
});
}
(
: ,
: ,
: ,
: ,
): {
layer = .[];
line = ..(fromX, fromY, toX, toY);
tiles = layer.(line);
!tiles.( tile..);
}
() {
layer = .[layerIndex];
( ty = y; ty < y + h; ty++) {
( tx = x; tx < x + w; tx++) {
layer.(tileIndex, tx, ty);
}
}
}
}
Anti-Patterns
❌ DON'T:
- Create tilemap without adding tileset
- Forget to set collision on tiles
- Use wrong tileset name from Tiled
- Assume tilemap coordinate system matches pixel coordinates
- Create large tilemaps without culling
- Load tilemaps without compression
✅ DO:
- Match tileset name to Tiled project
- Set collision properties in Tiled or code
- Use
tile.pixelX/Y for pixel positions
- Enable camera culling for large maps
- Use JSON compression for tilemaps
- Cache tilemap lookups when possible
Code Patterns
Tile Properties from Tiled
In Tiled, set tile properties:
- collides: true
- dangerous: true
- animates: true
- frameRate: 5
layer.setCollisionByProperty({ collides: true });
layer.setTileLocationCallback(
0,
0,
map.width,
map.height,
(sprite, tile) => {
if (tile.properties.dangerous) {
this.hurtPlayer(sprite);
}
},
this,
);
Parallax Tilemap Layers
create() {
const bgLayer = map.createLayer('Background', tileset);
const midLayer = map.createLayer('Midground', tileset);
const fgLayer = map.createLayer('Foreground', tileset);
bgLayer.setScrollFactor(0.2);
midLayer.setScrollFactor(0.5);
fgLayer.setScrollFactor(1);
}
Tilemap Bounds
create() {
this.cameras.main.setBounds(
0, 0,
this.map.widthInPixels,
this.map.heightInPixels
);
this.physics.world.setBounds(
0, 0,
this.map.widthInPixels,
this.map.heightInPixels
);
}
Tilemap Methods Reference
| Method | Description |
|---|
createLayer(name, tileset) | Create layer from tilemap |
setCollisionByProperty(props) | Set collision from properties |
setCollisionByExclusion(indices) | Set collision except specified |
setTileIndexCallback(index, fn) | Callback when tile touched |
getTileAt(x, y) | Get tile at grid coordinates |
getTileAtWorldXY(x, y) | Get tile at pixel coordinates |
putTileAt(index, x, y) | Place tile at grid coordinates |
removeTileAt(x, y) | Remove tile |
swapTiles(indexA, indexB) | Swap all tiles of two types |
Checklist
Reference