簡介

Godot 4 徹底重寫了 TileMap 系統。如果你曾在 Godot 3 中使用 TileMap,幾乎所有東西都變了 — TileSet 編輯器、圖塊的定義方式、自動拼貼、圖層以及 GDScript API。本指南將從零開始講解全新的架構。

Godot 3 使用者:舊有的 autotileset_cellv()cell_size 全部已被移除。請參閱頁面底部的從 Godot 3 遷移章節。

全新的 TileMap 架構

Godot 4 的 TileMap 系統由兩個主要元件組成:

  • TileMap 節點 — 你加入場景的節點。它持有一個或多個圖層,並參照一個 TileSet 資源。
  • TileSet 資源 — 定義圖塊本身。包含來源(圖集、場景集合等)、物理圖層、導航圖層、自訂資料圖層以及地形集。

關鍵變更:在 Godot 3 中,圖塊大小是在 TileMap 節點上設定的。在 Godot 4 中,圖塊大小改為在 TileSet 資源中定義,而 TileMap 只是參照它。

TileSet 來源

一個 TileSet 可以擁有多個來源,每個來源都以一個 source_id(整數)來識別。來源類型包括:

  • TileSetAtlasSource — 最常見的類型。一張包含多個以網格排列圖塊的紋理圖片。
  • TileSetScenesCollectionSource — 每個圖塊都是一個打包場景,適合用於動畫或可互動的圖塊。

設定 TileSet

步驟 1:建立 TileSet 資源

  1. 在場景中加入一個 TileMap 節點。
  2. 在檢視器中點擊 Tile Set 屬性並選擇 New TileSet
  3. 設定 Tile Size(例如 16x16 或 32x32)。

步驟 2:新增圖集來源

  1. 點擊 TileSet 以開啟底部面板的 TileSet 編輯器。
  2. 點擊 + 按鈕並選擇 Atlas
  3. 將你的圖塊集圖片拖曳到 Texture 屬性中。
  4. 編輯器會根據你的圖塊大小自動將其分割成圖塊。你可以調整紋理區域與邊界。

步驟 3:設定圖塊屬性

在 TileSet 編輯器中,你可以加入各種套用到所有圖塊的圖層類型:

  • Physics Layers — 圖塊的碰撞形狀
  • Navigation Layers — 供尋路使用的可行走多邊形
  • Custom Data Layers — 任意的具型別資料(bool、int、float、String 等)
  • Terrain Sets — 用於自動拼貼(Godot 3 autotile 的替代方案)

TileMap 圖層

單一 TileMap 節點就能包含多個圖層。相較於 Godot 3 需要為背景與前景使用各自獨立的 TileMap 節點,這是一大改進。每個圖層都可以擁有自己的 z-index、y-sort 與 modulate 設定。

常見的圖層配置:

  • Layer 0 — 背景(地面、地板) — z-index: -1
  • Layer 1 — 地形(牆壁、障礙物) — z-index: 0
  • Layer 2 — 前景(顯示在玩家上方的裝飾) — z-index: 1

圖層的 GDScript API

# Set a cell on layer 0
tilemap.set_cell(0, Vector2i(5, 3), source_id, atlas_coords)

# Get cell info
var source = tilemap.get_cell_source_id(0, Vector2i(5, 3))
var coords = tilemap.get_cell_atlas_coords(0, Vector2i(5, 3))

# Erase a cell
tilemap.erase_cell(0, Vector2i(5, 3))

# Check if a cell is occupied
if tilemap.get_cell_source_id(0, Vector2i(5, 3)) != -1:
    print("Cell has a tile")

API 提示:set_cell() 的第一個參數永遠是圖層索引(0、1、2...)。第二個是以 Vector2i 表示的儲存格位置。第三個是 source_id,第四個是以 Vector2i 表示的 atlas_coords

地形系統(自動拼貼)

地形系統取代了 Godot 3 的 autotile。它會根據相鄰的圖塊自動選取正確的圖塊變體。

設定地形

  1. 在 TileSet 中加入一個 Terrain Set(檢視器 → Terrain Sets → Add Element)。
  2. 選擇地形模式:Match Corners and Sides(47 個圖塊)、Match Corners(16 個圖塊)或 Match Sides(16 個圖塊)。
  3. 在該集合內加入地形類型(例如「Grass」、「Dirt」、「Water」)。
  4. 在 TileSet 編輯器中切換至 Select 模式,選取一個圖塊,然後在每個圖塊上繪製地形對接位元(peering bits)。

繪製地形

地形設定完成後,切換至 TileMap 編輯器並選擇 Terrains 分頁。選擇你的地形類型並直接在地圖上繪製,Godot 會自動選取正確的圖塊變體。

