選項
首頁首頁 Skill 其他 tilemaps

在 Phaser 4 中處理貼圖地圖時,請使用此技能。內容涵蓋載入 Tiled JSON 地圖、建立貼圖地圖圖層、貼圖碰撞、動態貼圖、貼圖屬性,以及貼圖地圖相機剔除。觸發條件:貼圖地圖、Tiled、貼圖地圖圖層、貼圖碰撞、貼圖屬性。

...展開全部
79
更新時間 2026-08-04

Tilemaps

Phaser 的 Tilemaps 可根據 Tiled JSON、CSV 或原始 2D 陣列渲染基於圖塊的關卡。一個 Tilemap 物件會儲存已解析的地圖資料,並提供方法來新增地磚集、建立圖層、設定碰撞以及查詢地磚。圖層(TilemapLayerTilemapGPULayer)則是實際渲染地磚的遊戲物件。Phaser 支援正交、等角、六邊形及錯位地圖。

主要原始碼路徑: src/tilemaps/Tilemap.js, src/tilemaps/TilemapLayer.js, src/tilemaps/TilemapGPULayer.js, src/tilemaps/TilemapLayerBase.js, src/tilemaps/Tile.js, src/tilemaps/Tileset.js, src/tilemaps/TilemapFactory.js, src/tilemaps/components/, src/tilemaps/parsers/tiled/ 相關技能: ../loading-assets/SKILL.md、../sprites-and-images/SKILL.md

快速入門

class GameScene extends Phaser.Scene {
    preload() {
        // Load the Tiled JSON and the tileset image
        this.load.tilemapTiledJSON('map', 'assets/level1.json');
        this.load.image('tiles', 'assets/tilesheet.png');
    }    create() {
        // Create the tilemap from cached JSON
        const map = this.add.tilemap('map');        // Link the tileset image to the tileset name used in Tiled
        const tileset = map.addTilesetImage('tilesheet', 'tiles');        // Create a layer - layerID must match the layer name in Tiled
        const ground = map.createLayer('Ground', tileset);        // Enable collision on specific tile indexes
        ground.setCollision([1, 2, 3]);
    }
}

流程始終為:載入 JSON + 圖片、建立地磚圖、新增地磚集圖片、建立圖層、設定碰撞。

核心概念

瓦片地圖與圖層的區別

A Tilemap 是一種資料容器,而非顯示物件。它儲存已解析的地圖資料(圖層、圖塊集、物件),並提供用於操作這些資料的方法。一個 TilemapLayerTilemapGPULayer 則是實際被加入顯示清單中、負責渲染地磚的遊戲物件。

const map = this.add.tilemap('map');    // Data container (not rendered)
const layer = map.createLayer('Ground', tileset);  // Game Object (rendered)

this.add.tilemap(key) 是註冊於 GameObjectFactory上註冊的工廠。它將操作委派給 ParseToTilemap ,該工廠會從快取中讀取資料並返回一個 Tilemap 實例。

圖塊集

A Tileset (src/tilemaps/Tileset.js) 將(來自 Tiled 的)圖塊集名稱與已載入的紋理建立關聯。它儲存 firstgid、磁磚尺寸、邊距及間距。

// tilesetName: the name in Tiled's tileset panel
// key: the Phaser texture key (defaults to tilesetName if omitted)
const tileset = map.addTilesetImage('tilesetName', 'textureKey');// Override tile dimensions, margin, and spacing if needed
const tileset = map.addTilesetImage('name', 'key', 16, 16, 1, 2);

addTilesetImage(tilesetName, key, tileWidth, tileHeight, tileMargin, tileSpacing, gid, tileOffset) - 若解析後的地圖資料中已存在該磁磚集名稱,則會將該貼圖套用至現有的 Tileset 物件;若不存在(非 Tiled 地圖),則會建立一個新的 Tileset。

重要:Phaser 的 Tiled 解析器不支援「圖片集合」類型的圖塊集。每個圖塊集必須僅包含單一張圖塊集圖片。

Tile 類別

圖層中的每個單元格皆為一個 Tile 物件(src/tilemaps/Tile.js)。主要屬性:

  • index - 圖磚集中的圖磚索引(若為空則為 -1)
  • x, y - 圖塊座標(以圖塊為單位,而非像素)
  • pixelX, pixelY - 相對於圖層原點的像素位置
  • width, height - 圖塊大小(以像素為單位)
  • properties - 來自 Tiled 的自訂屬性(物件)
  • collideLeft, collideRight, collideUp, collideDown - 邊緣碰撞標誌
  • faceLeft, faceRight, faceTop, faceBottom - 用於碰撞優化的「感興趣面」標記
  • collisionCallback - 每塊瓦片的碰撞回呼函式
  • tint - 色調顏色值(預設 0xffffff)
  • tintMode - 色調混合模式(預設 TintModes.MULTIPLY)
  • rotation - 旋轉角度
  • physics - 用於物理引擎專屬資料的物件(例如:物體)
  • alpha, visible, flipX, flipY - 從混合類繼承而來

