运行时回放:第 1、7、8 关,走的是测试里锁定的最短解(11 / 38 / 56 步)。1080p,32 秒,无声。
概览
这是一道技术策划方向的笔试题:做一个完整的推箱子,加一个关卡编辑器。我多问了一个问题——设计师做完一个关卡之后,怎么知道它有没有问题、可不可解、最短解是什么、能不能直接试玩?
最后交出去的不是“一个推箱子 + 一个画格子的窗口”,而是一条关卡内容生产链:
制作 → 校验 → 分析 → 解法预览 → 一键试玩 → 迭代
设计目标
推箱子的规则几十行就能写完。真正值得花力气的是数据改动之后的反馈速度。
关卡设计师的工作是反复改数据:加一堵墙、换一个箱子位置、改一个目标点。如果每次改完都要“打包 → 进游戏 → 手工走到终点”才知道结果,这个循环慢得没法用。所以工具的价值不在“能画格子”,而在每一次改动之后,能不能立刻得到可靠的反馈。
包含什么
- 确定性的
Board:整数网格上的规则核心,移动、推箱、Undo、Restart 都建立在棋盘快照上 - 关卡编辑器:工作副本、调色板、Undo / Redo、可点击定位的校验问题
- 校验器:阻断性错误与建议性警告两级
- 分析器:有预算上限的广度优先搜索,给出最短解与步数 / 推箱数
- 解法预览与一键试玩:在独立棋盘上回放最短解;用正式运行时加载器直接进 Play Mode
- 内容总览:对整个关卡目录批量校验与分析
- 多组压力板 / 门:一个贯穿全链路的新机制
- 分层的验证门禁:编译 → EditMode / PlayMode 测试 → 构建

关键决策
物理不参与规则
规则收敛到一个确定性的整数网格上,动画只是视图层的缓动,棋盘状态永远是即时权威。这样同一套规则可以被测试、分析器、解法预览反复复用,不会出现“编辑器里跑的是简化版,游戏里跑的是物理版”的对不上。运行时代码不依赖 UnityEditor 或 AssetDatabase,关卡通过显式序列化的 LevelCatalog 加载。
编辑的是工作副本,不是资源
New / Load 得到一份可编辑的工作副本,Save 之前资源不会被修改;Undo / Redo 作用在编辑历史上。存在阻断性错误时,试玩按钮直接禁用。

Error 和 Warning 的边界
- Error:箱子与目标数量不一致、占据者落在墙或门上、网格格式不对——拦截保存和试玩
- Warning:箱子停在非目标格且两个正交方向都是墙(静态死角死锁)——只提示,不拦截
死角死锁做成警告,是因为有些死锁是设计师故意要的。硬性不变量由 Error 守,可争论的问题留给设计师。

让工具承认“我不知道”
分析器遍历真实的 Board 状态,给出三种结论:可解、无解、未确定。预算耗尽不等于无解——对足够大的关卡,它会如实说“我不知道”,而不是把“算不动了”包装成“这关无解”。


门的状态是派生的,从不存储
压力板 + 门是为了验证这条链能不能承载新规则:它要求数据、棋盘、撤销、校验器、分析器、解法预览、编辑器、内容总览、运行时和测试一起扩展。门的开闭是玩家与箱子位置的纯函数,所以撤销、重开和分析器的已访问状态集都自动保持正确。


关卡
八个关卡分两组,前四关是基础,后四关引入压力板与门。
| 关卡 | 箱子 | 最短解 | 在教什么 |
|---|---|---|---|
| 01 推箱入位 | 2 | 11 步 / 5 推 | 箱子只能推不能拉 |
| 02 绕路借道 | 2 | 28 步 / 7 推 | 站在箱子错误的一侧时要绕到另一端 |
| 03 墙角陷阱 | 3 | 23 步 / 7 推 | 推到外墙就再也推不回来 |
| 04 先后有序 | 3 | 39 步 / 17 推 | 必须先填最深的目标 |
| 05 以箱压板 | 3 | 46 步 / 16 推 | 一个箱子压板撑门,送其他箱子过门 |
| 06 双板同压 | 3 | 40 步 / 14 推 | 同组两块压板要同时压住 |
| 07 分组换门 | 3 | 38 步 / 16 推 | A / B 两组门各自独立 |
| 08 层层开门 | 4 | 56 步 / 21 推 | 顺序、撑门时机与空间规划的综合 |
关卡不是摆出来就算数的:测试会回放每一关的最短解,要求分析器得到同样的最优值;还会把第 5 – 8 关的门拿掉、把第 7 – 8 关的 A / B 分组合并,验证拿掉之后关卡会变得不成立——也就是说这些机制在关卡里是必要的,不是装饰。
验证
- 三层门禁:
Fast只编译,Gate加上 EditMode 与 PlayMode 测试,Release再构建 Windows x64 - 当前结果:EditMode 197 / 197、PlayMode 4 / 4,构建通过
- 目录审计:8 个关卡全部有效,0 错误、0 警告、0 不可解、0 未确定
- PlayMode 测试确实接进了门禁:放进一个故意失败的测试,门禁变红;拿掉之后恢复。两次运行的输出都留了证据
如果重新做
- 运行时表现仍是轻量的程序化绘制(OnGUI),够用但不精致,会优先换掉
- 分析器有预算上限,大关卡会落到“未确定”——这是刻意的取舍,但它不是完整的求解器
- 内容规模有限,8 个关卡覆盖了从基础到压力板 / 门的弧线,谈不上丰富;继续投入的话我会先打磨关卡质量,而不是继续堆系统
完整的开发复盘见文章:Sokoban Studio:我把一个推箱子笔试做成了关卡生产工具链。