今日速览

  • Godot 4 里 TileMap 已废弃,取而代之的是 TileMapLayer:一个节点只管「一层」瓦片,多层就用多个 TileMapLayer 叠加。别再往老节点上画了。
  • 官方明确建议:把 TileSet 保存成外部 .tres 资源,多个关卡共用同一套 TileSet——否则每关都内嵌一份,改一处要改十处。
  • TileSet 必须先设 tile size,再拖图集(atlas),顺序反了自动切图会全错位;图集里全透明的区域不会生成瓦片。
  • 给瓦片加物理碰撞层,TileMapLayer 勾上 Collision Enabled 就自动生成碰撞;这是平台跳跃游戏最省事的「地面/墙」做法。
  • 官方提醒:TileMap 内置导航有性能局限,正式项目建议烘焙到 NavigationRegion2D 再用。

核心学习内容

一、TileMapLayer 的分层哲学

一个 TileMapLayer = 一张「半透明玻璃纸」,同一格上不同层可以各放一块瓦片。典型分层:Background(远景)→ Ground(地面/碰撞)→ Decoration(装饰)→ Foreground(遮住玩家的前景)。好处是各层独立开关、独立排序,还能分别控制碰撞与导航。

节点级关键属性(理解这几个就够用):

属性作用
tile_set引用的 TileSet 资源(推荐外部 .tres)
collision_enabled是否生成瓦片碰撞体
use_kinematic_bodies碰撞体是否实例化为运动学刚体
y_sort_originY 排序垂直偏移(角色能「走到树前/树后」)
rendering_quadrant_size合批象限边长,越大合批越狠但刷新越慢
navigation_enabled是否生成导航网格

注意:开了 Y Sort 后瓦片按 Y 分组,会打破默认的象限合批,这是「高瓦片量掉帧」的常见原因之一。此外坐标被限制在 ±32767(16 位有符号)内,超大世界要自己分块。

二、TileSet:图集、图块属性与地形自动拼接

  1. 新建 TileMapLayer → 在 Inspector 里新建 TileSet → 先设 tile size(如 64×64)。
  2. 打开底部 TileSet 面板,把 tilesheet 拖进去,选「自动创建瓦片」,全透明处自动跳过;不需要的瓦片用橡皮擦删掉。
  3. 图集属性重点:Margins(边缘留白)、Separation(瓦片间距,用于带描线的图集)、Texture Region Size(单块尺寸)、Use Texture Padding(默认开,加 1px 透明边,防过滤时的纹理渗色)。
  4. 给需要的瓦片加物理层:在 TileSet 面板的 Physics Layers 里画碰撞多边形。地形块画矩形,斜坡画斜边,一格一格的平台就能精确对齐角色碰撞。
  5. 地形自动拼接(Terrain Sets):把「草地/泥土/砖墙」等归入一个 terrain set,给每块瓦片设置 peering bits(四周该怎么拼),之后用 Terrain 画笔一笔拖过去,拐角、边框、内角全部自动接好——手动画边框的时代结束了。
  6. 场景瓦片(Scene tiles):用 TileSetScenesCollectionSource 把「商店、传送门、敌人出生点」做成瓦片。画上去即实例化该场景,关卡数据从此可以「一块瓦片 = 一个玩法元素」。

三、代码读写地图:让关卡可生成、可存档

关卡不该只在编辑器里手画。TileMapLayer 提供了一套干净的网格 API:

# 网格坐标 <-> 世界坐标
var cell := layer.local_to_map(layer.to_local(get_global_mouse_position()))
var world := layer.map_to_local(cell)

# 写入 / 擦除
layer.set_cell(cell, source_id, atlas_coords, alternative_tile)
layer.erase_cell(cell)

# 读取与遍历
layer.get_cell_source_id(cell)        # -1 表示空格
for c in layer.get_used_cells():      # 只遍历有瓦片的格子,省性能
    pass

用途很实在:程序化生成关卡(用噪声/尺寸算法算好 grid,再批量 set_cell)、关卡编辑器(玩家自建地图并序列化)、动态破坏地形(挖矿/炸墙就是 erase_cell)。注意所有 TileMap 更新会批处理到帧末,需要在同一帧内立刻读到结果时调 update_internals()。

🎯 DeepSeek 提示词

复制到 DeepSeek 直接可用。把 【】 替换成你自己的项目信息。

① 用代码程序化生成一整关 TileMapLayer

你是一位资深 Godot 4 游戏程序员,熟练使用 TileMapLayer 与 TileSet。

【背景】我在用 GDScript 做 2D 平台跳跃游戏,TileMapLayer 已配好一个外部 TileSet:
- source_id = 0 是地形图集,atlas_coords 里 (0,0)=地面、(1,0)=地面左缘、(2,0)=地面右缘、(3,0)=实心砖块
- source_id = 1 是场景瓦片集合,0=敌人生成点,1=金币

