Community程式設計與開發github.com

ziva-sh/godot-tilemaplayer

正確使用 Godot 4.3+ TileMapLayer 節點程式碼,包括設定、讀取、清除、座標轉換、地形與碰撞處理,以及從舊版 TileMap 遷移。

godot-tilemaplayer 是什麼?

這個技能提供了一份完整的 Godot 4.3+ 開發指南,專注於 TileMapLayer 節點的使用。它涵蓋了細胞 API 的正確用法,如 set_cell(coords, source_id, atlas_coords)、讀取細胞資訊與自訂資料、清除細胞、以及 local_to_map 和 map_to_local 的座標轉換。此外還詳細說明了地形(自動拼接)系統、透過 TileSet 物理圖層設定碰撞、如何取得角色碰撞到的方格,以及從已棄用的 TileMap 節點遷移到多個 TileMapLayer 的具體步驟。此技能對在 GDScript 中放置、讀取或清除圖塊、在程式碼中建立 TileSet、程式化生成關卡、處理圖塊碰撞,以及將 Godot 3 或 Godot 4.0 的 TileMap 程式碼移植到 4.3+ 的開發者極為有用。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ziva-sh/godot-skills/tree/HEAD/skills/godot-tilemaplayer

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

TileMapLayer (Godot 4.3+)

Godot 4.3 新增了 TileMapLayer 節點,並棄用了 TileMap。每個 TileMapLayer 代表一個圖層,因此一個含有地面、牆壁與裝飾的關卡,會由三個共享同一個 TileSet 的兄弟 TileMapLayer 節點組成。請勿針對 TileMap 撰寫新程式碼,也絕對不要使用 Godot 3 的 API(例如 set_cellv、world_to_map、set_cell(x, y, tile_id))。

細胞 API

一個細胞由整數地圖座標(Vector2i)識別。一個圖塊則由三個值識別:

  • source_id:TileSet 中來源的 ID(可能是一個圖集紋理或場景集合)。第一個圖集通常是 0;請參考 TileSet 編輯器或 TileSet.add_source() 的回傳值。
  • atlas_coords:該圖塊在圖集中的欄與列,單位為圖塊而非像素。
  • alternative_tile:除非您製作了翻轉或旋轉的替代圖塊,否則為 0。
extends TileMapLayer

const SOURCE_ID := 0
const GRASS := Vector2i(0, 0)
const WALL := Vector2i(1, 0)


func _ready() -> void:
	for x in range(10):
		set_cell(Vector2i(x, 5), SOURCE_ID, GRASS)
	set_cell(Vector2i(3, 4), SOURCE_ID, WALL)

	var source_id := get_cell_source_id(Vector2i(3, 4))  # 細胞為空時回傳 -1
	var atlas := get_cell_atlas_coords(Vector2i(3, 4))  # 為空時回傳 Vector2i(-1, -1)
	print(source_id, atlas)

	erase_cell(Vector2i(3, 4))
	print(get_used_cells().size(), " 個細胞,範圍 ", get_used_rect())


func cell_at_global(global_point: Vector2) -> Vector2i:
	return local_to_map(to_local(global_point))


func center_of_cell(coords: Vector2i) -> Vector2:
	# map_to_local 回傳該圖層本地空間中的細胞中心。
	return to_global(map_to_local(coords))

重要事實:

  • 使用預設引數呼叫 set_cell(coords) 會清除該細胞(source_id 預設為 -1)。放置圖塊時,務必傳入 source_id 和 atlas_coords。
  • 設定不存在的 atlas_coords 仍然會儲存該細胞(get_cell_source_id() 會回傳來源),但之後呼叫 get_cell_tile_data() 會記錄 The TileSetAtlasSource atlas has no tile at (x, y). 並回傳 null。
  • local_to_map() 和 map_to_local() 作用於圖層的本地空間。當圖層被移動或縮放時,請使用 to_local() / to_global() 進行轉換。
  • get_used_cells_by_id(source_id, atlas_coords) 可找出所有使用特定圖塊的細胞。
  • 變更會在影格結束時批次處理。若需要立即更新碰撞或場景圖塊,請呼叫 update_internals()。

