7.3 KiB
7.3 KiB
AI Native Visual RPG 开发经验沉淀
1. 项目特点判断
这个项目不是单纯的“像素 UI 项目”,而是 4 条链路同时耦合的项目:
- 叙事链路:AI 生成剧情文本与选项
- 状态链路:玩家、怪物、NPC、背包、好感、同伴、场景流转
- 演出链路:战斗计划、动画播放、投射物、特效、镜头位移
- 界面链路:选择世界、选择角色、冒险页、背包页、地图弹窗、编辑器页
经验:
- 做功能前先判断它主要影响哪几条链路。
- 如果一个需求同时影响“状态 + 演出 + UI”,不要只改一个点。
- 像“初始同伴”这种功能,本质上不是 UI 需求,而是“选角流程 + 初始 encounter + NPC 好感 + 招募状态”的组合需求。
2. 先做数据建模,再做 UI
这一类项目最容易犯的错误,是先加按钮、再补状态。
实践下来更稳的顺序是:
- 先把状态字段补齐
- 再补工具函数
- 再接交互入口
- 最后补展示层
已经验证有效的状态字段包括:
playerInventorynpcStatescompanionscurrentBattleNpcIdcurrentEncounterplayerActionModeactiveCombatEffects
经验:
- “能否交易 / 能否招募 / 送礼涨多少好感”都应该由状态和规则函数决定,不能写死在按钮文本里。
- 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 实际上有两种:
- 普通场景 NPC:可用通用 Medieval NPC 渲染
- 角色型 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. 冒险页布局要优先保证画面和选项完整可见
冒险页真正的优先级是:
- 上方画布要在一屏内正常显示
- 下方 3 个选项要在一屏内正常显示
- 剧情文本框剩余空间自适应
经验:
- 文本框不能无限长撑开
- 正确做法是:
- 文本框高度自适应剩余空间
- 文本超长时内部滚动
- 不能让
storyText把战斗画面和选项挤出首屏
9. 编辑器页和玩家页要明确隔离
当前项目里存在编辑器页面:
PresetEditorNpcVisualEditorStateFunctionEditor
玩家页和编辑器页的需求完全不同。
经验:
- 像字体切换、视觉统一这种全局改动,不要直接打到整个站点
- 应该只挂在非编辑器根容器上
- 比如
fusion-pixel-app这种类,只挂在正式游玩界面,不挂在编辑器根节点
10. 构建环境问题要项目内消化
实际踩到的构建问题:
- Node 16 环境下,Vite 构建会因为
crypto.getRandomValues缺失报错
沉淀出的解决方式:
- 不强依赖开发机立刻升级 Node
- 在项目内增加 Vite 启动包装脚本
- 统一让
dev / build / preview都走这层 shim
经验:
- 环境兼容问题如果能在项目内吸收,就尽量不要把负担转移给每个协作者
- 文档里要明确记录“为什么这样做”
11. 比较稳的开发顺序
后续继续扩展功能时,建议遵守这个顺序:
- 写状态字段
- 写规则工具函数
- 写流程 hook
- 接 UI
- 跑
npm run lint - 跑
npm run build - 再做视觉微调
不要反过来做:
- 先做 UI
- 再补状态
- 最后硬修流程
这种顺序在状态复杂的项目里会越改越乱。
12. 当前最值得继续坚持的原则
- 保持 AI 生成和本地规则分工清晰
- 保持角色型 NPC 与普通 NPC 的渲染分流
- 保持“怪物 / encounter / 战斗 NPC”统一坐标系
- 保持新增功能不破坏既有核心 UI 体验
- 保持编辑器页与玩家页隔离
- 每次大改后都用
lint + build双重验证
13. 后续建议
下一阶段最值得继续沉淀的方向:
- 把 NPC 交互逻辑继续从
useStoryGeneration中独立成更纯粹的useNpcInteractionFlow - 把角色型 NPC 的位置、缩放、贴地参数做成可配置规则,而不是继续散落在画布里微调
- 针对初始同伴流程补一份单独的状态图 / 时序图
- 对大 chunk 警告做代码分包
14. 一句话总结
这个项目真正的开发经验不是“怎么多写一个按钮”,而是:
- 在 AI 叙事、像素演出、战斗状态、NPC 规则、选择流程和编辑器体系同时存在的情况下,始终让每条链路各归其位。