Rework story engine flow and reorganize project docs
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
255
docs/experience/ADVENTURE_RUNTIME_DEV_EXPERIENCE.md
Normal file
255
docs/experience/ADVENTURE_RUNTIME_DEV_EXPERIENCE.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# 冒险运行时开发经验沉淀
|
||||
|
||||
日期:2026-03-24
|
||||
|
||||
## 1. 这轮工作主要覆盖了什么
|
||||
|
||||
这轮迭代不是单点 UI 修改,而是同时改了 4 条链路:
|
||||
|
||||
1. 战斗演绎链路:近战突进、远程施法、投射物/特效、受击结算时机。
|
||||
2. 探索链路:向前探索、呼喊、NPC 离队、切换场景时的新 encounter 生成与入场动画。
|
||||
3. NPC function 链路:聊天、招募、观察征兆、交易、离队、上下文注入边界。
|
||||
4. 面板链路:队伍页、角色详情、背包页、移动端空间分配、入口 icon 语义。
|
||||
|
||||
这类项目最重要的判断是:
|
||||
很多需求表面看是“改个界面”或“改句文案”,实际同时影响状态机、动画时序、AI 提示词、实体生成规则和移动端布局。
|
||||
|
||||
## 2. 这轮最值得沉淀的结论
|
||||
|
||||
### 2.1 function 的职责边界必须先定死
|
||||
|
||||
后面事实证明,只有少数 function 应该负责生成新 encounter:
|
||||
|
||||
- `idle_explore_forward`
|
||||
- `idle_call_out`
|
||||
- `npc_leave`
|
||||
- 进入新场景
|
||||
|
||||
其他 function 如果也偷偷新增 NPC、怪物、宝箱,后面一定会出现这些问题:
|
||||
|
||||
- 剧情上下文越来越乱
|
||||
- 场景上实体数量失控
|
||||
- 玩家以为“聊天/招募/观察”也会强行推进世界
|
||||
- AI 生成内容和本地规则互相打架
|
||||
|
||||
经验:
|
||||
先定义“谁能创造世界实体”,再写文案和动画。
|
||||
|
||||
### 2.2 动画完成点必须和数值结算点绑定
|
||||
|
||||
这轮一个关键修正是:
|
||||
攻击特效播放完后,受击目标才扣血。
|
||||
|
||||
如果不这样做,玩家看到的就是:
|
||||
|
||||
- 特效还没打到,血条先掉了
|
||||
- 投射物还在飞,目标已经结算
|
||||
- dash 还没到位,攻击已经命中
|
||||
|
||||
经验:
|
||||
战斗系统里不能只写“播放动画”,必须写清楚:
|
||||
|
||||
1. 起手阶段是什么
|
||||
2. 位移阶段是什么
|
||||
3. 命中阶段是什么
|
||||
4. 哪个阶段结束后才改数值
|
||||
|
||||
### 2.3 视觉素材选择要按“语义 + 小尺寸可读性”来做
|
||||
|
||||
这轮做过两类视觉判断:
|
||||
|
||||
- 战斗特效素材该怎么挂到角色/技能上
|
||||
- 冒险页入口 icon 应该换成什么
|
||||
|
||||
经验不是“素材越花越好”,而是:
|
||||
|
||||
- 先看素材本身表达的动作语义
|
||||
- 再看缩小到按钮尺寸后是否还能一眼看懂
|
||||
- 最后才考虑风格统一
|
||||
|
||||
例如:
|
||||
|
||||
- 队伍入口用“盔甲”不如用“盾牌”更像角色/编队
|
||||
- 背包入口用真正的包袋图,比木板式 HUD 图更直观
|
||||
- 远程施法不移动时,特效就必须承担“动作已经发生”的视觉职责
|
||||
|
||||
### 2.4 角色型 NPC 和普通 encounter 不能混着处理
|
||||
|
||||
这轮踩过的坑说明:
|
||||
|
||||
- 可扮演但未入队的 NPC
|
||||
- 已入队同伴
|
||||
- 普通场景 NPC
|
||||
|
||||
这三者虽然都可能显示为 NPC,但数据完整度、立绘来源、详情页能力并不一样。
|
||||
|
||||
经验:
|
||||
|
||||
- 角色型 NPC 要按角色数据链路渲染
|
||||
- 普通 NPC 要按 encounter/NPC state 渲染
|
||||
- 详情弹窗必须对缺失字段做空值保护
|
||||
|
||||
否则就会出现点击小人直接报 `map` 相关错误这类问题。
|
||||
|
||||
### 2.5 角色和同伴的朝向/位移必须彼此独立
|
||||
|
||||
`idle_observe_signs` 的修正说明了一件事:
|
||||
如果主角和同伴在 transform、朝向、随机停顿上仍然存在隐含父子级关系,最后视觉表现一定不自然。
|
||||
|
||||
经验:
|
||||
|
||||
- 主角随机转向和同伴随机转向要分别计算
|
||||
- 位置、朝向、停留时长都要独立采样
|
||||
- 不要让父容器顺手把子角色的朝向也带过去
|
||||
|
||||
这条经验同样适用于:
|
||||
|
||||
- 招募入队时的新同伴 dash
|
||||
- 多角色待机观察
|
||||
- 场景内多实体同步演绎
|
||||
|
||||
### 2.6 大模型负责“推理与叙述”,本地规则负责“世界变更”
|
||||
|
||||
这轮对 `npc_chat`、`npc_recruit`、`idle_observe_signs` 的调整,本质上都指向同一个原则:
|
||||
|
||||
- 大模型可以生成观察结果、聊天内容、氛围描述
|
||||
- 大模型不应该偷偷新增实体、替玩家做决定、绕开本地规则结算
|
||||
|
||||
经验:
|
||||
|
||||
1. 聊天生成要明确禁止提及其他 function 行为。
|
||||
2. 招募对话可以引导到成功入队,但最终入队仍应由本地流程触发。
|
||||
3. `idle_observe_signs` 可以走大模型推理,但写入剧情上下文的内容要可控。
|
||||
4. `npc_recruit` 这种流程不要顺手给下次推理塞一个“新 NPC”。
|
||||
|
||||
一句话总结:
|
||||
AI 可以解释世界,但不能私自改世界。
|
||||
|
||||
### 2.7 移动端面板要优先保信息密度,不要保装饰
|
||||
|
||||
这轮背包和队伍页的调整很能说明问题:
|
||||
|
||||
- 队伍页只保留成员列表
|
||||
- 成员详情放到弹窗
|
||||
- 背包页去掉多余标题、提示文案、厚重背景框
|
||||
- 装备信息移到角色详情,不和背包抢空间
|
||||
|
||||
经验:
|
||||
|
||||
- 主面板只放“高频扫读信息”
|
||||
- 低频详情放二级弹窗
|
||||
- 任何重复信息都要尽量去重
|
||||
|
||||
在小屏上,空间不是拿来“显得完整”的,而是拿来“保证可操作”的。
|
||||
|
||||
## 3. 这轮最典型的踩坑记录
|
||||
|
||||
### 3.1 encounter 生成距离只改一处是不够的
|
||||
|
||||
一开始只是把某个函数里的怪物生成位置往后挪,但后来发现:
|
||||
|
||||
- 其他会生成 encounter 的 function 仍然太近
|
||||
- 新场景进入时也可能直接出现在屏幕里
|
||||
|
||||
经验:
|
||||
“从屏幕外进场、要走 4 秒距离”必须是统一约束,不是某个函数里的特判。
|
||||
|
||||
### 3.2 详情文案改源头不一定等于改到了最终显示层
|
||||
|
||||
这轮“选项小字太长”的问题最后证明:
|
||||
真正该改的是渲染层显示的 `detailText`,而不是只改某个上游数据源。
|
||||
|
||||
经验:
|
||||
用户说“没有生效”时,要优先检查最终渲染层,而不是只检查中间数据。
|
||||
|
||||
### 3.3 新同伴入队时,尺寸问题本质是缩放基准不统一
|
||||
|
||||
招募流程里位置正确但大小不对,说明问题不在路径,而在:
|
||||
|
||||
- 新同伴使用的缩放基准
|
||||
- 主角扮演角色使用的缩放基准
|
||||
|
||||
不一致。
|
||||
|
||||
经验:
|
||||
只要角色加入到主队镜头体系里,尺寸基准必须复用主角/同伴那套规则,不能临时另开一套。
|
||||
|
||||
### 3.4 背包和角色详情职责不清,会持续挤压移动端布局
|
||||
|
||||
这轮背包页一度同时承担:
|
||||
|
||||
- 物品网格
|
||||
- 装备总览
|
||||
- 装备卸下
|
||||
- 详情查看
|
||||
|
||||
最后结果就是移动端空间不够、信息层级混乱。
|
||||
|
||||
经验:
|
||||
|
||||
- 背包负责“物品”
|
||||
- 角色详情负责“装备”
|
||||
|
||||
职责一旦分清,后面很多 UI 冲突会自然消失。
|
||||
|
||||
## 4. 可复用的开发方法
|
||||
|
||||
### 4.1 新增一个 function 前,先问 6 个问题
|
||||
|
||||
1. 它会不会生成新 encounter?
|
||||
2. 它会不会写入后续推理上下文?
|
||||
3. 它的动画分几段?
|
||||
4. 哪一刻才算真正生效?
|
||||
5. 哪些内容由 AI 生成,哪些必须本地决定?
|
||||
6. 它是否需要从屏幕外入场?
|
||||
|
||||
这 6 个问题先答清,后面返工会少很多。
|
||||
|
||||
### 4.2 配战斗动画时,至少明确 4 个时点
|
||||
|
||||
1. 起手
|
||||
2. 位移/施法
|
||||
3. 特效命中
|
||||
4. 扣血/击退/结算
|
||||
|
||||
特别是:
|
||||
|
||||
- 近战攻击前的 dash
|
||||
- 远程不移动但要挂特效
|
||||
- 受击延后到命中特效之后
|
||||
|
||||
都属于这套时点设计。
|
||||
|
||||
### 4.3 做素材替换时,不要只看资源名
|
||||
|
||||
正确顺序更接近:
|
||||
|
||||
1. 打开素材看实际形状
|
||||
2. 判断它在当前语义里是不是“最像这个功能”
|
||||
3. 缩到真实 UI 尺寸再看一遍
|
||||
4. 再决定 active/inactive 怎么处理
|
||||
|
||||
### 4.4 做聊天流式界面时,反馈一定要插到正在发生的流里
|
||||
|
||||
这轮加“好感度 +x”提示后,更明确了一件事:
|
||||
|
||||
- 系统反馈不应该只藏在最终结果
|
||||
- 要插进聊天进行中的体验里
|
||||
- 文本流超出剧情框时要自动滚动
|
||||
|
||||
否则用户会错过真正重要的状态变化。
|
||||
|
||||
## 5. 以后继续做这类需求时,建议坚持的原则
|
||||
|
||||
- 先收拢 function 边界,再改剧情文案。
|
||||
- 先确定动画结算时序,再接特效素材。
|
||||
- 先做本地规则兜底,再让大模型生成文本。
|
||||
- 先保证移动端可扫读,再考虑装饰性面板。
|
||||
- 先复用已有角色/场景坐标体系,再做个别修正。
|
||||
- 先看最终显示层,再判断“改动是否生效”。
|
||||
|
||||
## 6. 这轮最重要的一句话总结
|
||||
|
||||
这类 AI 冒险 RPG 的开发,最难的不是“把功能做出来”,而是:
|
||||
|
||||
**让 function 边界、世界状态、视觉演绎、移动端面板和大模型文本在同一套规则下稳定协作。**
|
||||
116
docs/experience/AGENT_UI_CHANGELOG.md
Normal file
116
docs/experience/AGENT_UI_CHANGELOG.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# UI 改动记录(供后续 Agent 阅读)
|
||||
|
||||
本文档汇总 **像素 RPG UI 皮肤化** 相关实现与决策,便于新会话快速接手。更细的命名与规范见同目录上一级的 **`UI_CODING_STANDARD.md`**。
|
||||
|
||||
---
|
||||
|
||||
## 1. 相关文件一览
|
||||
|
||||
| 路径 | 作用 |
|
||||
|------|------|
|
||||
| `UI_CODING_STANDARD.md` | 资源目录约定、9-slice 规则、图标语义、`Icons`/`UI` 命名解读、已知问题(含世界按钮切片) |
|
||||
| `src/uiAssets.ts` | **唯一推荐** 的 UI 资源映射:`UI_CHROME`(9-slice 配置)、`TAB_ICONS`、`WORLD_SELECT_ICONS`、`getNineSliceStyle()` |
|
||||
| `src/components/PixelIcon.tsx` | 小图标 `<img>`,`image-rendering: pixelated` |
|
||||
| `src/index.css` | `.pixel-nine-slice`、`.pixel-root-shell` / `.pixel-app-shell`、tab/按钮布局类、`--ui-scale` |
|
||||
| `src/App.tsx` | 世界选择、角色卡、底部 tab、剧情/背包面板、地图弹窗、`MudMapRoom` |
|
||||
| `src/components/GameCanvas.tsx` | 场景名按钮(9-slice `Title_frame_m`) |
|
||||
| `vite.config.ts` | `root` / `envDir` 指向 `__dirname`,保证 `.env.local` 从项目根加载 |
|
||||
| `public/UI/`、`public/Icons/` | 静态资源(路径以 `/UI/...`、`/Icons/...` 引用) |
|
||||
|
||||
---
|
||||
|
||||
## 2. 架构要点
|
||||
|
||||
### 2.1 9-slice(禁止整图 `background-size: 100% 100%` 拉框体)
|
||||
|
||||
- 使用 CSS **`border-image`** + **`fill`**,通过自定义属性注入切片参数。
|
||||
- 类名:**`pixel-nine-slice`**(定义在 `src/index.css`)。
|
||||
- 行内样式由 **`getNineSliceStyle(texture, overrides?)`** 生成(`src/uiAssets.ts`),设置 `--frame-src`、`--slice-*`、`--frame-pad-*`、`--frame-repeat`、可选 `--frame-base`(一般仅在图源中心确实透明时使用)。
|
||||
|
||||
### 2.2 响应与缩放
|
||||
|
||||
- `:root` 上 **`--ui-scale`**:`clamp`(桌面)+ 小屏媒体查询内固定约 `0.8`。
|
||||
- 边框宽度 = 切片像素 × `--ui-scale`,与 padding 同逻辑,避免移动端边框比例失控。
|
||||
|
||||
### 2.3 交互
|
||||
|
||||
- **`pixel-pressable`**:hover 用 `translateY` + `brightness`,**避免**对像素框体做 `scale()` 以免糊边。
|
||||
|
||||
### 2.4 全局背景
|
||||
|
||||
- **根布局**(`App.tsx` 最外层):`pixel-root-shell` + `Background_fill.png` 平铺 + 深色半透明渐变(替代纯 `#050505` 死底)。
|
||||
- **下半屏内容区** `pixel-app-shell`:同一纹理 + **更轻**的遮罩,让纹理更明显。
|
||||
- 开局标题区已去掉单独 `bg-zinc-950`,与根背景一致。
|
||||
|
||||
---
|
||||
|
||||
## 3. `UI_CHROME` 当前用途(速查)
|
||||
|
||||
以下为 `src/uiAssets.ts` 中主要键与界面位置的对应关系(切片数值以文件内为准):
|
||||
|
||||
| Key | 资源(示例) | 用途 |
|
||||
|-----|----------------|------|
|
||||
| `appBackground` | `Background_fill.png` | 根壳 + 下半屏平铺底 |
|
||||
| `worldButtonWuxia` / `worldButtonXianxia` | `1_orange_button` / `1_violet_button` | 开局武侠/仙侠(**条高 28px**,切片见下文) |
|
||||
| `characterCardFrame` | `pick_hero_frame` | 选角卡片 |
|
||||
| `tabActive` / `tabInactive` | `Shop_tab_picked` / `Shop_tab` | 底部「角色 / 冒险 / 背包」 |
|
||||
| `panel` | `Frame_bg_big_2` | 装备区等通用面板 |
|
||||
| `storyPanel` | `Dialogue_frame` | 剧情正文区 |
|
||||
| `inventoryPanel` | `Inventory_bg` | 背包条目 |
|
||||
| `statsPanel` | `Stats_bar` | 角色数值面板 |
|
||||
| `choiceButton` | `Options_bar` | 剧情选项按钮 |
|
||||
| `modalPanel` | `Popup_window` | 地图弹窗外壳 |
|
||||
| `infoPanel` | `Dialogue_frame` | 地图弹窗内「当前地点 / 可前往」信息块 |
|
||||
| `sceneTitle` | `Title_frame_m` | 战斗画布顶部场景名按钮 |
|
||||
| `mapRoomCell` | `Map_frame` | 地图节点卡片(`MudMapRoom`) |
|
||||
| `mapDiagramPanel` | `Frame_bg_big_2` | 地图关系图整体衬底 |
|
||||
|
||||
图标路径:`TAB_ICONS`、`WORLD_SELECT_ICONS`、`CHROME_ICONS`;装备槽与背包分类见 `getEquipmentSlotIcon` / `getInventoryCategoryIcon`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 已知坑(必读)
|
||||
|
||||
### 4.1 世界选择按钮「中间发空」
|
||||
|
||||
- 图源 **`1_orange_button.png` / `1_violet_button.png` 为 125×28**。
|
||||
- 若 **`slice.top + slice.bottom >= 28`**,中间横带高度为 **0**,`border-image` 的 `fill` 异常,看起来像透明/没画上。
|
||||
- **正确做法**:减小上下切片(当前为 **9+9**),并配合 `repeat: 'stretch'` 竖向拉伸条形成品。
|
||||
- **不推荐**:用大色块 `baseColor` 糊底(与素材内渐变/内框不一致)。详见 `UI_CODING_STANDARD.md`「已知问题」。
|
||||
|
||||
### 4.2 新增 9-slice 前
|
||||
|
||||
先读 PNG **宽高**,保证 **`top+bottom < height`** 且 **`left+right < width`**。
|
||||
|
||||
---
|
||||
|
||||
## 5. 环境与运行(与 UI 无关但易踩坑)
|
||||
|
||||
- LLM:`VITE_LLM_*` 写在项目根 **`.env.local`**;因 `vite.config.ts` 固定 `envDir: __dirname`,从任意 cwd 启动也应能读到。
|
||||
- 开发:`npm run dev`(默认端口见 `package.json`)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 尚未统一成 UI 图、仍用 Tailwind 小块面的区域(可选后续)
|
||||
|
||||
若产品要求「全盘无纯色板」,可继续替换,当前仍可能为 `bg-black/20`、`rounded-lg border` 等:
|
||||
|
||||
- 角色页装备行、属性格子
|
||||
- 地图弹窗顶栏分隔、关闭按钮外圈
|
||||
- `GameCanvas` 内血条、名字条等 HUD
|
||||
|
||||
---
|
||||
|
||||
## 7. 修改清单摘要(按主题)
|
||||
|
||||
1. **资源规范**:`UI_CODING_STANDARD.md` + 集中映射 `uiAssets.ts`。
|
||||
2. **9-slice 系统**:`index.css` + `getNineSliceStyle`。
|
||||
3. **开局 / 主界面**:世界按钮、选角卡、tab、面板、选项、背包、根与内容区背景纹理。
|
||||
4. **地图弹窗**:外壳、信息板、节点 `Map_frame`、关系图 `Frame_bg_big_2`。
|
||||
5. **画布**:场景名 `Title_frame_m`。
|
||||
6. **世界按钮**:按真实像素尺寸修正切片,去掉错误 `baseColor` 方案。
|
||||
7. **Vite**:`root`/`envDir` 保证环境变量加载稳定。
|
||||
|
||||
---
|
||||
|
||||
*文档目的:交接给下一个 Agent 时,优先读本文件 + `UI_CODING_STANDARD.md`,再改 `uiAssets.ts` / `App.tsx` / `index.css`。*
|
||||
262
docs/experience/CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md
Normal file
262
docs/experience/CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md
Normal file
@@ -0,0 +1,262 @@
|
||||
# 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. 一句话总结
|
||||
|
||||
这个项目最重要的经验不是“多写了多少功能”,而是:
|
||||
|
||||
**凡是会同时影响叙事、状态、演出和工具链的需求,都要先统一边界,再落实现。**
|
||||
277
docs/experience/CODEX_PAST_WORK_EXPERIENCE_SUMMARY.md
Normal file
277
docs/experience/CODEX_PAST_WORK_EXPERIENCE_SUMMARY.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# Codex Past Work Experience Summary
|
||||
|
||||
日期:`2026-03-23`
|
||||
|
||||
## 1. 工作范围概览
|
||||
|
||||
这几轮工作主要集中在 4 个方向:
|
||||
|
||||
1. 编辑器体系整理
|
||||
2. NPC 视觉编辑与素材接入
|
||||
3. 玩家角色与怪物动画资源纠偏
|
||||
4. 选项行为编辑器与预览链路升级
|
||||
|
||||
这些改动不是孤立的 UI 修补,而是横跨了:
|
||||
|
||||
- 资源定义层
|
||||
- 编辑器字段层
|
||||
- 运行时预览层
|
||||
- 游戏真实播放逻辑层
|
||||
|
||||
## 2. 已完成的核心工作
|
||||
|
||||
### 2.1 编辑器入口与页签整理
|
||||
|
||||
- 保留 `/preset-editor`、`/npc-editor`、`/function-editor`
|
||||
- 新增 `/behavior-editor` 作为“选项行为”编辑页别名
|
||||
- 将原先单独的 `NPC 视觉` 标签并回 `NPC` 编辑页
|
||||
- 将 `Function` 页签改名为 `选项行为`
|
||||
|
||||
结论:
|
||||
- 路由层要尽量兼容旧入口,避免历史链接失效
|
||||
- 页签命名要贴近创作者语言,而不是内部实现命名
|
||||
|
||||
### 2.2 NPC 视觉模块并入 NPC 编辑
|
||||
|
||||
完成内容:
|
||||
|
||||
- 将 [NpcVisualEditor](/E:/Repos/Genarrative/src/components/NpcVisualEditor.tsx) 嵌入 [PresetEditor](/E:/Repos/Genarrative/src/components/PresetEditor.tsx) 的 NPC 编辑页
|
||||
- 让 NPC 文本字段与视觉字段围绕同一个当前选中 NPC 联动
|
||||
- 保留视觉覆盖保存与全局布局保存能力
|
||||
|
||||
经验:
|
||||
|
||||
- NPC 文本编辑和 NPC 视觉编辑不应分裂成两个互不关联的工作流
|
||||
- “当前选中的 NPC” 必须是两个模块共享的单一数据源
|
||||
|
||||
### 2.3 Medieval NPC 素材定义重建
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 [medievalNpcVisuals.ts](/E:/Repos/Genarrative/src/data/medievalNpcVisuals.ts) 中重建了 Medieval NPC 的资产定义
|
||||
- 补齐了 cloth / leather / metal / melee / magic / ranged 六大类真实素材
|
||||
- 为素材增加了:
|
||||
- 语义化名称
|
||||
- 图块尺寸
|
||||
- 列数
|
||||
- 帧数
|
||||
- 姿态选项
|
||||
- 让编辑器不再直接使用文件名、序号名作为展示项
|
||||
|
||||
经验:
|
||||
|
||||
- 编辑器下拉项如果来自手写数组,迟早会和真实素材目录脱节
|
||||
- 素材定义最好具备“资产元数据”,而不是只有路径字符串
|
||||
- 一旦资产存在大图块,就不能再默认所有图块都是 `32x32`
|
||||
|
||||
### 2.4 NPC 动画器支持大图块武器
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 [MedievalNpcAnimator.tsx](/E:/Repos/Genarrative/src/components/MedievalNpcAnimator.tsx) 中为 `AtlasSprite` 增加:
|
||||
- `tileWidth`
|
||||
- `tileHeight`
|
||||
- 对齐偏移支持
|
||||
|
||||
效果:
|
||||
|
||||
- 长柄武器
|
||||
- 巨剑
|
||||
- 64x32 远程武器
|
||||
- 64x64 投石索类武器
|
||||
|
||||
都能正确显示,不再被按 `32x32` 裁坏。
|
||||
|
||||
经验:
|
||||
|
||||
- 视觉编辑器一旦涉及装备 atlas,就必须把“资源尺寸”从数据层带到渲染层
|
||||
|
||||
### 2.5 玩家角色动画映射纠偏
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 [characterPresets.ts](/E:/Repos/Genarrative/src/data/characterPresets.ts) 中重新核对 5 个玩家角色的 Hero 动画目录
|
||||
- 修正了错误帧数、错误前缀、遗漏动作
|
||||
- 补齐了真实存在但之前未接入的动作:
|
||||
- `acquire`
|
||||
- `climb`
|
||||
- `dash`
|
||||
- `die`
|
||||
- `double jump`
|
||||
- `hurt`
|
||||
- `jump`
|
||||
- `jump attack`
|
||||
- `wall slide`
|
||||
- 给角色动画配置增加了 `file` 字段,支持单文件动画
|
||||
|
||||
相关文件:
|
||||
|
||||
- [types.ts](/E:/Repos/Genarrative/src/types.ts)
|
||||
- [CharacterAnimator.tsx](/E:/Repos/Genarrative/src/components/CharacterAnimator.tsx)
|
||||
- [characterCombat.ts](/E:/Repos/Genarrative/src/data/characterCombat.ts)
|
||||
|
||||
经验:
|
||||
|
||||
- 只要编辑器允许用户切“预览动作”,就不能让未映射动作静默 fallback 到 `idle`
|
||||
- 正确做法是:
|
||||
1. 先补齐真实动作映射
|
||||
2. 再让预览下拉只显示当前角色实际可用动作
|
||||
|
||||
### 2.6 怪物动画空白帧修复
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 [monsterPresets.ts](/E:/Repos/Genarrative/src/data/monsterPresets.ts) 中把怪物动画从“连续帧猜测”改成“按图集行起点取帧”
|
||||
- 补上缺失的 `die` 配置
|
||||
- 清除了所有落进空白格的动画段
|
||||
|
||||
经验:
|
||||
|
||||
- 像素怪物图集不一定按一个连续区段排完整套动作
|
||||
- 如果动作配置只写 `start + frames`,但没结合图集行结构,就非常容易踩进空白帧
|
||||
|
||||
### 2.7 选项行为编辑器重构
|
||||
|
||||
完成内容:
|
||||
|
||||
- 将原 “Function 编辑器” 改造成 “选项行为编辑器”
|
||||
- 页面文案和入口统一为“选项行为”
|
||||
- 移除“基础场景 / 结果场景”双窗格预览
|
||||
- 保留并强化:
|
||||
- 行为列表
|
||||
- 覆盖保存
|
||||
- 快速模板套用
|
||||
|
||||
经验:
|
||||
|
||||
- 创作者并不关心 “function” 这个技术词,更关心“这个选项会发生什么”
|
||||
- 同类编辑器如果只给字段表单而没有模板起稿能力,复用效率会很低
|
||||
|
||||
### 2.8 选项行为预览升级到实机回放
|
||||
|
||||
完成内容:
|
||||
|
||||
- 在 [StateFunctionEditor.tsx](/E:/Repos/Genarrative/src/components/StateFunctionEditor.tsx) 中新增 `BehaviorExecutionPreview`
|
||||
- 预览不再是静态推测,而是:
|
||||
1. 构造本地 `GameState`
|
||||
2. 调用真实 `resolveFunctionOption`
|
||||
3. 再调用 [useCombatFlow.ts](/E:/Repos/Genarrative/src/hooks/useCombatFlow.ts) 的
|
||||
- `buildResolvedChoiceState`
|
||||
- `playResolvedChoice`
|
||||
- 从而直接复用游戏真实逻辑
|
||||
|
||||
覆盖能力包括:
|
||||
|
||||
- 战斗行为
|
||||
- 恢复行为
|
||||
- 脱离行为
|
||||
- 探索前探
|
||||
- 切场行为
|
||||
|
||||
经验:
|
||||
|
||||
- 编辑器预览只要和运行时逻辑写成两套,就一定会越来越不一致
|
||||
- 预览层最稳的做法是“调用真实业务逻辑”,而不是“模拟真实业务逻辑”
|
||||
|
||||
## 3. 关键踩坑记录
|
||||
|
||||
### 3.1 图标组件名覆盖原生 `Map`
|
||||
|
||||
问题:
|
||||
|
||||
- `lucide-react` 的 `Map` 图标直接命名为 `Map`
|
||||
- 在 NPC 页签里 `new Map()` 实际调用到了图标组件
|
||||
- 导致页签内容直接渲染为空
|
||||
|
||||
经验:
|
||||
|
||||
- 图标组件命名尽量使用 `MapIcon`、`UserIcon` 这类后缀
|
||||
- 避免覆盖 JS/TS 原生对象名
|
||||
|
||||
### 3.2 预览 effect 依赖不稳定导致回放反复重启
|
||||
|
||||
问题:
|
||||
|
||||
- `BehaviorExecutionPreview` 里使用了 `useCombatFlow()`
|
||||
- 但 effect 依赖了返回对象本身
|
||||
- 每次 `gameState` 更新,effect 都会被视为变更
|
||||
- 导致预览回放速度异常、重复重启、动画像加速
|
||||
|
||||
经验:
|
||||
|
||||
- 只要预览组件内部要“异步播放状态变化”,就要高度警惕 effect 依赖环
|
||||
- 解决方式是:
|
||||
- 用 `ref` 保存稳定方法引用
|
||||
- 让 effect 只依赖真正的输入配置,不依赖内部播放状态
|
||||
|
||||
### 3.3 实时面板与回放阶段不同步
|
||||
|
||||
问题:
|
||||
|
||||
- `LIVE PLAYER` 用的是实时 `gameState`
|
||||
- `BATTLE SNAPSHOT` 用的是预计算首回合快照
|
||||
- 两者不是同一时间点的数据
|
||||
- 导致面板看起来“都对,但互相对不上”
|
||||
|
||||
经验:
|
||||
|
||||
- 预览面板要么都显示“实时状态”
|
||||
- 要么都显示“同一个阶段的快照”
|
||||
- 混用实时值和预测值会让创作者误判
|
||||
|
||||
## 4. 这类项目里沉淀下来的方法论
|
||||
|
||||
### 4.1 先校验资源,再改编辑器
|
||||
|
||||
顺序建议:
|
||||
|
||||
1. 先扫真实目录
|
||||
2. 再建资产定义
|
||||
3. 再修编辑器字段
|
||||
4. 最后修预览
|
||||
|
||||
### 4.2 预览必须尽量复用游戏真实链路
|
||||
|
||||
优先级:
|
||||
|
||||
1. 复用真实函数
|
||||
2. 复用真实状态结构
|
||||
3. 复用真实渲染组件
|
||||
4. 最后才是补充编辑器专用的辅助信息
|
||||
|
||||
### 4.3 编辑器要区分“可编辑字段”和“会生效字段”
|
||||
|
||||
经验:
|
||||
|
||||
- 不是所有字段都应该在所有行为类型下开放
|
||||
- 如果某类行为最终不会直接读取某个字段,就应该禁用或弱化它
|
||||
- 否则创作者会错误地以为改动无效是 bug
|
||||
|
||||
### 4.4 模板比空白表单更重要
|
||||
|
||||
经验:
|
||||
|
||||
- 当系统里已经有多种成熟行为时,最快的创作路径不是“从零填写”
|
||||
- 而是:
|
||||
- 选一个最像的
|
||||
- 套结构
|
||||
- 微调文案和数值
|
||||
|
||||
## 5. 推荐的后续方向
|
||||
|
||||
如果继续打磨这套编辑器,建议下一步做:
|
||||
|
||||
1. 为选项行为预览增加“时间轴 / 阶段日志”
|
||||
2. 为选项行为编辑器增加“新建行为向导”
|
||||
3. 把更多系统状态引入预览上下文
|
||||
- 同伴
|
||||
- NPC 状态
|
||||
- 背包
|
||||
- 当前场景实体池
|
||||
4. 把“可编辑字段”和“只读推导字段”视觉上再分开
|
||||
|
||||
## 6. 一句话总结
|
||||
|
||||
过去这几轮最重要的经验不是“写了多少编辑器 UI”,而是:
|
||||
|
||||
**编辑器一旦想可靠,就不能只编辑静态数据,必须逐步接管真实资源定义、真实运行时状态和真实播放逻辑。**
|
||||
191
docs/experience/MOBILE_UI_DEV_EXPERIENCE.md
Normal file
191
docs/experience/MOBILE_UI_DEV_EXPERIENCE.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# 奇幻酒馆 UI 开发经验沉淀
|
||||
|
||||
## 1. 总体原则
|
||||
|
||||
### 1.1 先保证移动端成立,再兼容网页端
|
||||
- 入口页、世界选择、角色选择、冒险页、弹窗面板,都要先按手机竖屏去定义信息密度。
|
||||
- 网页端只做“放宽容器、增加留白、补充 hover”,不要反过来让桌面布局压垮手机体验。
|
||||
- 任何区域如果在移动端需要滚动,必须明确谁滚动,不能让整页和局部同时争夺滚动。
|
||||
|
||||
### 1.2 游戏 UI 要优先“状态清晰”,而不是“文案很多”
|
||||
- 开始页应该像主菜单,不像产品介绍页。
|
||||
- 角色选择页应该像角色选择器,不像角色说明书。
|
||||
- 冒险页应该像战斗/剧情操作台,不像文档阅读器。
|
||||
|
||||
### 1.3 一屏内的层级顺序要稳定
|
||||
- 上半部分:画面演出。
|
||||
- 中间部分:剧情或核心信息。
|
||||
- 底部:操作按钮。
|
||||
- 玩家必须能快速判断“我在看什么、下一步点哪里”。
|
||||
|
||||
## 2. 入口页经验
|
||||
|
||||
### 2.1 开始页
|
||||
- 极简化是对的。
|
||||
- 当前实践证明:开始页只保留“开始游戏”和“开发团队”两个主按钮,体验明显更像游戏。
|
||||
- 游戏名和英文副标题可以保留,但不要再加长段描述。
|
||||
|
||||
### 2.2 世界选择
|
||||
- 纵向焦点轮播比普通列表更适合移动端。
|
||||
- 当前居中的卡片应该最大、最清晰、最亮;上下卡片缩放和透明度随滚动连续变化。
|
||||
- 世界确认动作应该绑定当前聚焦卡,而不是每张卡都塞太多按钮。
|
||||
|
||||
### 2.3 角色选择
|
||||
- 横向轮播是正确方向。
|
||||
- 中间卡片应承担“主视觉 + 主要信息”。
|
||||
- 左右卡片只做预览,不需要承载完整信息。
|
||||
- 左右卡片倾斜方向一定要符合透视直觉:
|
||||
左侧卡片向左外倾,右侧卡片向右外倾。
|
||||
- 中间卡片不要出现任何模糊,否则会破坏“当前选中”的确认感。
|
||||
|
||||
## 3. 角色选择页经验
|
||||
|
||||
### 3.1 聚焦卡的表现
|
||||
- 中间聚焦卡用角色 `run` 动画是有效的,能明显提升“角色活着”的感觉。
|
||||
- 但动画资源和静态立绘的锚点通常不一致,必须单独做位置与缩放修正。
|
||||
- 结论:
|
||||
动画版角色不要直接复用静态图样式,要单独给 `transform`、`height`、`transform-origin`。
|
||||
|
||||
### 3.2 信息区要紧凑
|
||||
- 角色数值和角色背景应该放在轮播下方,但必须压缩高度。
|
||||
- 如果下方面板过高,会直接破坏上半部分轮播体验,尤其在手机上。
|
||||
- 删除背景面板里的额外动画模块是正确的,因为它与主轮播重复抢视觉焦点。
|
||||
|
||||
### 3.3 文案层级
|
||||
- 页面标题只保留一句:
|
||||
“选择你扮演的角色”
|
||||
- 不要再强调 `CHARACTER SELECT` 之类的开发向分类标签。
|
||||
- 聚焦卡下方直接显示角色名,比把名字只放在卡片底部更直观。
|
||||
|
||||
### 3.4 按钮位置
|
||||
- “确认选择”必须放在角色轮播和信息区之后,作为页面最后的主动作。
|
||||
- 按钮不宜过宽过高,否则会抢轮播的视觉重心。
|
||||
|
||||
## 4. 冒险页经验
|
||||
|
||||
### 4.1 剧情区必须自适应
|
||||
- 剧情文本区不应该写死高度。
|
||||
- 正确做法是:
|
||||
让它自动填满“上方画面下缘”和“底部按钮区上缘”之间的剩余空间。
|
||||
- 这样才能同时保证:
|
||||
1. 上方画面一屏可见
|
||||
2. 下方三个选项一屏可见
|
||||
3. 中间剧情尽量大
|
||||
|
||||
### 4.2 底部操作区必须锚定到底
|
||||
- 队伍、背包、换一换、选项列表,都应该属于底部控制区。
|
||||
- 用户会天然在屏幕底部寻找交互入口,尤其是手机。
|
||||
- 因此:
|
||||
不要把这些按钮漂在中间,不要让剧情区把它们挤走。
|
||||
|
||||
### 4.3 队伍与背包不应打断主流程
|
||||
- 在冒险页内,队伍和背包更适合“弹出面板”而不是“切换整页”。
|
||||
- 原因:
|
||||
1. 不会打断当前剧情阅读
|
||||
2. 用户返回成本更低
|
||||
3. 操作像手游副面板,更符合预期
|
||||
|
||||
### 4.4 图标优于文字按钮
|
||||
- 在底部工具区,队伍/背包改成 icon 后更紧凑。
|
||||
- 但必须保留 `aria-label`,保证语义清晰、后续也方便测试。
|
||||
|
||||
## 5. 队伍面板经验
|
||||
|
||||
### 5.1 移动端成员列表不能太“卡片化”
|
||||
- 如果每个成员都再套一层大边框卡片,手机上会显得很挤。
|
||||
- 更好的方式是直接在主面板里陈列成员,弱化分隔、强化内容。
|
||||
|
||||
### 5.2 队伍列表展示什么
|
||||
- 头像
|
||||
- 姓名
|
||||
- 称号
|
||||
- 身份标记(领队/同行)
|
||||
- HP / MP
|
||||
|
||||
### 5.3 队伍详情弹窗
|
||||
- 弹窗必须可滚动。
|
||||
- 弹窗宽度不宜太大,手机优先单列或偏单列。
|
||||
- 技能、装备、属性三个区块保持稳定结构,便于扫读。
|
||||
|
||||
## 6. 背包页经验
|
||||
|
||||
### 6.1 格子数要优先适配手机
|
||||
- 手机端格子间距要小一号。
|
||||
- 图标尺寸和分类角标要跟着缩小。
|
||||
- 目标不是“每个格子信息很多”,而是“单屏能看更多格子”。
|
||||
|
||||
### 6.2 背包详情弹窗
|
||||
- 手机端改成单列/窄宽度布局更合理。
|
||||
- 详情窗里的信息顺序建议固定:
|
||||
1. 名称与类别
|
||||
2. 品质与数量
|
||||
3. 大图标
|
||||
4. 说明
|
||||
5. 标签
|
||||
|
||||
## 7. 样式与动画经验
|
||||
|
||||
### 7.1 轮播动画要连续,不要离散
|
||||
- 滚动时应根据“当前位置与当前卡片中心的距离”实时计算:
|
||||
- `scale`
|
||||
- `opacity`
|
||||
- `rotate`
|
||||
- `translate`
|
||||
- 不要做成“翻页后才跳变”的效果。
|
||||
|
||||
### 7.2 焦点卡与非焦点卡的职责要不同
|
||||
- 焦点卡负责可读性与确认感。
|
||||
- 非焦点卡负责预告与空间深度。
|
||||
- 所以焦点卡不该模糊,非焦点卡可以轻微降透明度、缩放、偏移。
|
||||
|
||||
### 7.3 资源锚点要单独校准
|
||||
- 静态立绘和动画帧经常不是同一锚点。
|
||||
- 只要切换成动画,就需要重新调:
|
||||
- 高度
|
||||
- Y 偏移
|
||||
- 缩放
|
||||
- `transform-origin`
|
||||
|
||||
## 8. 工程经验
|
||||
|
||||
### 8.1 组件要继续拆
|
||||
- 本轮重构证明,把入口页、冒险页、队伍页、背包页拆成独立组件是正确的。
|
||||
- 后续新增 UI 需求时,应优先落在:
|
||||
- `GameShell.tsx`
|
||||
- `AdventurePanel.tsx`
|
||||
- `CharacterPanel.tsx`
|
||||
- `InventoryPanel.tsx`
|
||||
|
||||
### 8.2 不要相信“服务已经在跑”
|
||||
- 这轮出现过“端口上有进程,但浏览器仍然拿到旧模块”的问题。
|
||||
- 实际经验:
|
||||
1. 要检查 `src` 文件内容
|
||||
2. 要检查 dev server 实际返回的模块内容
|
||||
3. 要确认启动脚本是否是当前项目真正使用的脚本
|
||||
|
||||
### 8.3 本项目当前开发服务入口
|
||||
- 本地正确启动脚本是:
|
||||
`node scripts/vite-cli.mjs --port=3000 --host=0.0.0.0`
|
||||
- 历史脚本或旧进程会导致“代码已改但 UI 看起来没变”的假象。
|
||||
|
||||
## 9. 后续建议
|
||||
|
||||
### 9.1 可以继续统一中英混杂文案
|
||||
- 当前部分新旧文本仍有历史遗留字符问题。
|
||||
- 如果后面继续做 UI 精修,建议单独做一轮文案清洗。
|
||||
|
||||
### 9.2 可以把轮播抽成通用组件
|
||||
- 世界纵向焦点轮播
|
||||
- 角色横向倾斜轮播
|
||||
- 这两套逻辑已经足够稳定,适合后续抽成通用 hook 或通用组件。
|
||||
|
||||
### 9.3 可以补移动端安全区适配
|
||||
- 当前已经偏移动端优先,但还可以继续加:
|
||||
- `safe-area-inset-bottom`
|
||||
- `safe-area-inset-top`
|
||||
- 更细的竖屏断点处理
|
||||
|
||||
## 10. 一句话结论
|
||||
|
||||
这一轮最关键的经验是:
|
||||
**游戏 UI 的移动端优化,本质不是把元素缩小,而是重组视觉重心、固定操作锚点、让焦点内容在一屏内自然成立。**
|
||||
243
docs/experience/PROJECT_DEVELOPMENT_EXPERIENCE.md
Normal file
243
docs/experience/PROJECT_DEVELOPMENT_EXPERIENCE.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# 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 规则、选择流程和编辑器体系同时存在的情况下,始终让每条链路各归其位。
|
||||
266
docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md
Normal file
266
docs/experience/PROJECT_WORK_EXPERIENCE_PLAYBOOK.md
Normal file
@@ -0,0 +1,266 @@
|
||||
# 奇幻酒馆项目开发经验手册
|
||||
|
||||
日期:`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/experience/PROJECT_DEVELOPMENT_EXPERIENCE.md`
|
||||
- `docs/experience/MOBILE_UI_DEV_EXPERIENCE.md`
|
||||
- `docs/experience/CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md`
|
||||
- `docs/experience/AGENT_UI_CHANGELOG.md`
|
||||
25
docs/experience/README.md
Normal file
25
docs/experience/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# 经验沉淀
|
||||
|
||||
这一组文档主要回答两个问题:
|
||||
|
||||
- 这个项目开发时有哪些稳定有效的方法论。
|
||||
- 遇到 UI、运行时、编辑器、AI 边界问题时,优先应该怎么判断。
|
||||
|
||||
## 推荐入口
|
||||
|
||||
1. [PROJECT_WORK_EXPERIENCE_PLAYBOOK.md](./PROJECT_WORK_EXPERIENCE_PLAYBOOK.md):最完整的项目开发手册,适合先建立全局认识。
|
||||
2. [PROJECT_DEVELOPMENT_EXPERIENCE.md](./PROJECT_DEVELOPMENT_EXPERIENCE.md):项目级经验浓缩版,适合快速回顾。
|
||||
3. [ADVENTURE_RUNTIME_DEV_EXPERIENCE.md](./ADVENTURE_RUNTIME_DEV_EXPERIENCE.md):专门看运行时、战斗、演出、NPC 流程时优先读。
|
||||
4. [MOBILE_UI_DEV_EXPERIENCE.md](./MOBILE_UI_DEV_EXPERIENCE.md):做移动端/游戏 UI 时的布局和交互经验。
|
||||
5. [AGENT_UI_CHANGELOG.md](./AGENT_UI_CHANGELOG.md):当前 UI 改动脉络、资产约束和已知坑。
|
||||
|
||||
## 历史实现经验
|
||||
|
||||
- [CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md](./CODEX_IMPLEMENTATION_EXPERIENCE_2026-03-24.md):偏“这类需求怎么拆链路”的实战经验。
|
||||
- [CODEX_PAST_WORK_EXPERIENCE_SUMMARY.md](./CODEX_PAST_WORK_EXPERIENCE_SUMMARY.md):偏“之前做过什么、怎么做的”的历史记录。
|
||||
|
||||
## 使用建议
|
||||
|
||||
- 只需要读一份时,优先看 `PROJECT_WORK_EXPERIENCE_PLAYBOOK`。
|
||||
- 做 UI 改动时,把本目录和根目录的 `UI_CODING_STANDARD.md` 对照着看。
|
||||
- 做运行时流程改动时,把本目录和 `docs/audits/engineering/README.md` 一起看,能更快发现风险边界。
|
||||
Reference in New Issue
Block a user