Files
Genarrative/docs/CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md
高物 c49c64896a
Some checks failed
CI / verify (push) Has been cancelled
初始仓库迁移
2026-04-04 23:57:06 +08:00

7.1 KiB
Raw Blame History

Codex 实战经验沉淀

日期:2026-03-24

1. 先判断需求属于哪条链路

这个项目几乎所有需求都不是单点 UI 改动,通常会同时影响几条链路:

  • 叙事链路AI 剧情、提示词、选项文案
  • 状态链路:GameState、NPC 状态、背包、队伍、委托
  • 演出链路:屏幕外进场、战斗播放、实体站位、动画与特效
  • 工具链路编辑器、校验脚本、存档兼容、smoke

经验:

  • 每次动手前先判断“这次主要影响哪几条链路”,不要把需求误判成单纯的 UI 需求。
  • 只改表现、不改状态,最终一定会返工。
  • 只改状态、不补校验,后面也一定会返工。

2. 先补状态模型,再补交互

这类项目里,最稳定的顺序永远是:

  1. 先补类型与状态字段
  2. 再补规则函数
  3. 再补 hook 流程
  4. 最后接 UI

已经反复验证有效的例子:

  • quests
  • playerEquipment
  • playerCurrency
  • roster
  • companions
  • currentNpcBattleMode
  • sparReturnEncounter

经验:

  • 如果一个功能需要“长期留存”,就不要只存在于局部组件 state。
  • 先建模后接按钮,比先堆按钮后补状态稳定得多。

3. AI 负责叙事,本地负责规则

项目里最稳的边界是:

  • AI 负责:
    • storyText
    • 对话文本
    • 选项的自然语言表达
  • 本地规则负责:
    • 交易是否合法
    • 招募是否成立
    • 装备是否生效
    • 委托进度是否完成
    • 掉落、货币、好感、队伍编成

经验:

  • 只要涉及数值、资源、状态迁移,就尽量不要让大模型即兴决定。
  • 给模型的提示词应该描述“局面”和“边界”,不要让它代替规则系统。

4. 固定选项提示不要写得太死

一个重要经验是:

  • 模型需要知道每个 functionId 的核心含义
  • 但不需要看到“当前默认文案 / 补充信息 / 实际行为”这种过于细碎、强绑定的结构

更好的方式是:

  • 保留 functionId、数量、顺序
  • 只提供“这个 function 的核心语义参考”
  • 让模型重写更自然、连续的 actionText

经验:

  • 提示词越像表单,模型越容易产出僵硬选项。
  • 提示词越像“约束 + 语义边界”,剧情越自然。

5. 面前实体的提示词必须和主角对称

如果主角有:

  • 描述
  • 性格
  • 状态
  • 属性

那么“当前面前实体”也应该尽量有同样结构。

经验:

  • 只给一句“某 NPC 在这里活动”太粗,会削弱模型对局面的把握。
  • 面前实体和主角描述层级一致后,模型更容易写出有来回感、对称感的叙事。
  • 对生命/灵力这类状态,离散分档文本比裸数字更利于模型理解。

6. 屏幕外进场一定要抽成统一工具

这类项目很容易在多个地方各写一套“从屏幕外进入”的逻辑,结果出现:

  • 同一实体重复进场
  • 先进入屏幕,又被拉回屏幕外再进一次
  • 多怪时只动第一个,其他直接跳终点

这次稳定下来的方法是:

  • 抽统一的过渡工具
    • buildEncounterEntryState
    • buildEncounterTransitionState
    • interpolateEncounterTransitionState
  • 所有进场逻辑都复用这一套
  • 区分两种场景:
    • 真正从屏幕外冲入
    • 已经在屏内预览,只是收敛到正式位置

经验:

  • “屏幕外进入”本质上不是动画问题,而是状态过渡问题。
  • 一旦同时存在 preview / call_out / resolve / replay就必须统一插值逻辑。