TilemapGPULayer (v4.0.0)

TilemapGPULayer 是一款專為 WebGL 設計的高效能替代方案,用以取代 TilemapLayer。它透過著色器將整個圖層渲染為單一四邊形,使其運算幾乎完全由 GPU 主導。

// Pass gpu: true as the 5th argument to createLayer
const layer = map.createLayer('Ground', tileset, 0, 0, true);

功能:

  • 每層僅支援單一圖塊集(不支援多圖塊集)
  • 最大貼圖地圖尺寸:4096x4096 個貼圖
  • 最大獨特磁磚 ID 數量:2^23(8,388,608)
  • 支援地磚翻轉與地磚動畫
  • 僅支援正交地圖(不支援等角/六邊形/錯位)
  • 採用 LINEAR 濾波平滑貼圖邊界(無接縫)
  • 採用「最近鄰」濾波法呈現銳利像素

限制:

  • 圖層編輯內容不會自動顯示。請在 generateLayerDataTexture()
  • 僅限 WebGL 渲染器(無 Canvas 備用方案)
  • 單一層級無法使用多個圖磚集
// If you edit tiles on a GPU layer, regenerate the data texture:
gpuLayer.putTileAt(5, 10, 10);
gpuLayer.generateLayerDataTexture();

TilemapLayerBase

兩者皆 TilemapLayerTilemapGPULayer 繼承自 TilemapLayerBase (src/tilemaps/TilemapLayerBase.js),而該類別則繼承自 GameObject。基類提供了所有瓦片查詢、操作及碰撞相關的方法。它包含以下元件混合函式:Alpha、BlendMode、ComputedSize、Depth、ElapseTimer、Flip、GetBounds、Lighting、Mask、Origin、RenderNodes、Transform、Visible、ScrollFactor 以及 Arcade Physics Collision。

常見模式

從 Tiled JSON 建立

preload() {
    this.load.tilemapTiledJSON('map', 'assets/map.json');
    this.load.image('tiles', 'assets/tileset.png');
}create() {
    const map = this.add.tilemap('map');
    const tileset = map.addTilesetImage('TilesetNameInTiled', 'tiles');
    const layer = map.createLayer('LayerNameInTiled', tileset);
}

傳入的 layerID 傳入的 createLayer 必須與 Tiled 中的圖層名稱完全一致。群組圖層的子元素會依照 'ParentGroup/Layer' 命名規範進行扁平化。

多個圖層

const map = this.add.tilemap('map');
const tileset = map.addTilesetImage('terrain', 'terrain-img');const background = map.createLayer('Background', tileset);
const ground = map.createLayer('Ground', tileset);
const foreground = map.createLayer('Foreground', tileset);// Layers are rendered in creation order. Use depth for finer control:
foreground.setDepth(10);

一個圖層可以使用多個磁磚集(僅限 CPU 圖層):

const tiles1 = map.addTilesetImage('terrain', 'terrain-img');
const tiles2 = map.addTilesetImage('objects', 'objects-img');
const layer = map.createLayer('Ground', [tiles1, tiles2]);

建立空白圖層

const map = this.add.tilemap('map');
const tileset = map.addTilesetImage('terrain', 'terrain-img');// createBlankLayer(name, tileset, x, y, width, height, tileWidth, tileHeight)
const layer = map.createBlankLayer('dynamic', tileset, 0, 0, 50, 50, 32, 32);// Fill it with tiles
layer.fill(1);  // Fill entire layer with tile index 1
layer.putTileAt(5, 10, 10);  // Place tile index 5 at tile coord (10, 10)

碰撞設定

有幾種方法可以為 Arcade Physics 啟用瓦片碰撞:

// By specific tile indexes
layer.setCollision([1, 2, 3]);// By range (inclusive)
layer.setCollisionBetween(1, 50);// By tile property (set in Tiled's tileset editor)
layer.setCollisionByProperty({ collides: true });
// Supports arrays: { type: ['stone', 'lava'] }// By exclusion - collide on ALL tiles except these
layer.setCollisionByExclusion([-1, 0]);  // -1 is empty, 0 is often background// From Tiled collision editor shapes
layer.setCollisionFromCollisionGroup();

所有位於 TilemapLayerBase 鏡像方法 Tilemap 但不需要 layer 參數。在 Tilemap上,您可以傳入圖層參考,或使用「當前圖層」:

map.setLayer('Ground');
map.setCollision([1, 2, 3]);  // Applies to current layer
// Or specify a layer explicitly:
map.setCollision([1, 2, 3], true, true, 'Ground');