# Set terrain programmatically
tilemap.set_cells_terrain_connect(0, [Vector2i(5, 3)], 0, 0)
# Parameters: layer, cells array, terrain_set, terrain index

圖塊上的物理

若要為圖塊加入碰撞:

  1. 在 TileSet 檢視器中加入一個 Physics Layer
  2. 設定此物理圖層所使用的碰撞圖層(collision layer)與遮罩(mask)。
  3. 在 TileSet 編輯器中切換至 Physics 分頁,並在每個圖塊上繪製碰撞多邊形。

提示:你可以為不同的圖塊類型設置多個物理圖層。例如,一個圖層用於牆壁(阻擋移動),另一個用於危險物(透過 Area2D 重疊觸發傷害)。

圖塊上的自訂資料

自訂資料圖層讓你能為任何圖塊附加具型別的中繼資料。這對遊戲邏輯極為實用。

設定自訂資料

  1. 在 TileSet 檢視器中加入一個 Custom Data Layer
  2. 為其命名(例如「is_destructible」)並設定型別(例如 bool)。
  3. 在 TileSet 編輯器中切換至 Custom Data 分頁,並逐一為每個圖塊設定值。

在程式碼中讀取自訂資料

var tile_data = tilemap.get_cell_tile_data(0, Vector2i(5, 3))
if tile_data:
    var is_destructible = tile_data.get_custom_data("is_destructible")
    var damage = tile_data.get_custom_data("damage")
    if is_destructible:
        destroy_tile(Vector2i(5, 3))

常見的自訂資料範例:

  • is_destructible: bool
  • damage: int
  • movement_cost: float
  • tile_type: String(例如 "water"、"lava"、"ice")
  • spawn_chance: float

程序化圖塊擺放

使用全新的 API 以程式方式擺放圖塊相當簡單:

# Fill a rectangular area
for x in range(20):
    for y in range(10):
        tilemap.set_cell(0, Vector2i(x, y), 0, Vector2i(0, 0))

# Random tile placement
for x in range(50):
    for y in range(50):
        if randf() > 0.7:
            tilemap.set_cell(0, Vector2i(x, y), 0, Vector2i(1, 0))
        else:
            tilemap.set_cell(0, Vector2i(x, y), 0, Vector2i(0, 0))

# Get all used cells on a layer
var used_cells: Array[Vector2i] = tilemap.get_used_cells(0)
print("Layer 0 has ", used_cells.size(), " tiles")

# Clear all tiles on a layer
tilemap.clear_layer(0)

# Clear everything
tilemap.clear()

世界座標與地圖座標的轉換

# Convert world position to map coordinates
var map_pos: Vector2i = tilemap.local_to_map(world_position)

# Convert map coordinates to world position (center of tile)
var world_pos: Vector2 = tilemap.map_to_local(Vector2i(5, 3))

# Example: check what tile the player is standing on
var player_tile = tilemap.local_to_map(tilemap.to_local(player.global_position))
var tile_data = tilemap.get_cell_tile_data(0, player_tile)
if tile_data:
    var tile_type = tile_data.get_custom_data("tile_type")
    print("Player is on: ", tile_type)

從 Godot 3 遷移

Godot 3 Godot 4
TileMap.cell_size TileSet.tile_size
set_cellv(pos, tile_id) set_cell(layer, pos, source_id, atlas_coords)
get_cellv(pos) get_cell_source_id(layer, pos)
autotile 地形系統(Terrain Sets)
每個 TileMap 節點一個圖層 單一 TileMap 中的多個圖層
TileMap.tile_set = preload(...) 在檢視器中或透過程式碼指派 TileSet 資源
world_to_map() local_to_map()
map_to_world() map_to_local()

常見錯誤

  1. 忘記先建立 TileSet。在你指派 TileSet 資源之前,TileMap 節點不會顯示圖塊編輯器。請在檢視器中建立一個。

  2. 錯誤的 source_id。如果你只有一個圖集來源,它的 source_id 就是 0。加入第二個來源會使其成為 source_id = 1。請查看 TileSet 編輯器的底部面板 — 每個來源分頁都會顯示其 ID。

  3. 把 atlas_coords 與圖塊 ID 混淆。在 Godot 4 中,並沒有簡單的圖塊 ID。取而代之的是,你透過圖塊在圖集網格中的位置,以 Vector2i(column, row) 來參照它們。

  4. 未指定圖層參數。每個儲存格操作都需要以圖層索引作為第一個引數。忘記它會導致引數錯誤。

  5. 使用 set_cellv()此方法已不再存在。請使用具有新簽章的 set_cell()