7. 多实体系统里,不要默认“只处理第一个”

这个坑非常常见:

  • 场景配置里有多个怪
  • 运行时逻辑却只用 monsterIds[0]
  • 或者动画只插值 sceneMonsters[0]

经验:

  • 只要数据结构已经允许数组,就尽量按“整组”处理。
  • 即便最后 UI 只重点展示一个,也不要在底层逻辑里偷偷退化成单体。

8. 招募系统不要只做“当前队伍”

如果只有 companions 而没有 roster,后面一定会遇到这些问题:

  • 队伍满员时必须强制覆盖旧同伴
  • 已招募角色很难转成待命
  • 营地/编队功能没法闭环

这次稳定下来的模型是:

  • companions:当前上阵
  • roster:已招募但待命

经验:

  • 只要项目里有招募,迟早就要有 roster。
  • roster 不只是 UI 功能,而是状态层能力。

9. 装备系统不要只做展示

装备真正形成闭环,至少要同时做到:

  • 背包里可装备 / 卸下
  • 装备改变真实属性
  • 战斗行为读取装备加成
  • 存档兼容旧存档

经验:

  • “装备栏能显示”不算完成。
  • 只有真正影响 maxHp / maxMana / damage / incomingDamage,它才是玩法系统。

10. 交易系统最好统一成货币价值模型

一开始按“品质交换”虽然简单,但很快会遇到问题:

  • 不同类别物品难比较
  • 直接购买不好接
  • 后面加入售卖、任务赏金、宝藏货币时会冲突

更稳定的做法是:

  • 所有物品都有统一价值
  • NPC 商品有购买价
  • 玩家物品有回收价
  • 货币作为通用交换媒介

经验:

  • 一旦出现货币,就尽量让交易系统全面切成“价值模型”。
  • 不要同时长期维护“品质交换”和“货币购买”两套完全不同的判定逻辑。

11. 编辑器要先做保存前校验

编辑器进入“可持续生产内容”阶段后,最优先的不是视觉,而是:

  • 保存前校验
  • 非法引用提示
  • 数值边界检查

经验:

  • 编辑器最怕的不是“不够漂亮”,而是“保存成功但运行时报错”。
  • 只要内容开始增多,校验脚本和保存前校验就必须尽早接入。

12. 每次大改后都要补 smoke

对这个项目来说,lint + build 不够。

至少要补 smoke 的场景包括:

  • 委托接取 -> 推进 -> 交付
  • 多怪遭遇
  • 装备加成
  • 队伍编成
  • 交易价值与直接购买
  • 进场插值

经验:

  • 只靠人工点点看,很容易漏掉状态分支。
  • smoke 不一定要重,但要覆盖关键闭环。

13. 兼容旧存档要同步做

每次给 GameState 新增字段时,都要同步考虑:

  • 默认值
  • 存档读取兼容
  • 旧字段缺失时如何补全

经验:

  • 旧存档兼容不是“最后再说”的工作。
  • 新字段一旦进 GameState,就应当同一轮把持久化兼容补上。

14. 不要在坏文件上无限缝补

这次实际踩到过一个很明显的坑:

  • 某些文件本身已经混入大量乱码或结构损坏
  • 在原地做小 patch 会越来越难维护

更稳的做法是:

  • 保留接口
  • 整文件重写成干净版本
  • 再接回现有调用

经验:

  • 当一个文件已经进入“局部 patch 很难保证正确”的状态时,重写往往比继续缝补更省时间。

15. 后续继续迭代时的建议顺序

如果继续推进这个项目,建议优先顺序:

  1. 先清理中文乱码高频文件
  2. 再继续精英/Boss 层
  3. 再补营地关系事件
  4. 再做编辑器差异预览 / 导入导出

16. 一句话总结

这个项目最重要的经验不是“多写了多少功能”,而是:

凡是会同时影响叙事、状态、演出和工具链的需求,都要先统一边界,再落实现。