物理整合(Arcade)

// Enable collisions between a sprite and a tilemap layer
this.physics.add.collider(player, groundLayer);// With a callback
this.physics.add.collider(player, groundLayer, (sprite, tile) => {
    if (tile.index === 5) {
        // Hit a special tile
    }
});// Overlap detection instead of collision
this.physics.add.overlap(player, groundLayer, (sprite, tile) => {
    // Player is overlapping this tile
});

該圖層的格子必須已設定碰撞(透過 setCollision* 方法)設定碰撞,物理系統才能偵測到這些方塊。該圖層本身具備 collisionCategorycollisionMask 屬性,用於碰撞過濾。

地磚屬性

可在 Tiled 的圖塊集編輯器中為圖塊設定自訂屬性:

// Access tile properties
const tile = layer.getTileAt(10, 5);
console.log(tile.properties.damage);    // Custom property from Tiled
console.log(tile.properties.type);      // Custom property from Tiled// Set collision based on custom properties
layer.setCollisionByProperty({ collides: true });
layer.setCollisionByProperty({ type: ['wall', 'rock'] });

地磚回呼

// Callback by tile index - fires when physics body overlaps these tiles
map.setTileIndexCallback([5, 6, 7], (sprite, tile) => {
    // Called for tiles with index 5, 6, or 7
    console.log('Hit tile', tile.index, 'at', tile.x, tile.y);
}, this);// Callback by tile location - fires for tiles in a rectangular area
map.setTileLocationCallback(10, 10, 5, 5, (sprite, tile) => {
    // Called for any tile in the 5x5 region starting at (10, 10)
}, this);// Per-tile callback
const tile = layer.getTileAt(10, 5);
tile.collisionCallback = (sprite, tile) => {
    // Custom logic for this specific tile
};

地磚回呼需在物體與圖層之間存在有效的物理碰撞體/重疊區域。

查詢地磚

const tile = layer.getTileAt(10, 5);               // By tile coords (or null)
const tile = layer.getTileAt(10, 5, true);          // nonNull: Tile with index -1 instead of null
const tile = layer.getTileAtWorldXY(worldX, worldY); // By world coords
const exists = layer.hasTileAt(10, 5);              // Boolean check// Region queries
const tiles = layer.getTilesWithin(0, 0, 10, 10);            // Tile coord region
const tiles = layer.getTilesWithinWorldXY(x, y, w, h);       // World coord region
const tiles = layer.getTilesWithinShape(circle);              // Shape overlap// Functional queries
const water = layer.filterTiles(t => t.properties.type === 'water');
const spawn = layer.findTile(t => t.properties.isSpawn);
layer.forEachTile(t => { /* iterate all tiles */ });

執行時修改地磚

layer.putTileAt(5, 10, 10);                      // Place tile index 5 at (10, 10)
layer.putTileAtWorldXY(5, worldX, worldY);        // Place by world coords
layer.putTilesAt([[1, 2], [3, 4]], 10, 10);       // Place a 2x2 grid
layer.removeTileAt(10, 10);                       // Remove tile
layer.fill(1, 0, 0, 10, 10);                     // Fill 10x10 region with index 1
layer.replaceByIndex(5, 10);                      // Replace all index-5 with index-10
layer.copy(0, 0, 5, 5, 20, 20);                  // Copy 5x5 from (0,0) to (20,20)
layer.randomize(0, 0, 10, 10, [1, 2, 3, 4]);     // Random tiles in region
layer.weightedRandomize([{ index: 1, weight: 4 }, { index: 2, weight: 1 }], 0, 0, 10, 10);
layer.shuffle(0, 0, 10, 10);                     // Shuffle tiles in region

座標轉換

const tileXY = layer.worldToTileXY(worldX, worldY);   // World -> tile coords
const worldXY = layer.tileToWorldXY(tileX, tileY);    // Tile -> world coords// Reuse a vector to avoid allocation
const vec = new Phaser.Math.Vector2();
layer.worldToTileXY(worldX, worldY, true, vec);  // snapToFloor = true

物件圖層(瓦片式)

瓦片式物件圖層用於定義點、矩形及貼圖的放置位置。請使用 createFromObjectsTilemap:

// Create sprites from all objects on the 'Enemies' object layer
const enemies = map.createFromObjects('Enemies', {
    gid: 26,          // Match by tile GID
    classType: Enemy   // Custom class extending Sprite
});// Match by name
const coins = map.createFromObjects('Items', {
    name: 'coin',
    key: 'coin-texture',
    frame: 0
});// Match by type
const spawns = map.createFromObjects('Spawns', {
    type: 'player-spawn'
});// Access raw object layer data
const objectLayer = map.getObjectLayer('Enemies');
objectLayer.objects.forEach(obj => {
    console.log(obj.name, obj.x, obj.y, obj.properties);
});

