godot-tilemap-mastery
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTileMap Mastery
TileMap精通指南
TileMapLayer grids, TileSet atlases, terrain autotiling, and custom data define efficient 2D level systems.
TileMapLayer网格、TileSet图集、地形自动铺砖及自定义数据构成了高效的2D关卡系统。
Available Scripts
可用脚本
tilemap_data_manager.gd
tilemap_data_manager.gd
Expert TileMap serialization and chunking manager for large worlds.
适用于大型世界的专业TileMap序列化与分块管理器。
NEVER Do in TileMaps
TileMap使用禁忌
- NEVER use set_cell() in loops without batching — 1000 tiles × = 1000 individual function calls = slow. Use
set_cell()for bulk OR cache changes, apply once.set_cells_terrain_connect() - NEVER forget source_id parameter — without source_id? Wrong overload = crash OR silent failure. Use
set_cell(pos, atlas_coords).set_cell(pos, source_id, atlas_coords) - NEVER mix tile coordinates with world coordinates — without
set_cell(mouse_position)? Wrong grid position. ALWAYS convert:local_to_map().local_to_map(global_pos) - NEVER skip terrain set configuration — Manual tile assignment for organic shapes? 100+ tiles for grass patch. Use with terrain sets for autotiling.
set_cells_terrain_connect() - NEVER use TileMap for dynamic entities — Enemies/pickups as tiles? No signals, physics, scripts. Use Node2D/CharacterBody2D, reserve TileMap for static/destructible geometry.
- NEVER query get_cell_tile_data() in _physics_process — Every frame tile data lookup? Performance tank. Cache tile data in dictionary: .
tile_cache[pos] = get_cell_tile_data(pos)
- 绝对不要在循环中无批处理调用set_cell() — 1000个瓦片 × = 1000次独立函数调用 = 性能低下。批量操作请使用
set_cell(),或先缓存修改再一次性应用。set_cells_terrain_connect() - 绝对不要遗漏source_id参数 — 调用却不带source_id?错误的重载会导致崩溃或静默失败。请使用
set_cell(pos, atlas_coords)。set_cell(pos, source_id, atlas_coords) - 绝对不要混淆瓦片坐标与世界坐标 — 直接用却不调用
set_cell(mouse_position)?会得到错误的网格位置。务必转换坐标:local_to_map()。local_to_map(global_pos) - 绝对不要跳过地形集配置 — 手动为有机形状分配瓦片?一片草地要选100+个瓦片。请结合地形集使用实现自动铺砖。
set_cells_terrain_connect() - 绝对不要用TileMap承载动态实体 — 把敌人/道具设为瓦片?这样无法使用信号、物理系统和脚本。请使用Node2D/CharacterBody2D,TileMap仅用于静态或可破坏几何体。
- 绝对不要在_physics_process中调用get_cell_tile_data() — 每帧查询瓦片数据?会导致性能暴跌。请把瓦片数据缓存到字典中:。
tile_cache[pos] = get_cell_tile_data(pos)
Step 1: Create TileSet Resource
步骤1:创建TileSet资源
- Create a node
TileMapLayer - In Inspector: TileSet → New TileSet
- Click TileSet to open bottom TileSet editor
- 创建节点
TileMapLayer - 在检查器中:TileSet → 新建TileSet
- 点击TileSet打开底部的TileSet编辑器
Step 2: Add Tile Atlas
步骤2:添加瓦片图集
- In TileSet editor: + → Atlas
- Select your tile sheet texture
- Configure grid size (e.g., 16x16 pixels per tile)
- 在TileSet编辑器中:+ → 图集
- 选择你的瓦片集纹理
- 配置网格大小(例如:16x16像素/瓦片)
Step 3: Add Physics, Collision, Navigation
步骤3:添加物理、碰撞与导航
gdscript
undefinedgdscript
undefinedEach tile can have:
每个瓦片可包含:
- Physics Layer: CollisionShape2D for each tile
- 物理层:为每个瓦片添加CollisionShape2D
- Terrain: Auto-tiling rules
- 地形:自动铺砖规则
- Custom Data: Arbitrary properties
- 自定义数据:任意属性
**Add collision to tiles:**
1. Select tile in TileSet editor
2. Switch to "Physics" tab
3. Draw collision polygon
**为瓦片添加碰撞:**
1. 在TileSet编辑器中选择瓦片
2. 切换到「物理」标签页
3. 绘制碰撞多边形Using TileMapLayer
使用TileMapLayer
Basic Tilemap Setup
基础TileMap设置
gdscript
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))gdscript
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))Runtime Tile Placement
运行时瓦片放置
gdscript
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))gdscript
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))Flood Fill Pattern
洪水填充模式
gdscript
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)gdscript
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)Terrain Auto-Tiling
地形自动铺砖
Setup Terrain Set
设置地形集
- In TileSet editor: Terrains tab
- Add Terrain Set (e.g., "Ground")
- Add Terrain (e.g., "Grass", "Dirt")
- Assign tiles to terrain by painting them
- 在TileSet编辑器中:地形标签页
- 添加地形集(例如:「地面」)
- 添加地形(例如:「草地」、「泥土」)
- 通过绘制为瓦片分配地形
Use Terrain in Code
代码中使用地形
gdscript
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
)gdscript
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
)Multiple Layers Pattern
多层级模式
gdscript
undefinedgdscript
undefinedScene structure:
场景结构:
Node2D (Level)
Node2D (关卡)
├─ TileMapLayer (Ground)
├─ TileMapLayer (地面)
├─ TileMapLayer (Decoration)
├─ TileMapLayer (装饰)
└─ TileMapLayer (Collision)
└─ TileMapLayer (碰撞)
Each layer can have different:
每个层级可配置不同的:
- Rendering order (z_index)
- 渲染顺序(z_index)
- Collision layers/masks
- 碰撞层/掩码
- Modulation (color tint)
- 调制颜色(色调)
undefinedundefinedPhysics Integration
物理集成
Enable Physics Layer
启用物理层
- TileSet editor → Physics Layers
- Add physics layer
- Assign collision shapes to tiles
Check collision from code:
gdscript
func _physics_process(delta: float) -> void:
# TileMapLayer acts as StaticBody2D
# CharacterBody2D.move_and_slide() automatically detects tilemap collision
pass- TileSet编辑器 → 物理层
- 添加物理层
- 为瓦片分配碰撞形状
代码中检测碰撞:
gdscript
func _physics_process(delta: float) -> void:
# TileMapLayer可作为StaticBody2D使用
# CharacterBody2D.move_and_slide()会自动检测TileMap碰撞
passOne-Way Collision Tiles
单向碰撞瓦片
gdscript
undefinedgdscript
undefinedIn TileSet physics layer settings:
在TileSet物理层设置中:
- Enable "One Way Collision"
- 启用「单向碰撞」
- Set "One Way Collision Margin"
- 设置「单向碰撞边距」
Character can jump through from below
角色可从下方跳跃穿过
undefinedundefinedCustom Tile Data
自定义瓦片数据
Define Custom Data Layer
定义自定义数据层
- TileSet editor → Custom Data Layers
- Add property (e.g., "damage_per_second: int")
- Set value for specific tiles
- TileSet编辑器 → 自定义数据层
- 添加属性(例如:"damage_per_second: int")
- 为特定瓦片设置值
Read Custom Data
读取自定义数据
gdscript
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 0gdscript
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 0Performance Optimization
性能优化
Use TileMapLayer Groups
使用TileMapLayer分组
gdscript
undefinedgdscript
undefinedStatic geometry: Single large TileMapLayer
静态几何体:单个大型TileMapLayer
Dynamic tiles: Separate layer for runtime changes
动态瓦片:单独层级用于运行时修改
undefinedundefinedChunking for Large Worlds
大型世界分块
gdscript
undefinedgdscript
undefinedSplit world into multiple TileMapLayer nodes
将世界拆分为多个TileMapLayer节点
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...
undefinedconst 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)
# 加载该区块的瓦片...
undefinedNavigation Integration
导航集成
Setup Navigation Layer
设置导航层
- TileSet editor → Navigation Layers
- Add navigation layer
- Paint navigation polygons on tiles
Use with NavigationAgent2D:
gdscript
undefined- TileSet编辑器 → 导航层
- 添加导航层
- 为瓦片绘制导航多边形
结合NavigationAgent2D使用:
gdscript
undefinedNavigation automatically created from TileMap
导航系统会自动从TileMap生成导航数据
NavigationAgent2D.get_next_path_position() works immediately
NavigationAgent2D.get_next_path_position()可直接使用
undefinedundefinedBest Practices
最佳实践
1. Organize TileSet by Purpose
1. 按用途组织TileSet
TileSet Layers:
- Ground (terrain=grass, dirt, stone)
- Walls (collision + rendering)
- Decoration (no collision, overlay)TileSet层级:
- 地面(地形:草地、泥土、石头)
- 墙体(碰撞 + 渲染)
- 装饰(无碰撞,叠加层)Available Scripts
可用脚本
MANDATORY: Read before implementing terrain systems or runtime placement.
必须阅读:在实现地形系统或运行时放置功能前请先阅读。
terrain_autotile.gd
terrain_autotile.gd
Runtime terrain autotiling with batching and validation.
set_cells_terrain_connect基于批处理与验证的运行时地形自动铺砖脚本。
set_cells_terrain_connecttilemap_chunking.gd
tilemap_chunking.gd
Chunk-based TileMap management with batched updates - essential for large procedural worlds.
基于分块的TileMap管理脚本,支持批处理更新——是大型程序化世界的必备工具。
2. Use Terrain for Organic Shapes
2. 用地形实现有机形状
gdscript
undefinedgdscript
undefined✅ Good - smooth terrain transitions
✅ 推荐 - 平滑地形过渡
set_cells_terrain_connect(tile_positions, 0, 0)
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))
undefinedfor pos in positions:
set_cell(pos, 0, Vector2i(0, 0))
undefined3. Layer Z-Index Management
3. 层级Z轴顺序管理
gdscript
undefinedgdscript
undefinedBackground layers
背景层
$Background.z_index = -10
$Background.z_index = -10
Ground layer
地面层
$Ground.z_index = 0
$Ground.z_index = 0
Foreground decoration
前景装饰层
$Foreground.z_index = 10
undefined$Foreground.z_index = 10
undefinedCommon Patterns
常见模式
Destructible Tiles
可破坏瓦片
gdscript
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.gdscript
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)
# 生成粒子效果、掉落物品等Tile Highlighting
瓦片高亮
gdscript
@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))gdscript
@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))Reference
参考资料
Related
相关技能
- Master Skill: godot-master
- 大师技能:godot-master