【任务】写一个 level_generator.gd(继承 Node2D),挂在关卡根节点上:
1. 用 FastNoiseLite 生成一条起伏的地面线(可导出参数:宽度、高度、噪声频率、种子)。
2. 地面线下方 2 格填实心砖块(source_id=0),表层瓦片按左右是否有邻居选 (1,0)/(2,0)/(0,0)。
3. 在地面之上按概率散布金币(source_id=1, alt=1),空中的平台边缘按概率放敌人(source_id=1, alt=0)。
4. 暴露一个 @export var seed_value 与一个 regenerate() 方法,重复调用前先 layer.clear()。
5. 起点左侧 3 格保证是平地(不放敌人),避免开局即死。

【输出格式】
- 完整可运行的 level_generator.gd(含中文注释)。
- 一段说明:如何在场景树里挂载、如何把生成的地图导出成固定关卡用于打磨。
【约束】
- 只用 Godot 4.x 内置 API,不引第三方插件。
- 遍历用 get_used_cells(),不要 for 整个矩形逐格查询。
- 所有随机走同一个 RandomNumberGenerator(用 seed_value 初始化),保证同种子同地图。

② 让 DeepSeek 把 TileMap 地形接上导航(敌人寻路)

你是 Godot 4 导航系统专家。我要让敌人通过 TileMapLayer 上画的地形做 2D 寻路。

【现状】
- Ground 层是 TileMapLayer,瓦片的物理层画了碰撞多边形。
- 敌人用 CharacterBody2D + NavigationAgent2D。

【任务】
1. 说明为什么官方不建议直接用 TileMapLayer 内置导航(Navigation Enabled),而推荐烘焙到 NavigationRegion2D,给出两种方案的取舍。
2. 给出「从 TileMapLayer 的可通行瓦片自动生成 NavigationPolygon」的分步操作(编辑器手动 + 脚本自动两条路)。
3. 写 enemy_nav.gd:敌人每帧朝 NavigationAgent2D.get_next_path_position() 移动,带最大速度与转向平滑;到达阈值后停下。
4. 处理「导航未同步」问题:说明 NavigationServer2D 的地图同步发生在物理帧,需要 await get_tree().physics_frame 一次再取路径。
5. 给出地图在运行时被修改(如炸开墙)后重新烘焙导航的正确调用顺序。

【输出格式】先分步操作,再给完整脚本,最后给「常见坑」清单。
【约束】只用内置 API;脚本要能被直接挂到敌人节点上运行。

③ 让 DeepSeek 帮你规划 TileSet 结构与瓦片清单(元提示词)

你是一位 2D 游戏美术管线顾问,同时很懂 Godot 4 TileSet / TileMapLayer。

【背景】我的游戏是【像素风地下城探险】,视口 320×180,单块瓦片 16×16,共 4 层(Background / Ground / Decoration / Foreground)。

【任务】输出一份可直接照着做的「TileSet 搭建方案」:
1. 瓦片清单表:列名 = 用途 / atlas 坐标建议 / 是否需要碰撞 / 属于哪个 terrain set / 备注。覆盖地面、墙、斜坡、平台、装饰、可交互物。
2. 给出 4 个图层各自的职责与 z 顺序建议,说明为什么这么分。
3. 给出 terrain set 的「peering bits」配置思路(草地/砖墙各一套),以及最少需要哪几张「角/边」专用瓦片才能让自动拼接不穿帮。
4. 列出 3 个最容易踩的坑(排序、纹理渗色、碰撞对齐),每个给一句规避方法。

【输出格式】Markdown 表格 + 简洁要点,不要长篇大论。
【约束】像素风、16×16 网格;所有建议必须能在 Godot 4.7 编辑器里直接落地。

学习心得

前几天的关卡设计方法论(灰盒三步法)解决「关卡长什么样」,今天这节课解决「用什么工具把它画出来、并且能被代码读写」。对「用 DeepSeek 做一款 Steam 游戏」来说,TileMapLayer 的意义在于:关卡从「美术活」变成了「数据活」——只要 TileSet 结构设计好,程序化生成、存档、玩家自建地图都能靠 DeepSeek 生成的几十行代码搞定,一个人也能做内容量。先把 Ground 层和碰撞跑通,用灰盒瓦片占位,别急着找漂亮素材。

明日关注

  • 按提示词③先定下 TileSet 的瓦片清单与 4 层结构,用免费占位瓦片(Kenney)搭一个 10 分钟能跑灰盒关。
  • 把提示词①的生成器跑起来,用同一个 seed 复现,再换 seed 看多样性。
  • 给 Ground 层配好物理层碰撞,让 CharacterBody2D 角色走上去不穿模、能贴墙。

本文由自动化学习流水线每日生成,坚持即学即记。