godot-tilemap-mastery by thedivergentai/gd-agentic-skills
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-tilemap-masteryTileMapLayer 网格、TileSet 图集、地形自动拼接和自定义数据共同定义了高效的 2D 关卡系统。
用于大型世界的专业 TileMap 序列化和分块管理器。
用于道路、河流和有机路径的高级运行时地形自动拼接(Terrains v2)。
基于自定义数据层管理图块生命值和破坏的模式。
高效读取自定义数据(摩擦力、危险区域)以驱动角色/物理逻辑。
使用批量图块放置逻辑进行优化的程序化生成,以获得更好的性能。
处理 2.5D 效果和多层建筑的 Y 轴排序和 Z 索引分层。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
专业的 TileMap 物理:处理单向碰撞和碰撞层管理。
用于动态世界变换和可破坏环境的运行时导航更新。
使用 TileMapPattern 高效“盖章”复杂的多图块结构部件。
优化:为高频游戏玩法查询缓存 TileData 元数据。
管理向 Godot 4.3 多 TileMapLayer 节点标准的过渡。
set_cell() = 1000 次单独的函数调用 = 缓慢。使用 set_cells_terrain_connect() 进行批量操作,或者缓存更改,一次性应用。set_cell(pos, atlas_coords) 没有 source_id?错误的函数重载 = 崩溃或静默失败。使用 set_cell(pos, source_id, atlas_coords)。set_cell(mouse_position) 没有 local_to_map()?错误的网格位置。始终转换:local_to_map(global_pos)。set_cells_terrain_connect() 进行自动拼接。tile_cache[pos] = get_cell_tile_data(pos)。TileMapLayer 节点# 每个图块可以拥有:
# - 物理层:每个图块的 CollisionShape2D
# - 地形:自动拼接规则
# - 自定义数据:任意属性
为图块添加碰撞:
extends TileMapLayer
func _ready() -> void:
# 在网格坐标 (x, y) 处设置图块
set_cell(Vector2i(0, 0), 0, Vector2i(0, 0)) # source_id, atlas_coords
# 获取坐标处的图块
var atlas_coords := get_cell_atlas_coords(Vector2i(0, 0))
# 清除图块
erase_cell(Vector2i(0, 0))
extends TileMapLayer
func _input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed:
var global_pos := get_global_mouse_position()
var tile_pos := local_to_map(global_pos)
# 放置草地图块(假设 source_id=0, atlas=(0,0))
set_cell(tile_pos, 0, Vector2i(0, 0))
func flood_fill(start_pos: Vector2i, tile_source: int, atlas_coords: Vector2i) -> void:
var cells_to_fill: Array[Vector2i] = [start_pos]
var original_tile := get_cell_atlas_coords(start_pos)
while cells_to_fill.size() > 0:
var current := cells_to_fill.pop_back()
if get_cell_atlas_coords(current) != original_tile:
continue
set_cell(current, tile_source, atlas_coords)
# 添加相邻图块
for dir in [Vector2i.UP, Vector2i.DOWN, Vector2i.LEFT, Vector2i.RIGHT]:
cells_to_fill.append(current + dir)
extends TileMapLayer
func paint_terrain(start: Vector2i, end: Vector2i, terrain_set: int, terrain: int) -> void:
for x in range(start.x, end.x + 1):
for y in range(start.y, end.y + 1):
set_cells_terrain_connect(
[Vector2i(x, y)],
terrain_set,
terrain,
false # ignore_empty_terrains
)
# 场景结构:
# Node2D (关卡)
# ├─ TileMapLayer (地面)
# ├─ TileMapLayer (装饰)
# └─ TileMapLayer (碰撞)
# 每个图层可以有不同的:
# - 渲染顺序 (z_index)
# - 碰撞层/遮罩
# - 调制(颜色色调)
从代码中检查碰撞:
func _physics_process(delta: float) -> void:
# TileMapLayer 充当 StaticBody2D
# CharacterBody2D.move_and_slide() 会自动检测 tilemap 碰撞
pass
# 在 TileSet 物理层设置中:
# - 启用“单向碰撞”
# - 设置“单向碰撞边距”
# 角色可以从下方跳穿
func get_tile_damage(tile_pos: Vector2i) -> int:
var tile_data := get_cell_tile_data(tile_pos)
if tile_data:
return tile_data.get_custom_data("damage_per_second")
return 0
# 静态几何体:单个大的 TileMapLayer
# 动态图块:用于运行时更改的独立图层
# 将世界分割成多个 TileMapLayer 节点
# 根据玩家位置加载/卸载区块
const CHUNK_SIZE := 32
func load_chunk(chunk_coords: Vector2i) -> void:
var chunk_name := "Chunk_%d_%d" % [chunk_coords.x, chunk_coords.y]
var chunk := TileMapLayer.new()
chunk.name = chunk_name
chunk.tile_set = base_tileset
add_child(chunk)
# 为此区块加载图块...
与 NavigationAgent2D 一起使用:
# 从 TileMap 自动创建导航
# NavigationAgent2D.get_next_path_position() 立即生效
TileSet 图层:
- 地面 (地形=草地, 泥土, 石头)
- 墙壁 (碰撞 + 渲染)
- 装饰 (无碰撞, 覆盖层)
强制要求:在实现地形系统或运行时放置之前阅读。
使用 set_cells_terrain_connect 批处理和验证的运行时地形自动拼接。
基于区块的 TileMap 管理,具有批量更新功能 - 对于大型程序化世界至关重要。
# ✅ 良好 - 平滑的地形过渡
set_cells_terrain_connect(tile_positions, 0, 0)
# ❌ 糟糕 - 为有机形状手动分配图块
for pos in positions:
set_cell(pos, 0, Vector2i(0, 0))
# 背景图层
$Background.z_index = -10
# 地面图层
$Ground.z_index = 0
# 前景装饰
$Foreground.z_index = 10
func destroy_tile(world_pos: Vector2) -> void:
var tile_pos := local_to_map(world_pos)
var tile_data := get_cell_tile_data(tile_pos)
if tile_data and tile_data.get_custom_data("destructible"):
erase_cell(tile_pos)
# 生成粒子效果,掉落物品等。
@onready var highlight_layer: TileMapLayer = $HighlightLayer
func highlight_tile(tile_pos: Vector2i) -> void:
highlight_layer.clear()
highlight_layer.set_cell(tile_pos, 0, Vector2i(0, 0))
每周安装数
72
仓库
GitHub 星标数
59
首次出现
2026年2月10日
安全审计
安装于
codex71
opencode70
gemini-cli70
kimi-cli67
amp67
github-copilot67
TileMapLayer grids, TileSet atlases, terrain autotiling, and custom data define efficient 2D level systems.
Expert TileMap serialization and chunking manager for large worlds.
Advanced runtime terrain autotiling (Terrains v2) for roads, rivers, and organic paths.
Pattern for managing tile health and breakage based on Custom Data Layers.
Efficiently reading Custom Data (friction, hazards) to drive character/physics logic.
Optimized procedural generation using bulk tile placement logic for better performance.
Handling Y-sorting and Z-index layering for 2.5D effects and multi-floor buildings.
Expert TileMap physics: handling one-way collisions and collision layer management.
Runtime navigation updates for dynamic world-shifting and destructible environments.
Using TileMapPattern for efficiently "stamping" complex, multi-tile structural pieces.
Optimization: caching TileData metadata for high-frequency gameplay queries.
Managing the transition to the Godot 4.3 standard of multiple TileMapLayer nodes.
set_cell() = 1000 individual function calls = slow. Use set_cells_terrain_connect() for bulk OR cache changes, apply once.set_cell(pos, atlas_coords) without source_id? Wrong overload = crash OR silent failure. Use set_cell(pos, source_id, atlas_coords).set_cell(mouse_position) without local_to_map()? Wrong grid position. ALWAYS convert: local_to_map(global_pos).set_cells_terrain_connect() with terrain sets for autotiling.TileMapLayer node# Each tile can have:
# - Physics Layer: CollisionShape2D for each tile
# - Terrain: Auto-tiling rules
# - Custom Data: Arbitrary properties
Add collision to tiles:
extends TileMapLayer
func _ready() -> void:
# Set tile at grid coordinates (x, y)
set_cell(Vector2i(0, 0), 0, Vector2i(0, 0)) # source_id, atlas_coords
# Get tile at coordinates
var atlas_coords := get_cell_atlas_coords(Vector2i(0, 0))
# Clear tile
erase_cell(Vector2i(0, 0))
extends TileMapLayer
func _input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed:
var global_pos := get_global_mouse_position()
var tile_pos := local_to_map(global_pos)
# Place grass tile (assuming source_id=0, atlas=(0,0))
set_cell(tile_pos, 0, Vector2i(0, 0))
func flood_fill(start_pos: Vector2i, tile_source: int, atlas_coords: Vector2i) -> void:
var cells_to_fill: Array[Vector2i] = [start_pos]
var original_tile := get_cell_atlas_coords(start_pos)
while cells_to_fill.size() > 0:
var current := cells_to_fill.pop_back()
if get_cell_atlas_coords(current) != original_tile:
continue
set_cell(current, tile_source, atlas_coords)
# Add neighbors
for dir in [Vector2i.UP, Vector2i.DOWN, Vector2i.LEFT, Vector2i.RIGHT]:
cells_to_fill.append(current + dir)
extends TileMapLayer
func paint_terrain(start: Vector2i, end: Vector2i, terrain_set: int, terrain: int) -> void:
for x in range(start.x, end.x + 1):
for y in range(start.y, end.y + 1):
set_cells_terrain_connect(
[Vector2i(x, y)],
terrain_set,
terrain,
false # ignore_empty_terrains
)
# Scene structure:
# Node2D (Level)
# ├─ TileMapLayer (Ground)
# ├─ TileMapLayer (Decoration)
# └─ TileMapLayer (Collision)
# Each layer can have different:
# - Rendering order (z_index)
# - Collision layers/masks
# - Modulation (color tint)
Check collision from code:
func _physics_process(delta: float) -> void:
# TileMapLayer acts as StaticBody2D
# CharacterBody2D.move_and_slide() automatically detects tilemap collision
pass
# In TileSet physics layer settings:
# - Enable "One Way Collision"
# - Set "One Way Collision Margin"
# Character can jump through from below
func get_tile_damage(tile_pos: Vector2i) -> int:
var tile_data := get_cell_tile_data(tile_pos)
if tile_data:
return tile_data.get_custom_data("damage_per_second")
return 0
# Static geometry: Single large TileMapLayer
# Dynamic tiles: Separate layer for runtime changes
# Split world into multiple TileMapLayer nodes
# Load/unload chunks based on player position
const CHUNK_SIZE := 32
func load_chunk(chunk_coords: Vector2i) -> void:
var chunk_name := "Chunk_%d_%d" % [chunk_coords.x, chunk_coords.y]
var chunk := TileMapLayer.new()
chunk.name = chunk_name
chunk.tile_set = base_tileset
add_child(chunk)
# Load tiles for this chunk...
Use with NavigationAgent2D:
# Navigation automatically created from TileMap
# NavigationAgent2D.get_next_path_position() works immediately
TileSet Layers:
- Ground (terrain=grass, dirt, stone)
- Walls (collision + rendering)
- Decoration (no collision, overlay)
MANDATORY : Read before implementing terrain systems or runtime placement.
Runtime terrain autotiling with set_cells_terrain_connect batching and validation.
Chunk-based TileMap management with batched updates - essential for large procedural worlds.
# ✅ Good - smooth terrain transitions
set_cells_terrain_connect(tile_positions, 0, 0)
# ❌ Bad - manual tile assignment for organic shapes
for pos in positions:
set_cell(pos, 0, Vector2i(0, 0))
# Background layers
$Background.z_index = -10
# Ground layer
$Ground.z_index = 0
# Foreground decoration
$Foreground.z_index = 10
func destroy_tile(world_pos: Vector2) -> void:
var tile_pos := local_to_map(world_pos)
var tile_data := get_cell_tile_data(tile_pos)
if tile_data and tile_data.get_custom_data("destructible"):
erase_cell(tile_pos)
# Spawn particle effect, drop items, etc.
@onready var highlight_layer: TileMapLayer = $HighlightLayer
func highlight_tile(tile_pos: Vector2i) -> void:
highlight_layer.clear()
highlight_layer.set_cell(tile_pos, 0, Vector2i(0, 0))
Weekly Installs
72
Repository
GitHub Stars
59
First Seen
Feb 10, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex71
opencode70
gemini-cli70
kimi-cli67
amp67
github-copilot67
ESLint迁移到Oxlint完整指南:JavaScript/TypeScript项目性能优化工具
1,700 周安装
tile_cache[pos] = get_cell_tile_data(pos).