createFromObjects(layerName, config, useTileset) 設定選項: id, gid, name, type, classType (預設 Sprite), scene, container, key, frame, ignoreTileset.

動畫磁磚

貼圖動畫是在 Tiled 的貼圖集編輯器中定義,並會自動解析。 TilemapLayerTilemapGPULayer 皆支援動態地磚。 TilemapLayerBase 使用 ElapseTimer 透過 preUpdate.

等距、六邊形與錯位地圖

// Isometric map
const map = this.add.tilemap('iso-map');
const tileset = map.addTilesetImage('iso-tiles', 'iso-img');
const layer = map.createLayer('Ground', tileset);// Get tile at world coords in isometric space
const tile = layer.getIsoTileAtWorldXY(worldX, worldY);// TilemapGPULayer does NOT support iso/hex/staggered - use TilemapLayer

地圖的 orientation 屬性由 Tiled 資料設定。座標轉換函式會根據方位自動選取。

API 快速參考

瓦片地圖(資料容器 — 不進行渲染)

大多數瓦片查詢/碰撞/操作方法同時存在於 Tilemap (並附帶額外的 layer 參數) 與 TilemapLayerBase (無)兩者皆有。建議直接在圖層上呼叫。

TilemapLayerBase(渲染層 — CPU 與 GPU)

碰撞: setCollision(indexes), setCollisionBetween(start, stop), setCollisionByProperty(props), setCollisionByExclusion(indexes), setCollisionFromCollisionGroup(), setTileIndexCallback(indexes, cb, ctx), setTileLocationCallback(x, y, w, h, cb, ctx)

瓦片查詢: getTileAt(x, y, nonNull), getTileAtWorldXY(wx, wy, nonNull, cam), getTilesWithin(x, y, w, h, opts), getTilesWithinWorldXY(wx, wy, w, h, opts, cam), getTilesWithinShape(shape, opts, cam), hasTileAt(x, y), hasTileAtWorldXY(wx, wy, cam), filterTiles(cb), findTile(cb), forEachTile(cb)

瓦片操作: putTileAt(tile, x, y), putTileAtWorldXY(tile, wx, wy), putTilesAt(arr, x, y), removeTileAt(x, y), fill(index, x, y, w, h), copy(sx, sy, w, h, dx, dy), randomize(x, y, w, h, indexes), weightedRandomize(weights, x, y, w, h), shuffle(x, y, w, h), swapByIndex(a, b), replaceByIndex(find, replace), createFromTiles(indexes, replacements, config)

座標: worldToTileXY(wx, wy, snap, vec, cam), tileToWorldXY(tx, ty, vec, cam)

TilemapGPULayer(額外)

地磚屬性

index (數字,-1 表示為空), x/y (地磚座標), pixelX/pixelY (相對於圖層的像素位置), width/height, properties (來自 Tiled 的物件), collideLeft/Right/Up/Down (布林值), collisionCallback (函式), tint (數字), rotation (數字), alpha, flipX/flipY, physics (引擎資料物件)

注意事項

  1. 圖塊集名稱必須與 Tiled 中的名稱完全一致。 addTilesetImage 的第一个參數是 Tiled 中定義的圖塊集名稱,而非 Phaser 的紋理鍵。若兩者不符,系統會 null 並在控制台顯示警告訊息。

  2. 圖層名稱必須與 Tiled 完全一致。 createLayer 此函式會從 Tiled 取得圖層名稱(或圖層索引)。群組圖層的子元素名前會加上 'GroupName/LayerName'.

  3. 每個圖層只能建立一次。若呼叫 createLayer 兩次並使用相同的圖層 ID 會返回 null 並發出警告。圖層資料僅能與一個圖層遊戲物件相關聯。

  4. setCollision 必須在物理碰撞體生效前呼叫此方法。若未將磁磚標記為可碰撞, this.physics.add.collider() 將穿過所有地磚。

  5. TilemapGPULayer 僅支援正投影。它不支援等角投影、六邊形或錯位地圖。此外,每層僅支援單一瓦片集。

  6. TilemapGPULayer 需要手動重新生成貼圖。在呼叫 putTileAt 或其他編輯方法後,請呼叫 generateLayerDataTexture() ,否則變更將不會顯示。

  7. 不支援「圖片集合」類型的圖塊集。Tiled 解析器要求圖塊集中的所有圖塊必須位於單一圖片中。必須在匯出的 JSON 中包含嵌入式圖塊集。

  8. 磁磚索引 -1 表示為空。許多方法預設會將 null 。請傳入 nonNull: true 可取得一個帶有 index === -1 來取得 Tile 物件。

  9. insertNull 在瓦片地圖生成器中。建立瓦片地圖時, insertNull: true 會儲存 null 來表示空地磚,而非使用索引為 -1 的 Tile 物件。此舉可為大型稀疏地圖節省記憶體,但會阻止在空格中動態放置地磚。

  10. Tile 回呼函式僅在物理模擬處於活躍狀態時才會觸發。 setTileIndexCallbacksetTileLocationCallback 必須具備物理碰撞體,或物體與圖層之間存在重疊,才會觸發。

  11. 圖層位置與 Tiled 偏移量。xy 未在 createLayer中未指定,則預設採用在 Tiled 中定義的圖層偏移量,而非 (0, 0)。

