244 lines
7.3 KiB
Markdown
244 lines
7.3 KiB
Markdown
# AI Native Visual RPG 开发经验沉淀
|
||
|
||
## 1. 项目特点判断
|
||
|
||
这个项目不是单纯的“像素 UI 项目”,而是 4 条链路同时耦合的项目:
|
||
|
||
1. 叙事链路:AI 生成剧情文本与选项
|
||
2. 状态链路:玩家、怪物、NPC、背包、好感、同伴、场景流转
|
||
3. 演出链路:战斗计划、动画播放、投射物、特效、镜头位移
|
||
4. 界面链路:选择世界、选择角色、冒险页、背包页、地图弹窗、编辑器页
|
||
|
||
经验:
|
||
|
||
- 做功能前先判断它主要影响哪几条链路。
|
||
- 如果一个需求同时影响“状态 + 演出 + UI”,不要只改一个点。
|
||
- 像“初始同伴”这种功能,本质上不是 UI 需求,而是“选角流程 + 初始 encounter + NPC 好感 + 招募状态”的组合需求。
|
||
|
||
## 2. 先做数据建模,再做 UI
|
||
|
||
这一类项目最容易犯的错误,是先加按钮、再补状态。
|
||
|
||
实践下来更稳的顺序是:
|
||
|
||
1. 先把状态字段补齐
|
||
2. 再补工具函数
|
||
3. 再接交互入口
|
||
4. 最后补展示层
|
||
|
||
已经验证有效的状态字段包括:
|
||
|
||
- `playerInventory`
|
||
- `npcStates`
|
||
- `companions`
|
||
- `currentBattleNpcId`
|
||
- `currentEncounter`
|
||
- `playerActionMode`
|
||
- `activeCombatEffects`
|
||
|
||
经验:
|
||
|
||
- “能否交易 / 能否招募 / 送礼涨多少好感”都应该由状态和规则函数决定,不能写死在按钮文本里。
|
||
- NPC 交互尽量走本地规则,不要依赖 AI 即时决定关键数值。
|
||
|
||
## 3. 复杂页面一定要拆流程层
|
||
|
||
`App.tsx` 一旦同时承载:
|
||
|
||
- 游戏主状态
|
||
- 剧情生成
|
||
- 战斗播放
|
||
- NPC 交互
|
||
- 地图
|
||
- 选角
|
||
|
||
就会迅速失控。
|
||
|
||
当前更合理的分层思路是:
|
||
|
||
- `useGameFlow`
|
||
负责基础游戏状态、世界选择、角色选择、初始进入逻辑
|
||
- `useCombatFlow`
|
||
负责战斗计划与播放
|
||
- `useStoryGeneration`
|
||
负责剧情生成、NPC 本地交互分流、选项池管理
|
||
- `useNpcInteractionFlow`
|
||
负责同伴/NPC 展示态
|
||
- `GameShell`
|
||
负责主容器与选择流程
|
||
- `AdventurePanel`
|
||
负责冒险页文本和选项
|
||
- `NpcModals`
|
||
负责交易 / 送礼 / 放生招募等弹窗
|
||
|
||
经验:
|
||
|
||
- 流程层优先按“职责”拆,不按“文件长度”拆。
|
||
- 状态修改逻辑尽量集中到 hook 内,不要散落在多个组件按钮回调里。
|
||
|
||
## 4. AI 只适合生成叙事,不适合决定关键规则
|
||
|
||
实践中最稳定的策略是:
|
||
|
||
- AI 负责:
|
||
- `storyText`
|
||
- 非 NPC 关键规则的普通探索选项文案
|
||
- 本地规则负责:
|
||
- NPC 交互选项
|
||
- 交易合法性
|
||
- 礼物好感值
|
||
- 招募阈值
|
||
- 战斗掉落
|
||
- 帮助奖励
|
||
|
||
经验:
|
||
|
||
- 凡是会影响数值平衡、背包物品、好感、队伍成员的部分,都不要交给 AI 即时决定。
|
||
- AI 生成内容要能被本地规则兜底,否则体验会不稳定。
|
||
|
||
## 5. NPC 系统要“角色型 NPC”和“普通 NPC”分开处理
|
||
|
||
项目里 NPC 实际上有两种:
|
||
|
||
1. 普通场景 NPC:可用通用 Medieval NPC 渲染
|
||
2. 角色型 NPC:应该复用玩家角色对应的立绘和动画
|
||
|
||
经验:
|
||
|
||
- 只看 `encounter.kind === 'npc'` 不够,还要看 `encounter.characterId`。
|
||
- 有 `characterId` 的 NPC,应该优先走 `CharacterAnimator`。
|
||
- 否则就会出现:
|
||
- 选了某个同伴,但开场看到的是另一套通用 NPC 外观
|
||
- 战斗里角色型 NPC 看起来像普通路人
|
||
|
||
## 6. 位置与朝向必须统一到一套坐标规则
|
||
|
||
这是这类项目里最容易反复返工的点。
|
||
|
||
实践中踩过的坑:
|
||
|
||
- `sceneMonsters` 用一套坐标逻辑
|
||
- `currentEncounter` 用另一套坐标逻辑
|
||
- 结果开场 NPC 和遇怪站位不一致
|
||
- 角色型 NPC 立绘比怪物更容易出现“脚没落地”“太小”“翻转方向错”
|
||
|
||
最终经验:
|
||
|
||
- 对面实体的横向定位必须统一到“怪物那套 world-space 逻辑”
|
||
- 也就是:
|
||
- 位置统一用怪物侧的 anchor
|
||
- 相机平移时统一跟随同一套计算
|
||
- 角色型 NPC 的垂直位置不能偷懒固定
|
||
- 应该结合角色自身 `groundOffsetY`
|
||
- 朝向规则要统一使用 `getFacingTowardPlayer`
|
||
|
||
一句话总结:
|
||
|
||
- 角色型 NPC 不应该单独发明一套站位系统,而应该尽量复用怪物对位系统。
|
||
|
||
## 7. “新增流程”不要破坏原有选择 UI
|
||
|
||
这次初始同伴功能就是一个典型经验:
|
||
|
||
- 用户原本对“选择扮演角色”的视觉和交互已经形成预期
|
||
- 如果为了加“初始同伴选择”直接把角色选择页改成另一种样式,会造成明显割裂
|
||
|
||
经验:
|
||
|
||
- 新流程优先插在旧流程后面,而不是重写旧流程
|
||
- “确认角色 -> 选择初始同伴 -> 进入冒险”比“把原选角页改成全新样式”风险小很多
|
||
- 如果必须改 UI,也要尽量保留旧页面的视觉结构和交互节奏
|
||
|
||
## 8. 冒险页布局要优先保证画面和选项完整可见
|
||
|
||
冒险页真正的优先级是:
|
||
|
||
1. 上方画布要在一屏内正常显示
|
||
2. 下方 3 个选项要在一屏内正常显示
|
||
3. 剧情文本框剩余空间自适应
|
||
|
||
经验:
|
||
|
||
- 文本框不能无限长撑开
|
||
- 正确做法是:
|
||
- 文本框高度自适应剩余空间
|
||
- 文本超长时内部滚动
|
||
- 不能让 `storyText` 把战斗画面和选项挤出首屏
|
||
|
||
## 9. 编辑器页和玩家页要明确隔离
|
||
|
||
当前项目里存在编辑器页面:
|
||
|
||
- `PresetEditor`
|
||
- `NpcVisualEditor`
|
||
- `StateFunctionEditor`
|
||
|
||
玩家页和编辑器页的需求完全不同。
|
||
|
||
经验:
|
||
|
||
- 像字体切换、视觉统一这种全局改动,不要直接打到整个站点
|
||
- 应该只挂在非编辑器根容器上
|
||
- 比如 `fusion-pixel-app` 这种类,只挂在正式游玩界面,不挂在编辑器根节点
|
||
|
||
## 10. 构建环境问题要项目内消化
|
||
|
||
实际踩到的构建问题:
|
||
|
||
- Node 16 环境下,Vite 构建会因为 `crypto.getRandomValues` 缺失报错
|
||
|
||
沉淀出的解决方式:
|
||
|
||
- 不强依赖开发机立刻升级 Node
|
||
- 在项目内增加 Vite 启动包装脚本
|
||
- 统一让 `dev / build / preview` 都走这层 shim
|
||
|
||
经验:
|
||
|
||
- 环境兼容问题如果能在项目内吸收,就尽量不要把负担转移给每个协作者
|
||
- 文档里要明确记录“为什么这样做”
|
||
|
||
## 11. 比较稳的开发顺序
|
||
|
||
后续继续扩展功能时,建议遵守这个顺序:
|
||
|
||
1. 写状态字段
|
||
2. 写规则工具函数
|
||
3. 写流程 hook
|
||
4. 接 UI
|
||
5. 跑 `npm run lint`
|
||
6. 跑 `npm run build`
|
||
7. 再做视觉微调
|
||
|
||
不要反过来做:
|
||
|
||
- 先做 UI
|
||
- 再补状态
|
||
- 最后硬修流程
|
||
|
||
这种顺序在状态复杂的项目里会越改越乱。
|
||
|
||
## 12. 当前最值得继续坚持的原则
|
||
|
||
- 保持 AI 生成和本地规则分工清晰
|
||
- 保持角色型 NPC 与普通 NPC 的渲染分流
|
||
- 保持“怪物 / encounter / 战斗 NPC”统一坐标系
|
||
- 保持新增功能不破坏既有核心 UI 体验
|
||
- 保持编辑器页与玩家页隔离
|
||
- 每次大改后都用 `lint + build` 双重验证
|
||
|
||
## 13. 后续建议
|
||
|
||
下一阶段最值得继续沉淀的方向:
|
||
|
||
1. 把 NPC 交互逻辑继续从 `useStoryGeneration` 中独立成更纯粹的 `useNpcInteractionFlow`
|
||
2. 把角色型 NPC 的位置、缩放、贴地参数做成可配置规则,而不是继续散落在画布里微调
|
||
3. 针对初始同伴流程补一份单独的状态图 / 时序图
|
||
4. 对大 chunk 警告做代码分包
|
||
|
||
## 14. 一句话总结
|
||
|
||
这个项目真正的开发经验不是“怎么多写一个按钮”,而是:
|
||
|
||
- 在 AI 叙事、像素演出、战斗状态、NPC 规则、选择流程和编辑器体系同时存在的情况下,始终让每条链路各归其位。
|