267 lines
9.8 KiB
Markdown
267 lines
9.8 KiB
Markdown
# 奇幻酒馆项目开发经验手册
|
||
|
||
日期:`2026-03-24`
|
||
|
||
## 1. 项目本质判断
|
||
|
||
这个项目不是单纯的前端页面项目,也不是单纯的大模型接入项目,而是 4 条链路同时存在的复合型项目:
|
||
|
||
1. 叙事链路:剧情文本、选项文本、角色对话、聊天上下文。
|
||
2. 状态链路:角色、怪物、NPC、场景、背包、装备、战斗状态、CD、蓝耗、死亡、掉落。
|
||
3. 演出链路:角色进场、近战贴身、受击、死亡、逃跑、镜头跟随、场景切换、前探预览。
|
||
4. 工具链路:NPC 形象编辑器、行为编辑器、预设数据、校验脚本、本地调试环境。
|
||
|
||
经验结论:
|
||
|
||
- 任何需求只要影响两条以上链路,就不能只改 UI。
|
||
- 先判断需求落在哪些链路,再决定改哪些文件。
|
||
- 这类项目最怕“看起来改好了”,但状态、动画、提示词和运行逻辑其实没对齐。
|
||
|
||
## 2. 架构拆分经验
|
||
|
||
已经验证更稳的结构是:
|
||
|
||
- `App.tsx` 保持尽量薄,只做外层挂载。
|
||
- `GameShell.tsx` 负责主流程壳层:开始页、世界选择、角色选择、游戏内主界面切换。
|
||
- 各类状态和流程尽量放进 hooks:
|
||
- `useGameFlow`
|
||
- `useCombatFlow`
|
||
- `useStoryGeneration`
|
||
- `useNpcInteractionFlow`
|
||
- `useInventoryFlow`
|
||
- `useEquipmentFlow`
|
||
- 各类独立 UI 面板拆成独立组件:
|
||
- `AdventurePanel`
|
||
- `CharacterPanel`
|
||
- `InventoryPanel`
|
||
- `MapModal`
|
||
- `AdventureEntityModal`
|
||
|
||
经验结论:
|
||
|
||
- 按职责拆,不按文件长度拆。
|
||
- 状态修改尽量集中在 hook 内,不要散落在多个按钮回调里。
|
||
- 预览系统、编辑器系统、正式游戏流程要尽量复用同一套业务逻辑,而不是各写一套。
|
||
|
||
## 3. AI 与本地规则的边界
|
||
|
||
目前最稳定的边界是:
|
||
|
||
- AI 负责生成:
|
||
- `storyText`
|
||
- `actionText`
|
||
- 对话文本
|
||
- 基于上下文的语气、叙事张力、选项措辞
|
||
- 本地规则负责决定:
|
||
- 哪些 function 当前可执行
|
||
- 技能是否在 CD
|
||
- 蓝量是否足够
|
||
- 伤害、回复、掉血、死亡、掉落
|
||
- 场景切换是否合法
|
||
- 背包、装备、属性、队伍变化
|
||
|
||
经验结论:
|
||
|
||
- 涉及数值、资源、状态迁移的部分,不要交给模型临场决定。
|
||
- 模型应被限制在“叙事表达层”,不要替代规则系统。
|
||
- 用户每次选择后只做一次模型推理,因此提示词必须一次性包含足够边界,不能再依赖后处理改写和过滤。
|
||
|
||
## 4. Function 驱动设计经验
|
||
|
||
当前更合理的设计方向是:
|
||
|
||
- 所有可选行为都落到 function。
|
||
- 每个 function 只有这些核心字段:
|
||
- `id`
|
||
- `text`
|
||
- `description`
|
||
- `category`
|
||
- `功能代码`
|
||
- 运行时先汇总当前场景的 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 开发服务器要统一入口
|
||
|
||
本项目本地正确启动方式应统一走:
|
||
|
||
```bash
|
||
node scripts/vite-cli.mjs --port=3000 --host=0.0.0.0
|
||
```
|
||
|
||
经验结论:
|
||
|
||
- 只要本地存在旧进程、旧脚本或错误端口映射,就很容易出现“代码改了但界面还是旧的”假象。
|
||
- 遇到这类问题,优先检查实际启动脚本、端口占用和返回模块内容,而不是先怀疑 UI 代码没生效。
|
||
|
||
## 11. 编辑器与正式运行时的关系
|
||
|
||
已经验证最稳的做法是:
|
||
|
||
- 编辑器预览直接复用正式运行时函数。
|
||
- 预览不自己模拟一套战斗和 function 执行逻辑。
|
||
- 运行时怎么结算,编辑器就怎么调用。
|
||
|
||
经验结论:
|
||
|
||
- 只要编辑器预览和正式逻辑分成两套,后面一定会越来越不一致。
|
||
- 预览系统的价值不是“看起来像”,而是“执行路径就是正式路径”。
|
||
|
||
## 12. 后续继续开发时建议遵循的顺序
|
||
|
||
推荐流程:
|
||
|
||
1. 先补数据结构和类型。
|
||
2. 再补 function 规则和过滤条件。
|
||
3. 再补 hook 流程与状态迁移。
|
||
4. 再补动画和演出。
|
||
5. 最后再做 UI 细修。
|
||
6. 每轮改动后至少做一次类型检查和本地启动验证。
|
||
|
||
不推荐的流程:
|
||
|
||
1. 先堆 UI。
|
||
2. 再临时塞状态。
|
||
3. 最后补运行逻辑。
|
||
|
||
这类项目里,后者几乎一定导致返工。
|
||
|
||
## 13. 一句话总结
|
||
|
||
这个项目最重要的经验不是“做了多少页面和功能”,而是:
|
||
|
||
**必须把 AI 文本生成、本地规则、动画演出、场景状态、编辑器工具这几套系统严格分层,再通过 function 和统一状态流把它们重新接起来。**
|
||
|
||
## 14. 相关文档
|
||
|
||
如需继续细看已有沉淀,可结合以下文档一起阅读:
|
||
|
||
- `docs/PROJECT_DEVELOPMENT_EXPERIENCE.md`
|
||
- `docs/MOBILE_UI_DEV_EXPERIENCE.md`
|
||
- `docs/CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md`
|
||
- `docs/AGENT_UI_CHANGELOG.md`
|