原始檔案地圖

在 GitHub 上查看

Tilemaps

Phaser Tilemaps render tile-based levels from Tiled JSON, CSV, or raw 2D arrays. A Tilemap holds parsed map data and provides methods to add tilesets, create layers, set collision, and query tiles. Layers (TilemapLayer or TilemapGPULayer) are the Game Objects that actually render tiles. Phaser supports orthogonal, isometric, hexagonal, and staggered maps.

Key source paths: src/tilemaps/Tilemap.js, src/tilemaps/TilemapLayer.js, src/tilemaps/TilemapGPULayer.js, src/tilemaps/TilemapLayerBase.js, src/tilemaps/Tile.js, src/tilemaps/Tileset.js, src/tilemaps/TilemapFactory.js, src/tilemaps/components/, src/tilemaps/parsers/tiled/ Related skills: ../loading-assets/SKILL.md, ../sprites-and-images/SKILL.md

Quick Start

class GameScene extends Phaser.Scene {
    preload() {
        // Load the Tiled JSON and the tileset image
        this.load.tilemapTiledJSON('map', 'assets/level1.json');
        this.load.image('tiles', 'assets/tilesheet.png');
    }    create() {
        // Create the tilemap from cached JSON
        const map = this.add.tilemap('map');        // Link the tileset image to the tileset name used in Tiled
        const tileset = map.addTilesetImage('tilesheet', 'tiles');        // Create a layer - layerID must match the layer name in Tiled
        const ground = map.createLayer('Ground', tileset);        // Enable collision on specific tile indexes
        ground.setCollision([1, 2, 3]);
    }
}

The flow is always: load JSON + image, create tilemap, add tileset image, create layer(s), set collision.

Core Concepts

Tilemap vs Layer

A Tilemap is a data container, not a display object. It stores parsed map data (layers, tilesets, objects) and provides methods that operate on them. A TilemapLayer or TilemapGPULayer is the actual Game Object added to the display list that renders tiles.

const map = this.add.tilemap('map');    // Data container (not rendered)
const layer = map.createLayer('Ground', tileset);  // Game Object (rendered)

this.add.tilemap(key) is a factory registered on GameObjectFactory. It delegates to ParseToTilemap which reads from the cache and returns a Tilemap instance.

Tilesets

A Tileset (src/tilemaps/Tileset.js) links a tileset name (from Tiled) to a loaded texture. It stores firstgid, tile dimensions, margin, and spacing.

// tilesetName: the name in Tiled's tileset panel
// key: the Phaser texture key (defaults to tilesetName if omitted)
const tileset = map.addTilesetImage('tilesetName', 'textureKey');// Override tile dimensions, margin, and spacing if needed
const tileset = map.addTilesetImage('name', 'key', 16, 16, 1, 2);

addTilesetImage(tilesetName, key, tileWidth, tileHeight, tileMargin, tileSpacing, gid, tileOffset) - If the tileset name already exists in the parsed map data, it updates the existing Tileset object with the texture. If not (non-Tiled maps), it creates a new Tileset.

Important: The Phaser Tiled parser does not support "Collection of Images" tilesets. All tiles must be in a single tileset image per tileset.

The Tile Class

Each cell in a layer is a Tile object (src/tilemaps/Tile.js). Key properties:

  • index - tile index in the tileset (-1 for empty)
  • x, y - tile coordinates (in tiles, not pixels)
  • pixelX, pixelY - pixel position relative to layer origin
  • width, height - tile size in pixels
  • properties - custom properties from Tiled (object)
  • collideLeft, collideRight, collideUp, collideDown - per-edge collision flags
  • faceLeft, faceRight, faceTop, faceBottom - interesting face flags for collision optimization
  • collisionCallback - per-tile collision callback function
  • tint - tint color value (default 0xffffff)
  • tintMode - tint blend mode (default TintModes.MULTIPLY)
  • rotation - rotation angle
  • physics - object for physics-engine-specific data (e.g. bodies)
  • alpha, visible, flipX, flipY - inherited from mixins

