ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

8、TileMap地图与视差滚动

2026/9/11 19:40:42 拓冰建站 浏览量
8、TileMap地图与视差滚动 第8章 TileMap 地图与视差滚动8.1 TileSet 资源创建创建步骤1. 添加 TileMapLayer 节点Godot 4.x 推荐使用 TileMapLayer 替代旧 TileMap 2. 在检查器中创建新的 TileSet 资源 3. 设置 Tile Size如 16x16 或 32x32 4. 添加 Tile Set Source图片源 5. 在 TileSet 编辑器中配置瓦片属性配置瓦片碰撞TileSet 编辑器 → 选择瓦片 → Physics Layer 1. 启用 Physics Layer 2. 为不同瓦片绘制碰撞形状 3. 可以创建多个 Physics Layer不同碰撞类型配置导航层TileSet 编辑器 → Navigation Layer 1. 启用 Navigation Layer 2. 为可行走区域绘制导航多边形 3. 用于 AI 寻路自定义数据层TileSet 编辑器 → Custom Data Layers 1. 添加自定义属性如 damage: int, sound: String 2. 为每个瓦片设置值 3. 在代码中读取 例如 - damage: int 0 0安全0伤害区域 - sound: String 脚步声类型 - is_slippery: bool false8.2 TileMapLayer4.x 新架构Godot 4.x 推荐使用TileMapLayer替代旧的 TileMap 多层方案。TileMapLayer 结构示意图旧方案TileMap 内部多层 TileMap Layer 0: 背景 Layer 1: 地形 Layer 2: 装饰 新方案TileMapLayer 节点推荐 Level (Node2D) ├── BackgroundLayer (TileMapLayer) ← z_index -10 │ └─ 天空、远景瓦片 ├── TerrainLayer (TileMapLayer) ← z_index 0 │ └─ 地面、墙壁带碰撞 ├── DecorationLayer (TileMapLayer) ← z_index 5 │ └─ 草、花、石头 └── ForegroundLayer (TileMapLayer) ← z_index 10 └─ 前景遮挡物 为什么用 TileMapLayer - 每层独立控制 z_index、碰撞、导航 - 可以单独启用/禁用某层 - 代码更清晰每层一个脚本代码操作 TileMapLayerextends TileMapLayer # 设置瓦片 func set_tile(pos: Vector2i, source_id: int, atlas_coords: Vector2i) - void: set_cell(pos, source_id, atlas_coords) # 获取瓦片 func get_tile_data(pos: Vector2i) - TileData: return get_cell_tile_data(pos) # 清除瓦片 func erase_tile(pos: Vector2i) - void: erase_cell(pos) # 获取自定义数据 func get_tile_damage(pos: Vector2i) - int: var data : get_cell_tile_data(pos) if data: return data.get_custom_data(damage) return 0 # 世界坐标 → 瓦片坐标 func world_to_tile(world_pos: Vector2) - Vector2i: return local_to_map(to_local(world_pos)) # 瓦片坐标 → 世界坐标 func tile_to_world(tile_pos: Vector2i) - Vector2: return to_global(map_to_local(tile_pos))8.3 地形自动拼接Terrain地形系统自动根据相邻瓦片选择正确的边缘瓦片。设置步骤1. TileSet 编辑器 → Terrains → 添加地形组 2. 添加地形如 草地、水面、沙地 3. 为每个瓦片设置地形标志 - 中心完全被同种地形包围 - 边缘与不同地形相邻 - 角落两条边与不同地形相邻 4. 编辑器自动根据标志选择正确瓦片代码绘制地形extends TileMapLayer # 使用地形绘制 func draw_terrain_line(from: Vector2i, to: Vector2i) - void: # 获取地形集 var terrain_set : 0 # 第一个地形组 var terrain_id : 0 # 第一个地形如草地 # 获取路径上的所有瓦片坐标 var cells : get_line_cells(from, to) # 设置地形 for cell in cells: set_cell(cell, 0, Vector2i.ZERO) # 先放置瓦片 # 然后让 TileMapLayer 自动更新地形连接 func get_line_cells(from: Vector2i, to: Vector2i) - Array[Vector2i]: var cells: Array[Vector2i] [] var dx : absi(to.x - from.x) var dy : absi(to.y - from.y) var sx : 1 if from.x to.x else -1 var sy : 1 if from.y to.y else -1 var err : dx - dy var current : from while true: cells.append(current) if current to: break var e2 : 2 * err if e2 -dy: err - dy current.x sx if e2 dx: err dx current.y sy return cells8.4 Animated Tiles动态瓦片# 在 TileSet 编辑器中 # 1. 选择一个瓦片 # 2. Animation → 添加帧 # 3. 设置帧持续时间 # 4. 设置播放模式循环/乒乓 # 代码中控制动画瓦片 func _ready() - void: # 获取瓦片的动画信息 var tile_data : get_cell_tile_data(Vector2i(5, 3)) if tile_data: var animation_frames : tile_data.get_animation_frames_count() var animation_speed : tile_data.get_animation_speed()8.5 程序化 TileMapextends TileMapLayer # 程序化生成地图 func generate_random_map(width: int, height: int) - void: for x in width: for y in height: var noise_val : noise.get_noise_2d(x, y) if noise_val -0.3: # 水面 set_cell(Vector2i(x, y), water_source, water_coords) elif noise_val 0.2: # 草地 set_cell(Vector2i(x, y), grass_source, grass_coords) else: # 山地 set_cell(Vector2i(x, y), mountain_source, mountain_coords) # 简单的房间生成 func generate_room(pos: Vector2i, size: Vector2i) - void: # 地板 for x in range(pos.x, pos.x size.x): for y in range(pos.y, pos.y size.y): set_cell(Vector2i(x, y), floor_source, floor_coords) # 墙壁 for x in range(pos.x - 1, pos.x size.x 1): set_cell(Vector2i(x, pos.y - 1), wall_source, wall_coords) # 上 set_cell(Vector2i(x, pos.y size.y), wall_source, wall_coords) # 下 for y in range(pos.y, pos.y size.y): set_cell(Vector2i(pos.x - 1, y), wall_source, wall_coords) # 左 set_cell(Vector2i(pos.x size.x, y), wall_source, wall_coords) # 右8.6 ParallaxBackground 视差滚动视差滚动让背景层以不同速度移动产生深度感。视差滚动原理示意图相机移动 →→→ motion_scale 0.0 (完全静止) ┌────────────────────────────────┐ │ 远山 / 天空 │ ← 几乎不动 └────────────────────────────────┘ motion_scale 0.3 (慢速) ┌────────────────────────────────┐ │ ️ ️ ️ 中距离山脉 │ ← 缓慢移动 └────────────────────────────────┘ motion_scale 0.7 (中速) ┌────────────────────────────────┐ │ 近距离树木 │ ← 较快移动 └────────────────────────────────┘ motion_scale 1.0 (与相机同速) ┌────────────────────────────────┐ │ 玩家游戏层 │ ← 正常移动 └────────────────────────────────┘ motion_scale 越小 离相机越远 移动越慢 产生深度感节点结构ParallaxBackground ├── ParallaxLayer (远景山/天空) motion_scale Vector2(0.1, 0.1) ├── ParallaxLayer (中景树木) motion_scale Vector2(0.5, 0.5) └── ParallaxLayer (近景草丛) motion_scale Vector2(0.8, 0.8)设置# ParallaxLayer 属性 motion_scale: Vector2 # 相对于相机的移动倍率 # Vector2(0, 0) 完全静止最远的背景 # Vector2(0.5, 0.5) 相机移动速度的一半 # Vector2(1, 1) 与相机同速前景 # Vector2(1.5, 1.5) 比相机更快超近景 motion_offset: Vector2 # 初始偏移 # 无限滚动 mirroring: Vector2 # 镜像重复 # 设置为精灵图片的大小实现无缝循环代码示例# ParallaxBackground 自动跟随相机 # 只需要设置好 motion_scale 即可 # 动态调整视差如进入室内时停止视差 extends ParallaxBackground func set_parallax_enabled(enabled: bool) - void: for layer in get_children(): if layer is ParallaxLayer: layer.motion_scale Vector2.ZERO if not enabled else layer.original_scale实操练习练习完整的关卡编辑器extends Node2D onready var terrain_layer: TileMapLayer $TerrainLayer onready var decoration_layer: TileMapLayer $DecorationLayer var current_brush: int 0 # 当前画笔 func _unhandled_input(event: InputEvent) - void: if event is InputEventMouse: var tile_pos : terrain_layer.world_to_tile(get_global_mouse_position()) if event is InputEventMouseButton: if event.button_index MOUSE_BUTTON_LEFT and event.pressed: paint_tile(tile_pos) elif event.button_index MOUSE_BUTTON_RIGHT and event.pressed: erase_tile(tile_pos) # 拖拽绘制 if event is InputEventMouseMotion and Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT): paint_tile(tile_pos) func paint_tile(pos: Vector2i) - void: match current_brush: 0: terrain_layer.set_cell(pos, 0, Vector2i.ZERO) # 草地 1: terrain_layer.set_cell(pos, 0, Vector2i(1, 0)) # 泥土 2: terrain_layer.set_cell(pos, 0, Vector2i(2, 0)) # 水面 func erase_tile(pos: Vector2i) - void: terrain_layer.erase_cell(pos)练习视差滚动背景# 创建多层视差背景 # 场景结构 # ParallaxBackground # Sky (ParallaxLayer) motion_scale (0, 0) # Mountains (ParallaxLayer) motion_scale (0.2, 0.1) # Trees (ParallaxLayer) motion_scale (0.6, 0.3) # Bushes (ParallaxLayer) motion_scale (0.9, 0.7) extends ParallaxBackground func _ready() - void: # 设置每层的镜像实现无限滚动 for layer in get_children(): if layer is ParallaxLayer: # 假设每个精灵宽度为 1920 layer.mirroring Vector2(1920, 0)