)
借助 Codex 独立做游戏 · 开发复盘从“能跑”到“能重来”我用 Codex 做第一波战斗时修掉的四个问题正常流程能跑不等于这个功能已经可靠。上一篇结束时《Riftkeeper》只有一条从主界面进入战斗模块的入口。当时我给下一阶段定下的目标是一波怪物、一种武器、一次购买和放置、怪物沿路径移动、武器造成伤害最后产生胜利或失败并打开结算界面。从代码进度看这条最小战斗链路已经基本搭起来了。配置读取、战斗规则、ECS、动态战场、商店、放置合成、实时 HUD 和结算逻辑都有了对应实现。但这次真正值得记录的并不是增加了多少功能而是 Codex 写出的代码进入异常路径后连续暴露出的四类问题。● 纯规则覆盖了正常输入却没有真正关住异常边界● ECS 对象池复用后旧会话可能误操作新会话● 进入战斗由多段异步操作组成任何一步失败都需要回滚● ECS 已经发布状态时MVVM 界面可能还没有完成订阅。01. 规则写出来了但输入边界没有真正关住最先完成的是一些不依赖 Cocos 的纯战斗规则包括基地受伤、阶段切换、怪物路径、购买合成和胜负判断。这些代码看起来并不复杂但补测试时很快发现第一版主要覆盖了“数据完全正确”的情况。怪物沿格点移动时还要处理路径引用不存在的格点、重复格点、一帧跨过多个节点、路径末尾循环以及速度、时间或坐标出现负数、无穷大和 NaN。正常路径之外还要验证重复格点、缺失引用、循环和异常输入。阶段切换也有一个隐蔽问题。最初使用普通对象保存允许的阶段如果直接查询对象属性像 toString 这样的原型链字段可能被误认为合法阶段。解决方法先定义输入域和不变量最后增加了自有属性判断并用测试遍历所有允许和禁止的阶段组合。配置表进入战斗前先验证引用关系领域层再保证每次状态变化都是完整、原子的。不能只让 Codex 根据示例写算法还要让它回答合法范围是什么哪些引用必须存在哪些状态绝不能发生02. ECS 对象池复用让旧会话碰到了新会话为了减少重复创建战斗实体和组件会被对象池复用。第一局结束后同一个组件对象可能在下一局重新初始化。问题出在事件退订上。旧界面关闭时保存着一个退订函数如果新战斗已经复用了原来的组件并注册了新监听器旧退订函数就可能删除新会话的监听器。对象可以复用但旧生命周期不能继续操作新会话。解决方法把所有权写进运行句柄每个运行句柄都要确认自己是否仍然拥有当前组件。只有句柄还在运行、组件仍属于当前会话时退订操作才能修改监听器集合。同时停止和销毁被改成幂等操作重复停止不会重复释放表现层释放报错时实体仍会在 finally 中销毁组件重置时清空命令、事件、监听器和缓存状态初始化中途失败时已经取得的实体必须归还。旧会话订阅 → 旧会话销毁 → 组件被复用 → 新会话订阅 → 旧退订函数延迟执行单独测试一局时这个问题几乎看不出来只有按完整复用顺序验证才会暴露。03. 进入战斗不是一串异步调用而是一笔事务战斗入口包含很多步骤加载 bundle、读取配置、取得 Prefab、加载场景、挂载 BattleStage、创建表现层、创建 ECS、建立 Session最后替换主界面并打开 BattleUI。第一版主要考虑了成功顺序却没有完整描述每一步失败后应该撤销什么。如果 BattleStage 已经挂载但 ECS 创建失败或者 BattleUI 打开失败而 bundle、场景和节点都已经存在下一次点击开始战斗时就可能遇到重复节点、残留资源或“会话已经存在”。只回滚本次已经取得的资源保留安全起点并允许重新进入。解决方法为每次进入维护一份资源账本每次进入都记录本次真正取得的资源。任何步骤失败后按生命周期反向清理停止 Session → 解除订阅 → 关闭 UI → 释放表现层 → 移除战斗舞台 → 销毁 ECS → 释放 bundle清理过程中即使某一步再次报错也会继续释放其他已经取得的资源最后再把原始错误和清理错误一起报告。测试也不再只验证一次成功进入而是让流程在不同阶段故意失败确认只释放已取得资源、主界面仍然可用、同一个流程可以重试、重复退出不会清理两遍并发退出也不会误删后来创建的新会话。04. ECS 已经发布状态MVVM 界面却还没订阅战斗 ECS 可能先计算出第一份 HUD 状态BattleUI 随后才创建并注册监听器。如果把 HUD 当成普通事件处理晚注册的界面只能等待下一次状态变化无法得到当前完整状态。这不是字段绑定写错了而是把“状态”和“事件”混在了一起。事件只代表发生过什么不应该回放状态代表现在是什么新的订阅者必须立即得到一份当前快照。状态需要向晚订阅者回放当前快照事件只向前传递。解决方法由状态源缓存并回放最新快照修复后战斗状态源会缓存最新 HUD 快照。BattleUI 注册后立刻收到当前状态后续只有状态真正变化时才再次发布。如果首次状态回放时界面回调抛出异常刚登记的监听器也会立即移除不能留下一个调用方拿不到退订函数的失效监听器。这个约束后来被补进开发规则状态订阅必须支持首次快照事件订阅不回放历史会话结束和对象池复用时必须清理缓存与监听器。05. 这次我怎样要求 Codex 检查代码经过这轮返工我会把下面这段要求加入后续提示词不要只验证成功路径。请按资源所有权和状态生命周期检查流程列出每一步可能失败的位置以及失败后的回滚顺序。至少覆盖重复进入、并发退出、退出后重进、对象池复用、晚订阅、回调异常和初始化中途失败。完成后分别报告聚焦测试、全量测试和未执行的 Editor、设备及端到端验证。它不会让 Codex 少写代码但能让检查重点从“功能有没有出现”转向“状态是否真的可控”。06. 当前验证结果战斗相关测试 70 项70 项通过 · 0 项失败● 应用 TypeScript 检查通过● git diff --check 通过● 完整测试共 133 项通过 122 项失败 11 项。完整测试不能写成“全部通过”。现有失败主要集中在旧 Loading 美术文件缺失、历史绝对路径、一个过期的 runLoadingStartup 测试调用以及未纳入仓库的 .vscode/settings.json。这些失败目前没有指向本轮战斗代码但仍然是项目需要继续清理的技术债。更重要的是本次没有执行 Cocos Creator 预览、真机运行和完整端到端操作。这次最准确的结论第一波战斗已经形成了代码与自动化测试层面的纵向切片但还不能称为已经验证完成的可玩版本。AI 可以很快补出正常流程真正决定代码是否可靠的是人有没有继续追问异常状态、资源所有权和验证边界。下一步下一步我不会急着增加更多武器和波次而是先把这条链路放进 Cocos Creator 中实际运行主界面进入战斗 → 购买并放置武器 → 完成一波战斗 → 打开结算 → 退出并重新进入只有这条链路在真实运行环境中也能重复完成“第一波战斗”才算真正交付。如果你也在用 AI 做游戏欢迎留言说说你遇到过哪些“正常流程之外”的问题。