TilemapGPULayer (v4.0.0)

TilemapGPULayer is a high-performance WebGL-only alternative to TilemapLayer. It renders the entire layer as a single quad using a shader, making it almost entirely GPU-bound.

// Pass gpu: true as the 5th argument to createLayer
const layer = map.createLayer('Ground', tileset, 0, 0, true);

Capabilities:

  • Single tileset per layer only (no multi-tileset)
  • Max tilemap size: 4096x4096 tiles
  • Max unique tile IDs: 2^23 (8,388,608)
  • Supports tile flip and tile animation
  • Orthographic maps only (no iso/hex/staggered)
  • Smooth tile borders with LINEAR filtering (no seams)
  • Sharp pixels with NEAREST filtering

Restrictions:

  • Layer edits do not display automatically. Call generateLayerDataTexture() after modifying tiles.
  • WebGL renderer only (no Canvas fallback)
  • Cannot use multiple tilesets on a single layer
// If you edit tiles on a GPU layer, regenerate the data texture:
gpuLayer.putTileAt(5, 10, 10);
gpuLayer.generateLayerDataTexture();

TilemapLayerBase

Both TilemapLayer and TilemapGPULayer extend TilemapLayerBase (src/tilemaps/TilemapLayerBase.js), which extends GameObject. The base class provides all tile query, manipulation, and collision methods. It includes these component mixins: Alpha, BlendMode, ComputedSize, Depth, ElapseTimer, Flip, GetBounds, Lighting, Mask, Origin, RenderNodes, Transform, Visible, ScrollFactor, and Arcade Physics Collision.

Common Patterns

Creating from Tiled JSON

preload() {
    this.load.tilemapTiledJSON('map', 'assets/map.json');
    this.load.image('tiles', 'assets/tileset.png');
}create() {
    const map = this.add.tilemap('map');
    const tileset = map.addTilesetImage('TilesetNameInTiled', 'tiles');
    const layer = map.createLayer('LayerNameInTiled', tileset);
}

The layerID passed to createLayer must match the layer name in Tiled exactly. Group layer children are flattened with a 'ParentGroup/Layer' naming convention.

Multiple Layers

const map = this.add.tilemap('map');
const tileset = map.addTilesetImage('terrain', 'terrain-img');const background = map.createLayer('Background', tileset);
const ground = map.createLayer('Ground', tileset);
const foreground = map.createLayer('Foreground', tileset);// Layers are rendered in creation order. Use depth for finer control:
foreground.setDepth(10);

A layer can use multiple tilesets (CPU layer only):

const tiles1 = map.addTilesetImage('terrain', 'terrain-img');
const tiles2 = map.addTilesetImage('objects', 'objects-img');
const layer = map.createLayer('Ground', [tiles1, tiles2]);

Creating a Blank Layer

const map = this.add.tilemap('map');
const tileset = map.addTilesetImage('terrain', 'terrain-img');// createBlankLayer(name, tileset, x, y, width, height, tileWidth, tileHeight)
const layer = map.createBlankLayer('dynamic', tileset, 0, 0, 50, 50, 32, 32);// Fill it with tiles
layer.fill(1);  // Fill entire layer with tile index 1
layer.putTileAt(5, 10, 10);  // Place tile index 5 at tile coord (10, 10)

Collision Setup

There are several ways to enable tile collision for Arcade Physics:

// By specific tile indexes
layer.setCollision([1, 2, 3]);// By range (inclusive)
layer.setCollisionBetween(1, 50);// By tile property (set in Tiled's tileset editor)
layer.setCollisionByProperty({ collides: true });
// Supports arrays: { type: ['stone', 'lava'] }// By exclusion - collide on ALL tiles except these
layer.setCollisionByExclusion([-1, 0]);  // -1 is empty, 0 is often background// From Tiled collision editor shapes
layer.setCollisionFromCollisionGroup();

All collision methods on TilemapLayerBase mirror methods on Tilemap but don't require a layer parameter. On the Tilemap, you can pass a layer reference or use the "current layer":

map.setLayer('Ground');
map.setCollision([1, 2, 3]);  // Applies to current layer
// Or specify a layer explicitly:
map.setCollision([1, 2, 3], true, true, 'Ground');

Physics Integration (Arcade)

// Enable collisions between a sprite and a tilemap layer
this.physics.add.collider(player, groundLayer);// With a callback
this.physics.add.collider(player, groundLayer, (sprite, tile) => {
    if (tile.index === 5) {
        // Hit a special tile
    }
});// Overlap detection instead of collision
this.physics.add.overlap(player, groundLayer, (sprite, tile) => {
    // Player is overlapping this tile
});

The layer must have collision set on its tiles (via setCollision* methods) for physics to detect them. The layer itself has collisionCategory and collisionMask properties for collision filtering.