每個圖塊的自訂資料

在 TileSet 中新增自訂資料圖層(檢查器 > TileSet > Custom Data Layers,例如類型為 int 的 damage),在 TileSet 編輯器中繪製數值,然後讀取:

extends TileMapLayer


func damage_at(coords: Vector2i) -> int:
	var data := get_cell_tile_data(coords)
	if data == null:
		return 0
	return data.get_custom_data("damage")

get_cell_tile_data() 對空細胞和場景集合圖塊會回傳 null,因此請先檢查後再呼叫其方法。

地形(自動拼接)

Godot 3 的自動拼接遮罩已改為地形集。在 TileSet 中,新增地形集與地形,然後在 TileSet 編輯器中為每個圖塊繪製其地形連接位元。在程式碼中,傳入所有您想填充的細胞:

extends TileMapLayer

const TERRAIN_SET := 0
const DIRT := 0


func paint_room(rect: Rect2i) -> void:
	var cells: Array[Vector2i] = []
	for x in range(rect.position.x, rect.end.x):
		for y in range(rect.position.y, rect.end.y):
			cells.append(Vector2i(x, y))
	set_cells_terrain_connect(cells, TERRAIN_SET, DIRT)

set_cells_terrain_connect() 會挑選圖塊使邊緣相連;set_cells_terrain_path() 則適用於道路與河流的繪製。如果結果顯示錯誤或缺失圖塊,表示 TileSet 中的連接位元不完整;程式碼無法修正這個問題。

碰撞

只有當 TileSet 設有物理圖層(TileSet 檢查器 > Physics Layers > Add Element)且圖塊在該圖層上繪有碰撞多邊形(TileSet 編輯器中選取圖塊,Physics > Physics Layer 0;按下 F 可繪製一個完整方塊矩形)時,圖塊才會產生碰撞。圖層的 collision_enabled 屬性預設為開啟。物理圖層還攜帶 collision_layer 和 collision_mask,這些設定在 TileSet 上,而非節點上。

若要找出 CharacterBody2D 觸碰了哪個圖塊,請使用碰撞點。除非 physics_quadrant_size 為 1(Godot 4.5+ 預設會將最多 16 x 16 個細胞合併為一個碰撞體),否則 get_coords_for_body_rid() 回傳的是物理象限的座標,而非細胞的座標:

extends CharacterBody2D

@export var level: TileMapLayer


func _physics_process(delta: float) -> void:
	velocity += get_gravity() * delta
	move_and_slide()
	for i in get_slide_collision_count():
		var collision := get_slide_collision(i)
		if collision.get_collider() == level:
			# 稍微踏入圖塊內部,因為接觸點在其邊緣。
			var inside := collision.get_position() - collision.get_normal()
			var coords := level.local_to_map(level.to_local(inside))
			print("觸碰圖塊 ", coords)

在程式碼中建立 TileSet

適用於程式化生成的關卡以及無法使用 TileSet 編輯器的測試。碰撞多邊形點是相對於圖塊中心。

extends Node2D


func _ready() -> void:
	var tile_set := TileSet.new()
	tile_set.tile_size = Vector2i(16, 16)
	tile_set.add_physics_layer()

	var source := TileSetAtlasSource.new()
	source.texture = load("res://tiles.png") as Texture2D
	source.texture_region_size = Vector2i(16, 16)
	source.create_tile(Vector2i(0, 0))
	var source_id := tile_set.add_source(source)

	var data := source.get_tile_data(Vector2i(0, 0), 0)
	data.add_collision_polygon(0)
	data.set_collision_polygon_points(0, 0, PackedVector2Array([
		Vector2(-8, -8), Vector2(8, -8), Vector2(8, 8), Vector2(-8, 8),
	]))

	var layer := TileMapLayer.new()
	layer.tile_set = tile_set
	add_child(layer)
	layer.set_cell(Vector2i(0, 0), source_id, Vector2i(0, 0))

