9.9 KiB
9.9 KiB
奇幻酒馆项目开发经验手册
日期:2026-03-24
1. 项目本质判断
这个项目不是单纯的前端页面项目,也不是单纯的大模型接入项目,而是 4 条链路同时存在的复合型项目:
- 叙事链路:剧情文本、选项文本、角色对话、聊天上下文。
- 状态链路:角色、怪物、NPC、场景、背包、装备、战斗状态、CD、蓝耗、死亡、掉落。
- 演出链路:角色进场、近战贴身、受击、死亡、逃跑、镜头跟随、场景切换、前探预览。
- 工具链路:NPC 形象编辑器、行为编辑器、预设数据、校验脚本、本地调试环境。
经验结论:
- 任何需求只要影响两条以上链路,就不能只改 UI。
- 先判断需求落在哪些链路,再决定改哪些文件。
- 这类项目最怕“看起来改好了”,但状态、动画、提示词和运行逻辑其实没对齐。
2. 架构拆分经验
已经验证更稳的结构是:
App.tsx保持尽量薄,只做外层挂载。GameShell.tsx负责主流程壳层:开始页、世界选择、角色选择、游戏内主界面切换。- 各类状态和流程尽量放进 hooks:
useGameFlowuseCombatFlowuseStoryGenerationuseNpcInteractionFlowuseInventoryFlowuseEquipmentFlow
- 各类独立 UI 面板拆成独立组件:
AdventurePanelCharacterPanelInventoryPanelMapModalAdventureEntityModal
经验结论:
- 按职责拆,不按文件长度拆。
- 状态修改尽量集中在 hook 内,不要散落在多个按钮回调里。
- 预览系统、编辑器系统、正式游戏流程要尽量复用同一套业务逻辑,而不是各写一套。
3. AI 与本地规则的边界
目前最稳定的边界是:
- AI 负责生成:
storyTextactionText- 对话文本
- 基于上下文的语气、叙事张力、选项措辞
- 本地规则负责决定:
- 哪些 function 当前可执行
- 技能是否在 CD
- 蓝量是否足够
- 伤害、回复、掉血、死亡、掉落
- 场景切换是否合法
- 背包、装备、属性、队伍变化
经验结论:
- 涉及数值、资源、状态迁移的部分,不要交给模型临场决定。
- 模型应被限制在“叙事表达层”,不要替代规则系统。
- 用户每次选择后只做一次模型推理,因此提示词必须一次性包含足够边界,不能再依赖后处理改写和过滤。
4. Function 驱动设计经验
当前更合理的设计方向是:
- 所有可选行为都落到 function。
- 每个 function 只有这些核心字段:
idtextdescriptioncategory功能代码
- 运行时先汇总当前场景的 function,再结合角色、状态、敌人、场景实体、资源状态做合法性过滤。
- 模型只在“当前合法 function 集合”内生成选项文本和剧情文本。
经验结论:
- 选项不是自由散文,而是 function 的叙事包装。
- function 必须和角色、状态、场景、实体绑定,不能做成完全漂浮的公共动作池。
- “每次选择只能并且必须命中一个 function” 是保持状态稳定的关键。
5. 战斗与动画的经验
战斗部分已经沉淀出的几个重要规则:
5.1 结算时机
- 用户点击选项后,后台状态应立即推进到“动画完成后的结果状态”,并把这个新状态放入后续推理上下文。
- 但扣血、死亡表现、消失等视觉结果要在动画播完后再体现在画面上。
这样做的好处:
- 模型推理可以立即开始,不被动画阻塞。
- 画面依然保留正确的演出节奏。
- 状态、上下文、下一轮推理不会落后于动画。
5.2 近战位移
- 近战动画不能按固定像素移动。
- 必须按左右锚点、舞台宽度和目标位置计算真实接近距离。
- 宽屏下如果只“往前走一点点”,基本就是位移基准用了屏幕百分比或固定偏移,而不是双方真实锚点差值。
5.3 死亡与退出战斗
- 怪物血量归零时先播死亡动画。
- 死亡动画完成后怪物再消失。
- 若敌方死亡,战斗状态应退出,切回空闲状态,并重新切换可用 function 集合。
5.4 逃跑与压迫感
- 逃跑镜头要跟着玩家,不是跟怪物。
- 玩家向前跑,怪物被越甩越远,才能形成“甩开追兵”的感觉。
- 相反,如果镜头锚在怪物侧,会让玩家像没动一样。
6. 遭遇、场景与地图经验
这部分已经验证有效的设计原则:
- 场景和背景图一一绑定,不切场景就不换背景。
- 场景切换必须由选项命中的 function 驱动,而不是每回合自动变化。
- 每个场景预设自己的怪物、NPC、宝藏池。
- 玩家“继续向前探路”时,不是立刻随机弹结果,而是先预生成前方实体,再通过移动和镜头演出把它带到正式交互位。
经验结论:
- “探索”也应该是一种可演出的 function,而不只是一次文字刷新。
- 同一时刻只应遇到一个主实体,避免一回合同时出现多只怪物造成状态混乱。
- 地图系统适合做成场景连接图,由具体 function 触发前往某个场景。
7. 移动端优先的 UI 经验
已经验证有效的 UI 方向:
- 先保证移动端一屏成立,再兼容网页宽屏。
- 开始页、世界选择、角色选择都要像游戏流程,而不是产品介绍页。
- 世界选择适合纵向焦点滑动。
- 角色选择适合横向翻卡和中心焦点展示。
- 冒险页中:
- 上方是画面演出
- 中间是自适应剧情文本
- 底部是固定的选项与功能入口
经验结论:
- 剧情区域不能写死高度,应填满画面下方和底部操作条上方之间的剩余空间。
- 队伍、背包更适合作为弹出面板,不应该切走主流程。
- 地图弹窗、队伍面板、背包详情都必须按手机窄屏重新组织,不要沿用桌面弹窗思路。
8. 选择页与游戏内界面经验
这轮迭代里比较明确的 UI 结论有:
- 开始页只保留核心按钮,视觉简洁更像正式游戏。
- 世界选择页要突出当前聚焦卡,其他卡随滑动连续改变透明度和大小。
- 角色选择页中:
- 中间卡片不能模糊
- 左右卡片要做正确方向的倾斜
- 中间角色可播放
run动画 - 角色名称显示在动画下方
- 属性和背景信息要紧凑,不能压缩掉上方卡片滑动空间
- 游戏内按钮应尽量图标化,把更多空间留给剧情和选项。
9. NPC 形象编辑器经验
NPC 编辑器这部分已经沉淀出一些通用原则:
- 这套 Medieval Fantasy Characters 素材不是传统逐帧全身序列帧,发型、脸型、胡子、武器等部件不能按“每帧都变化”的思路处理。
- 主手武器、副手武器、手、身体、头部、头饰需要明确图层关系。
- 主手武器必须真正握在手里,不能只靠大概位置“看起来差不多”。
- 因为素材高度重叠,编辑器里必须支持:
- 底部组件模块点击选择
- 键盘上下左右微调
- 拖拽微调
- 回滚按钮
经验结论:
- 视觉编辑器如果没有“可控选择 + 微调 + 回滚”,用户会很难调重叠素材。
- 选项命名不能直接暴露英文源文件名,最好转成更贴近视觉理解的中文名称。
- 编辑器产出的相对位置数据必须能直接落回项目运行时,不然就只是一个孤立工具。
10. 大模型接入与本地调试经验
这部分踩坑非常集中,结论也比较清晰:
10.1 前端不能直连目标模型接口
- 浏览器直连时会遇到 CORS。
- 即使接口本身可用,浏览器环境也可能被跨域限制。
- 更稳的方案是在开发服务器侧做代理,再由前端请求本地
/api/llm/...。
10.2 需要日志,但日志要聚焦
已经证明有价值的日志包括:
- 单次推理耗时
- 原始提示词文本
- 原始返回中的解析后文本
- 失败时的模型名、状态码和错误正文
10.3 开发服务器要统一入口
本项目本地正确启动方式应统一走:
node scripts/vite-cli.mjs --port=3000 --host=0.0.0.0
经验结论:
- 只要本地存在旧进程、旧脚本或错误端口映射,就很容易出现“代码改了但界面还是旧的”假象。
- 遇到这类问题,优先检查实际启动脚本、端口占用和返回模块内容,而不是先怀疑 UI 代码没生效。
11. 编辑器与正式运行时的关系
已经验证最稳的做法是:
- 编辑器预览直接复用正式运行时函数。
- 预览不自己模拟一套战斗和 function 执行逻辑。
- 运行时怎么结算,编辑器就怎么调用。
经验结论:
- 只要编辑器预览和正式逻辑分成两套,后面一定会越来越不一致。
- 预览系统的价值不是“看起来像”,而是“执行路径就是正式路径”。
12. 后续继续开发时建议遵循的顺序
推荐流程:
- 先补数据结构和类型。
- 再补 function 规则和过滤条件。
- 再补 hook 流程与状态迁移。
- 再补动画和演出。
- 最后再做 UI 细修。
- 每轮改动后至少做一次类型检查和本地启动验证。
不推荐的流程:
- 先堆 UI。
- 再临时塞状态。
- 最后补运行逻辑。
这类项目里,后者几乎一定导致返工。
13. 一句话总结
这个项目最重要的经验不是“做了多少页面和功能”,而是:
必须把 AI 文本生成、本地规则、动画演出、场景状态、编辑器工具这几套系统严格分层,再通过 function 和统一状态流把它们重新接起来。
14. 相关文档
如需继续细看已有沉淀,可结合以下文档一起阅读:
docs/experience/PROJECT_DEVELOPMENT_EXPERIENCE.mddocs/experience/MOBILE_UI_DEV_EXPERIENCE.mddocs/experience/CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.mddocs/experience/AGENT_UI_CHANGELOG.md