文章目录
什么是瓦片地图?
瓦片地图(TileMap) 是 2D 游戏中构建世界的核心技术之一。它将游戏场景划分为统一大小的格子(Tile),每个格子填充一张来自图集(TileSet)的小图片,从而高效地渲染大范围地图。Godot 4 对 TileMap 系统进行了彻底重构,引入了更强大的 TileSet 编辑器和多图层支持,是目前最完善的 2D 瓦片系统之一。
核心概念
TileMap 节点
TileMap 是 Godot 4 中管理瓦片的主节点。它承载以下职责:
- 引用一个
TileSet资源,定义所有可用瓦片的外观与属性 - 管理一个或多个 图层(Layer),用于分离前景、背景、碰撞层等
- 提供坐标转换、瓦片读写等 API
Godot 4.3+: 官方已将
TileMap拆分为独立的TileMapLayer节点,鼓励每层使用独立节点,获得更好的灵活性和性能。
TileSet 资源
TileSet 是瓦片地图的"数据库",定义了每块瓦片的:
- 纹理来源:单张图片或图集(Atlas)
- 碰撞形状:多边形、矩形等
- 物理材质:摩擦力、弹力等
- 导航多边形:用于 AI 寻路
- 自定义数据:附加游戏逻辑属性
- 动画帧:支持瓦片动画
创建第一个 TileMap
1. 添加节点
在场景树中添加 TileMap 节点,Inspector 面板会提示创建或绑定一个 TileSet。
场景树:
└── Node2D (Root)
└── TileMap
2. 配置 TileSet
点击 Inspector 中的 TileSet → 新建 TileSet,然后在底部的 TileSet 编辑器 中:
- 点击左上角 "+" 添加图集来源(Atlas Source)
- 导入你的 Sprite Sheet 图片
- 设置单个瓦片的像素尺寸(如 16×16、32×32)
- Godot 会自动切割图集并生成所有瓦片
3. 绘制地图
切换到 TileMap 标签,选择一个瓦片,在场景视图中点击或拖拽即可绘制。
图层系统(Layers)
TileMap 支持多个图层,每个图层可独立设置:
| 属性 | 说明 |
|---|---|
Name |
图层名称,便于脚本引用 |
Enabled |
是否渲染此图层 |
Modulate |
颜色调制(用于半透明效果) |
Y Sort Enabled |
启用 Y 轴排序(用于 RPG 俯视角) |
Z Index |
渲染层级 |
Navigation Enabled |
是否启用导航 |
典型图层配置(RPG 场景):
图层 0: 地面 (Ground) ← 草地、泥土、水面
图层 1: 装饰 (Decoration) ← 花草、石块(无碰撞)
图层 2: 阻挡 (Obstacles) ← 墙壁、树木(有碰撞)
图层 3: 顶层 (Overhead) ← 屋顶、树冠(玩家走过时半透明)
物理碰撞配置
在 TileSet 中添加碰撞
- 在 TileSet 编辑器中选择一个瓦片
- 点击 "物理层" → 确保已添加物理层(Physics Layer)
- 在瓦片的 碰撞 选项卡中绘制碰撞多边形
TileSet 结构:
├── 物理层 0 (Physics Layer 0)
│ ├── 碰撞形状 (多边形/矩形)
│ └── 物理材质 (可选)
└── 瓦片 ID → 绑定物理层
物理层与碰撞掩码
TileMap 的每个物理层都有独立的 层(Layer) 和 掩码(Mask):
# 设置 TileMap 的碰撞层
tile_map.set_physics_layer_collision_layer(0, 1) # 第0物理层在第1碰撞层
tile_map.set_physics_layer_collision_mask(0, 1) # 与第1碰撞层交互
自动图块(Auto Tiles / Terrain)
自动图块(地形系统)是 Godot 4 最强大的特性之一,能根据相邻瓦片自动选择正确的边缘和角落图片,无需手动拼接。
配置地形集
- 在 TileSet 编辑器中,选中你的图集来源
- 点击 "地形" 选项卡
- 创建 地形集(Terrain Set),选择匹配模式:
匹配角落和边缘:3×3 像素感知,最精细仅匹配角落:2×2 像素感知仅匹配边缘:简单四向匹配
- 为每块瓦片分配地形 ID
脚本中使用地形
# 使用地形自动填充一块区域
var cells = []
for x in range(0, 10):
for y in range(0, 5):
cells.append(Vector2i(x, y))
# 参数:图层索引, 地形集ID, 地形ID, 单元格列表
tile_map.set_cells_terrain_connect(0, 0, 0, cells)
导航网格(Navigation)
TileMap 可以直接生成 NavigationRegion2D 数据,为 AI 寻路提供网格。
配置步骤
- 在 TileSet 编辑器中添加 导航层(Navigation Layer)
- 为可行走的瓦片绘制 导航多边形
- 在场景中的 TileMap Inspector 里启用导航图层
- 添加
NavigationAgent2D到 NPC 节点
# NPC 寻路示例
extends CharacterBody2D
@onready var nav_agent = $NavigationAgent2D
func _ready():
nav_agent.target_position = player.global_position
func _physics_process(delta):
var next_pos = nav_agent.get_next_path_position()
var direction = (next_pos - global_position).normalized()
velocity = direction * SPEED
move_and_slide()
脚本控制 TileMap
基础读写操作
extends Node2D
@onready var tile_map: TileMap = $TileMap
func _ready():
# 获取指定位置的瓦片数据
var tile_data = tile_map.get_cell_tile_data(0, Vector2i(3, 4))
if tile_data:
print("找到瓦片:", tile_data)
# 放置一个瓦片
# 参数:图层, 地图坐标, 图集来源ID, 图集坐标
tile_map.set_cell(0, Vector2i(5, 5), 0, Vector2i(1, 0))
# 清除一个瓦片
tile_map.erase_cell(0, Vector2i(5, 5))
坐标转换
# 世界坐标 → 地图格子坐标
var world_pos = Vector2(320, 240)
var map_pos = tile_map.local_to_map(tile_map.to_local(world_pos))
print("地图坐标:", map_pos)
# 地图格子坐标 → 世界坐标(格子中心)
var grid_pos = Vector2i(5, 3)
var center = tile_map.map_to_local(grid_pos)
print("世界坐标(局部):", center)
获取区域内所有瓦片
# 获取某图层中所有已使用的格子坐标
var used_cells = tile_map.get_used_cells(0)
for cell in used_cells:
print("瓦片位置:", cell)
# 获取指定区域内的格子
var rect = Rect2i(0, 0, 10, 10)
var cells_in_rect = tile_map.get_used_cells_by_id(0, 0) # 来源0的所有瓦片
自定义数据读取
可以在 TileSet 中为瓦片添加自定义数据层(如 damage、is_passable),并在脚本中读取:
# 在 TileSet 中添加自定义数据层 "damage" (类型: float)
func get_tile_damage(map_pos: Vector2i) -> float:
var tile_data = tile_map.get_cell_tile_data(0, map_pos)
if tile_data:
return tile_data.get_custom_data("damage")
return 0.0
瓦片动画
TileSet 支持帧动画,让水面、火焰、传送门等元素动起来。
配置动画瓦片
- 在图集来源中选择起始帧瓦片
- 在 动画 选项卡中设置帧数和帧间距
- 设置 FPS(动画速率)
- 可设置 随机偏移(
Animation Offset),让同类瓦片不同步,更自然
# 运行时修改动画速率
var tile_data = tile_map.get_cell_tile_data(0, Vector2i(2, 3))
if tile_data:
tile_data.set_custom_data("animation_speed", 2.0)
性能优化建议
| 技巧 | 说明 |
|---|---|
| 合并图集 | 将所有瓦片放入单张大图,减少 Draw Call |
| 使用 Y Sort | 仅在需要 RPG 深度排序时开启,有性能开销 |
| 分割大地图 | 超大地图考虑分块加载(Chunk Loading) |
| 禁用不可见图层 | 将屏幕外的图层设为 enabled = false |
| 避免频繁 set_cell | 批量操作后一次性刷新,而非逐格调用 |
| 使用 TileMapLayer | Godot 4.3+ 推荐用独立节点替代多图层 TileMap |
程序化生成地图
结合脚本可以实现 Roguelike 风格的随机地图生成:
extends TileMap
const FLOOR_SOURCE = 0
const FLOOR_ATLAS = Vector2i(0, 0)
const WALL_ATLAS = Vector2i(1, 0)
func generate_dungeon(width: int, height: int):
clear() # 清空所有图层
for x in range(width):
for y in range(height):
var pos = Vector2i(x, y)
# 边界设为墙
if x == 0 or y == 0 or x == width-1 or y == height-1:
set_cell(0, pos, FLOOR_SOURCE, WALL_ATLAS)
else:
# 随机生成墙壁(密度 30%)
if randf() < 0.3:
set_cell(0, pos, FLOOR_SOURCE, WALL_ATLAS)
else:
set_cell(0, pos, FLOOR_SOURCE, FLOOR_ATLAS)
小结
Godot 的 TileMap 系统功能完备,从简单的平台跳跃游戏到复杂的 RPG 大地图均能胜任。掌握以下核心流程即可快速上手:
- 配置 TileSet → 导入图集、切割瓦片
- 设置物理层 → 为需要碰撞的瓦片绘制形状
- 启用地形系统 → 实现自动拼接边缘
- 多图层管理 → 分离地面、装饰、障碍
- 脚本控制 → 动态读写瓦片、响应游戏事件
随着 Godot 版本迭代,TileMapLayer 将成为主流,建议新项目直接采用该节点以获得最佳兼容性。
评论