從 TileMap 遷移

在編輯器中:選取 TileMap,開啟 TileMap 底部面板,點選工具箱圖示並選擇「Extract TileMap layers as individual TileMapLayer nodes」。然後更新腳本:所有原本需要 layer 索引的 TileMap 方法,現在都變成該圖層節點上的方法,且不再需要索引。

舊程式碼TileMapLayer
tile_map.set_cell(0, coords, source_id, atlas_coords)ground.set_cell(coords, source_id, atlas_coords)
tile_map.get_cell_source_id(1, coords)walls.get_cell_source_id(coords)
tile_map.get_used_cells(0)ground.get_used_cells()
tile_map.set_layer_enabled(2, false)decoration.enabled = false
tile_map.set_layer_z_index(1, 5)walls.z_index = 5
Godot 3 set_cellv(pos, id), world_to_map(p), map_to_world(c)set_cell(coords, source_id, atlas_coords), local_to_map(p), map_to_local(c)

常見錯誤

  • 傳遞像素位置給 set_cell()。請先使用 local_to_map() 進行轉換。
  • 以單一數字呼叫 set_cell(coords, tile_index):第二個引數是來源 ID,而 atlas_coords 預設為 Vector2i(-1, -1),這會清除該細胞。
  • 期望由未設定物理圖層的 TileSet,或由未繪製多邊形的圖塊產生碰撞。
  • 使用預設的 physics_quadrant_size 並呼叫 get_coords_for_body_rid() 而取得象限座標。
  • 未進行 null 檢查就呼叫 get_cell_tile_data() 的方法。
  • 因為舊版教學而為新專案新增 TileMap 節點。請改為每個圖層使用一個 TileMapLayer。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

ziva-sh/godot-4-api-pitfalls

Fixes Godot 3 APIs and GDScript syntax that AI assistants write into Godot 4 projects, such as KinematicBody2D, move_and_slide(velocity), export, onready, setget, yield, string connect(), instance(), rand_range, the Tween node, File, change_scene, Spatial, rect_* properties, Pool*Array, OS time functions and the old TileMap API. Use when writing, reviewing or porting GDScript for Godot 4.x, when a script fails with "not declared", "not found in base", "was removed in Godot 4" or "is not present

ziva-sh/godot-control-layout

Builds Godot 4 Control UIs that resize instead of clipping or overlapping - containers versus anchors, anchor presets from code, size flags, custom_minimum_size, MarginContainer margins, Label wrapping, mouse_filter, CanvasLayer HUDs, Godot 4 theme override names (add_theme_color_override and friends) and the display/window/stretch settings for multiple resolutions. Use when creating or fixing menus, HUDs, dialogs and inventory screens, when UI elements are cut off, zero-sized, overlapping, igno

ziva-sh/godot-scene-organization

Structures Godot 4 projects so scenes stay reusable and references do not break - when to make a scene, a script or a Resource, instancing with @export PackedScene, preload and load, @onready and %UniqueName node access, _ready order, groups, autoloads, class_name, and resource UIDs with the .uid files added in Godot 4.4, including how to move or rename files safely. Use when creating new scenes or scripts, deciding how nodes find each other, adding global state or an event bus, moving or renami

ziva-sh/godot-signals

Godot 4 signal patterns and their failure modes - declaring typed signals, emit(), connect() and disconnect() with Callables, bind() and unbind(), lambdas, CONNECT_ONE_SHOT and CONNECT_DEFERRED, await on signals and timers, editor-made connections stored in .tscn files, and the call down, signal up rule. Use when wiring UI buttons, timers, Area2D or body events and custom game events, when replacing Godot 3 connect("signal", self, "method") or yield code, or when debugging "already connected", "

相關技能