Tile Properties

Tiles can have custom properties set in Tiled's tileset editor:

// Access tile properties
const tile = layer.getTileAt(10, 5);
console.log(tile.properties.damage);    // Custom property from Tiled
console.log(tile.properties.type);      // Custom property from Tiled// Set collision based on custom properties
layer.setCollisionByProperty({ collides: true });
layer.setCollisionByProperty({ type: ['wall', 'rock'] });

Tile Callbacks

// Callback by tile index - fires when physics body overlaps these tiles
map.setTileIndexCallback([5, 6, 7], (sprite, tile) => {
    // Called for tiles with index 5, 6, or 7
    console.log('Hit tile', tile.index, 'at', tile.x, tile.y);
}, this);// Callback by tile location - fires for tiles in a rectangular area
map.setTileLocationCallback(10, 10, 5, 5, (sprite, tile) => {
    // Called for any tile in the 5x5 region starting at (10, 10)
}, this);// Per-tile callback
const tile = layer.getTileAt(10, 5);
tile.collisionCallback = (sprite, tile) => {
    // Custom logic for this specific tile
};

Tile callbacks require an active physics collider/overlap between the body and the layer.

Querying Tiles

const tile = layer.getTileAt(10, 5);               // By tile coords (or null)
const tile = layer.getTileAt(10, 5, true);          // nonNull: Tile with index -1 instead of null
const tile = layer.getTileAtWorldXY(worldX, worldY); // By world coords
const exists = layer.hasTileAt(10, 5);              // Boolean check// Region queries
const tiles = layer.getTilesWithin(0, 0, 10, 10);            // Tile coord region
const tiles = layer.getTilesWithinWorldXY(x, y, w, h);       // World coord region
const tiles = layer.getTilesWithinShape(circle);              // Shape overlap// Functional queries
const water = layer.filterTiles(t => t.properties.type === 'water');
const spawn = layer.findTile(t => t.properties.isSpawn);
layer.forEachTile(t => { /* iterate all tiles */ });

Modifying Tiles at Runtime

layer.putTileAt(5, 10, 10);                      // Place tile index 5 at (10, 10)
layer.putTileAtWorldXY(5, worldX, worldY);        // Place by world coords
layer.putTilesAt([[1, 2], [3, 4]], 10, 10);       // Place a 2x2 grid
layer.removeTileAt(10, 10);                       // Remove tile
layer.fill(1, 0, 0, 10, 10);                     // Fill 10x10 region with index 1
layer.replaceByIndex(5, 10);                      // Replace all index-5 with index-10
layer.copy(0, 0, 5, 5, 20, 20);                  // Copy 5x5 from (0,0) to (20,20)
layer.randomize(0, 0, 10, 10, [1, 2, 3, 4]);     // Random tiles in region
layer.weightedRandomize([{ index: 1, weight: 4 }, { index: 2, weight: 1 }], 0, 0, 10, 10);
layer.shuffle(0, 0, 10, 10);                     // Shuffle tiles in region

Coordinate Conversion

const tileXY = layer.worldToTileXY(worldX, worldY);   // World -> tile coords
const worldXY = layer.tileToWorldXY(tileX, tileY);    // Tile -> world coords// Reuse a vector to avoid allocation
const vec = new Phaser.Math.Vector2();
layer.worldToTileXY(worldX, worldY, true, vec);  // snapToFloor = true

Object Layers (Tiled)

Tiled object layers define points, rectangles, and sprite placement. Use createFromObjects on the Tilemap:

// Create sprites from all objects on the 'Enemies' object layer
const enemies = map.createFromObjects('Enemies', {
    gid: 26,          // Match by tile GID
    classType: Enemy   // Custom class extending Sprite
});// Match by name
const coins = map.createFromObjects('Items', {
    name: 'coin',
    key: 'coin-texture',
    frame: 0
});// Match by type
const spawns = map.createFromObjects('Spawns', {
    type: 'player-spawn'
});// Access raw object layer data
const objectLayer = map.getObjectLayer('Enemies');
objectLayer.objects.forEach(obj => {
    console.log(obj.name, obj.x, obj.y, obj.properties);
});

createFromObjects(layerName, config, useTileset) config options: id, gid, name, type, classType (default Sprite), scene, container, key, frame, ignoreTileset.

Animated Tiles

Tile animations are defined in Tiled's tileset editor and parsed automatically. Both TilemapLayer and TilemapGPULayer support animated tiles. The TilemapLayerBase uses ElapseTimer to track animation time via preUpdate.

Isometric, Hexagonal, and Staggered Maps

