返回
玩法拆解 · 代码 · Demo
网格物理关卡

格子移动与碰撞:从规则到实现

用统一的“占用/可达”模型,处理推箱子、位移技能与阻挡。

0
格子移动与碰撞:从规则到实现

玩法拆解

数据模型
  • 占用表 occupancy[x,y] → entityId
  • 层级:地形/单位/投射物
移动判定
  • 先算意图,再做 resolve
  • 支持链式推动(可选)

关键代码

占用表(简化)
ts· 18

Demo

最小可试玩:网格移动 + 墙体阻挡(用于演示占用/阻挡模型)。

文章

文章以 Markdown/MDX 文本子集渲染(不支持自定义组件)。

格子移动与碰撞:从规则到实现

这篇文章聚焦一个很常见但很容易“越写越乱”的系统:网格移动 + 阻挡 + 推动 + 多层碰撞

目标是把所有判定收敛到一个统一模型里,让你后续加上:

  • 推箱子/推动链(A 推 B 推 C…)
  • 位移技能(冲刺/击退/牵引)
  • 多层碰撞(地形 / 单位 / 投射物 / 机关)
  • 关卡机制(门、开关、冰面、传送)

都不会变成“到处 if-else 补洞”。

---

1. 核心结论:用“占用表 + 解析器”统一规则

不要让每个系统各写各的判定(移动系统写一次、技能系统再写一次、怪物 AI 再写一次)。

推荐的中心结构:

  1. 占用表(Occupancy):网格上每个格子当前被谁占用(按层)。
  2. 移动意图(Intent):某个实体希望从 A → B,原因是什么(玩家输入/AI/技能/击退)。
  3. 解析器(Resolver):把意图在占用表上“结算”为一个可执行的结果(成功 / 被阻挡 / 推动链成功 / 失败回滚)。

> 你要做到的是:所有移动最终都走同一个 Resolver。

---

2. 数据模型:层(Layer)比“类型 if-else”更省命

一个格子可能同时存在:

  • 地形(墙、地板、陷阱、传送带)
  • 单位(玩家、敌人、箱子)
  • 临时物(投射物、范围提示、特效占位)

因此占用表建议按层存:

  • terrain[x,y] -> terrainId
  • unit[x,y] -> unitId
  • projectile[x,y] -> projectileId(可选,通常投射物更适合连续空间)

这样“能不能走进来”就是按层组合规则,而不是写成“如果是箱子且是冰面且是门…”。

---

3. 移动结算:两阶段(意图 → 结算)比“边走边改”安全

错误做法:玩家按键时直接改坐标,再检查碰撞,发现不行再改回来。 这会导致连锁推动、多人同时移动、以及回放/撤销时非常痛苦。

推荐做法:先构造意图,再统一结算:

  • 输入阶段:收集意图 MoveIntent(entityId, from, dir)
  • 结算阶段:在“快照占用表”上运行 resolver,得到 MoveResult
  • 应用阶段:把 MoveResult 变成一个“可回放”的事件序列(写入事件日志)

---

4. 推动链(Push Chain):递归/迭代都行,但要可回滚

推动链的本质:

  • 我想进入格子 B,但 B 被箱子占用
  • 如果箱子能被推到 C,则我可以进入 B
  • 如果 C 被另一个箱子占用,则继续尝试
  • 直到遇到空格(成功)或墙/不可推物(失败)

关键点:

  • 一次结算里,不要反复读写真实占用表;在临时结构里模拟。
  • 失败时能“整条链一起失败”,不出现半成功导致穿模。

一个实用的实现套路:

  • tryMove(entity, dir) 返回 { ok, moves[] }
  • moves[] 是按顺序的位移列表(例如先推最后一个箱子,再推前一个,最后移动玩家)

---

5. 位移技能(冲刺/击退/牵引):把它当“多步移动”

很多人写技能位移时会绕过网格移动系统,直接改坐标,然后再补一堆特殊判定。

更稳的方式:

  • 冲刺 = 连续 N 次 MoveIntent(每步都走 resolver)
  • 击退 = 由受击事件触发的 MoveIntent(方向由攻击者到受击者)
  • 牵引 = 由技能触发的 MoveIntent(方向相反)

好处:

  • 技能不会“穿墙”
  • 推动链自然生效
  • 你还能统一做“碰到墙停止”“碰到机关触发”等规则

---

6. 常见坑与验收清单(写完就用来对照)

6.1 常见坑

  • 顺序依赖:两个单位同时想进入同一格,先处理谁会影响结果。
  • 幽灵占用:实体移动后忘记更新占用表,导致后续判定认为格子仍被占。
  • 半成功:推动链中途失败但前面的箱子已经被移动了。
  • 只在“移动”判定墙:技能位移/击退没有走同一套判定,导致穿墙。

6.2 最小验收(建议写成自动测试)

  • [ ] 不能走进墙
  • [ ] 推动 1 个箱子成功/失败都正确
  • [ ] 推动链 2~3 个箱子成功/失败都正确
  • [ ] 冲刺/击退不会穿墙,且与箱子交互正确
  • [ ] 事件回放后状态一致(占用表与坐标一致)

---

7. 下一步扩展(建议优先顺序)

  1. 死局检测/可达性(关卡生成、提示系统会用到)
  2. 机关层(地形触发:开关、传送带、陷阱)
  3. 视野/碰撞形状(从网格扩展到“网格 + 子格/半格”)

你可能也喜欢