// Isometric map
const map = this.add.tilemap('iso-map');
const tileset = map.addTilesetImage('iso-tiles', 'iso-img');
const layer = map.createLayer('Ground', tileset);// Get tile at world coords in isometric space
const tile = layer.getIsoTileAtWorldXY(worldX, worldY);// TilemapGPULayer does NOT support iso/hex/staggered - use TilemapLayer

The map orientation property is set from Tiled data. Coordinate conversion functions are automatically selected based on orientation.

API Quick Reference

Tilemap (data container - not rendered)

Most tile query/collision/manipulation methods exist on both Tilemap (with extra layer param) and TilemapLayerBase (without). Prefer calling on the layer directly.

TilemapLayerBase (rendered layer - CPU and GPU)

Collision: setCollision(indexes), setCollisionBetween(start, stop), setCollisionByProperty(props), setCollisionByExclusion(indexes), setCollisionFromCollisionGroup(), setTileIndexCallback(indexes, cb, ctx), setTileLocationCallback(x, y, w, h, cb, ctx)

Tile queries: getTileAt(x, y, nonNull), getTileAtWorldXY(wx, wy, nonNull, cam), getTilesWithin(x, y, w, h, opts), getTilesWithinWorldXY(wx, wy, w, h, opts, cam), getTilesWithinShape(shape, opts, cam), hasTileAt(x, y), hasTileAtWorldXY(wx, wy, cam), filterTiles(cb), findTile(cb), forEachTile(cb)

Tile manipulation: putTileAt(tile, x, y), putTileAtWorldXY(tile, wx, wy), putTilesAt(arr, x, y), removeTileAt(x, y), fill(index, x, y, w, h), copy(sx, sy, w, h, dx, dy), randomize(x, y, w, h, indexes), weightedRandomize(weights, x, y, w, h), shuffle(x, y, w, h), swapByIndex(a, b), replaceByIndex(find, replace), createFromTiles(indexes, replacements, config)

Coordinates: worldToTileXY(wx, wy, snap, vec, cam), tileToWorldXY(tx, ty, vec, cam)

TilemapGPULayer (additional)

Tile Properties

index (number, -1=empty), x/y (tile coords), pixelX/pixelY (pixel pos relative to layer), width/height, properties (object from Tiled), collideLeft/Right/Up/Down (boolean), collisionCallback (function), tint (number), rotation (number), alpha, flipX/flipY, physics (object for engine data)

Gotchas

  1. Tileset name must match Tiled exactly. The first argument to addTilesetImage is the tileset name as defined in Tiled, not the Phaser texture key. If they don't match, you get null back and a console warning.

  2. Layer name must match Tiled exactly. createLayer takes the layer name from Tiled (or layer index). Group layer children are prefixed with 'GroupName/LayerName'.

  3. Each layer can only be created once. Calling createLayer with the same layer ID twice returns null with a warning. The layer data can only be associated with one layer Game Object.

  4. setCollision must be called before physics colliders work. Without marking tiles as collidable, this.physics.add.collider() will pass through all tiles.

  5. TilemapGPULayer is orthographic only. It does not support isometric, hexagonal, or staggered maps. It also only supports a single tileset per layer.

  6. TilemapGPULayer requires manual texture regeneration. After calling putTileAt or other edit methods, call generateLayerDataTexture() or the changes won't appear.

  7. "Collection of Images" tilesets are not supported. The Tiled parser requires all tiles in a tileset to be in a single image. Embedded tilesets in the exported JSON are required.

  8. Tile index -1 means empty. Many methods return null for empty tiles by default. Pass nonNull: true to get a Tile object with index === -1 instead.

  9. insertNull in tilemap factory. When creating a tilemap, insertNull: true stores null for empty tiles instead of Tile objects with index -1. Saves memory for large sparse maps but prevents dynamic tile placement in empty cells.

  10. Tile callbacks only fire with active physics. setTileIndexCallback and setTileLocationCallback require a physics collider or overlap between the body and the layer to trigger.

  11. Layer position and Tiled offset. If x and y are not specified in createLayer, they default to the layer offset defined in Tiled, not (0, 0).

Source File Map

所有檔案

0 個檔案

安裝 tilemaps

請下載並將技能檔案解壓縮至您的 .claude/skills/ 目錄中。

下載 ZIP

複製儲存庫並將技能檔案複製到您的專案中。

git clone https://github.com/phaserjs/phaser/tree/master/skills/tilemaps # Copy the skill folder to .claude/skills/ or .codex/skills/

複製 複製
快速設定: 將技能資料夾複製到 .claude/skills/,Claude 會自動偵測並使用該技能
儲存庫 phaserjs/phaser

相關技能

multica-creating-agents
更新時間 2026-08-12
v4-new-features
更新時間 2026-08-04
agent-github-pr-manager
更新時間 2026-08-03
pixijs-application
更新時間 2026-08-04
OR