Files
zeling_v2/Docs/Verification/10_Manual_ProgressionSystem.md
Joywayer 9aaa2b6452 docs: 修正进度系统文档中虚构的技能树系统
将 10_Manual_ProgressionSystem.md 中不存在的 SkillTreeSO/技能点/技能树解锁
流程,改写为真实实现:技能(FormSkillSO)随形态由 FormController 注入 SkillManager,
施放消耗魂力/灵力;能力通过 AbilityType 位掩码解锁(PlayerStats/AbilityFlags)。
同步更正 MT-PROG-06 的 HasAbility/存档字段引用,并统一 05/07/11 文档措辞为
'形态技能一览(FormSkillPanel)',明确本项目无技能树。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 11:39:57 +08:00

343 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 手动测试 10 · 进程与养成系统
> **测试类型**Unity Editor 手动测试Play Mode
> **覆盖模块**`BaseGames.Skills`、`BaseGames.Equipment`、`BaseGames.Quest`、`BaseGames.Progression`、`BaseGames.World.Shop`
> **依赖组件**`SkillManager`、`EquipmentManager`、`QuestManager`、`AchievementManager`、`ShopKeeper`
> **场景要求**:含存档点、商店 NPC、任务触发器的完整测试场景
---
## 快速工具
| 工具 | 用途 | 菜单路径 |
|------|------|----------|
| **Validate All ScriptableObjects** | 遍历所有实现 `IValidatable` 的 SO输出验证结果含 FormSkillSO、QuestDatabaseSO 等) | `BaseGames → Tools → Validate All ScriptableObjects` |
> **注意**PlayModeDebugOverlay 已移除。Geo 注入、能力解锁测试等请通过 Inspector 直接修改对应 SO/Manager 字段,或临时编写 Editor 脚本触发。
> Tab 10 的场景摆放工具Add Quest Trigger、Add Shop NPC已不再提供请参照下方各节**手动步骤**手工创建对应对象。
>
> **重要:本项目没有"技能点 + 技能树解锁"系统。** 技能(`FormSkillSO`)随形态绑定,由 `FormController` 在切换形态时注入 `SkillManager`,无需花费技能点解锁;`SkillTreePanel` 仅为只读的形态技能一览面板。能力(二段跳/冲刺/形态等)通过 `AbilityType` 位掩码解锁(见 MT-PROG-06不涉及任何技能树。
**典型工作流**
1. 测试前:`BaseGames → Tools → Validate All ScriptableObjects` 一键确认 SO 存在若有缺失Console 给出路径提示。
2. `MT-PROG-01` 技能:进入 Play Mode通过 `FormController` 切换形态,确认 `SkillManager` 注入对应形态的三个技能,施放消耗魂力/灵力并进入冷却。
3. `MT-PROG-03` 任务:手动放置 `QuestGiver` NPC见下方步骤`QuestSO` 拖入 InspectorPlay Mode 中交互验证。
4. `MT-PROG-05` 商店:手动放置 `ShopNPC`(见下方步骤),通过 Inspector 修改 `_geo` 字段给玩家加钱,交互购买。
---
## 目录
1. [前置数据检查](#1-前置数据检查)
2. [MT-PROG-01形态技能与施放](#mt-prog-01形态技能与施放)
3. [MT-PROG-02装备系统护符/武器)](#mt-prog-02装备系统护符武器)
4. [MT-PROG-03任务系统QuestManager](#mt-prog-03任务系统questmanager)
5. [MT-PROG-04成就系统AchievementManager](#mt-prog-04成就系统achievementmanager)
6. [MT-PROG-05商店系统Shop](#mt-prog-05商店系统shop)
7. [MT-PROG-06能力解锁AbilityUnlock](#mt-prog-06能力解锁abilityunlock)
---
## 1. 前置数据检查
| 资产 | 路径(示例) | 必要性 | ✓ |
|------|------------|--------|---|
| FormSkillSO ×N | `Assets/_Game/Data/Skills/SKL_*.asset` | 技能测试必须(每形态 3 个:魂技+灵技1+灵技2 | ☐ |
| EquipmentSlotConfigSO | `Assets/Data/Equipment/SlotConfig.asset` | 装备测试必须 | ☐ |
| QuestDatabaseSO | `Assets/Data/Quests/` | 任务测试必须 | ☐ |
| AchievementDatabaseSO | `Assets/Data/Achievements/` | 成就测试必须 | ☐ |
| ShopInventorySO | `Assets/Data/Shop/` | 商店测试必须 | ☐ |
> **🔧 一键检查 + 资产创建**
>
> **步骤 1 — 验证资产存在性**
> 菜单 `BaseGames → Tools → Validate All ScriptableObjects`
> - Console 输出每项 ✅(通过)或 ❌(失败/未找到)
>
> **步骤 2 — 创建所有占位 SO**(若有缺失):
> 按照下方**步骤 3** 手动通过 Project 右键菜单创建对应资产。
>
> **步骤 3 — 创建尚未覆盖的数据资产(手动)**
>
> | 资产 | 创建方法 |
> |------|----------|
> | `FormSkillSO` | Project 右键 → Create → BaseGames → Skills → Form Skill保存到 `Assets/_Game/Data/Skills/`,命名 `SKL_{skillId}`;如有近战/爆炸判定再配套 `SKL_{skillId}_HitBox` 预制体 |
> | `EquipmentSlotConfigSO` | Project 右键 → Create → BaseGames → Equipment → Slot Config保存到 `Assets/_Game/Data/Equipment/` |
> | `QuestDatabaseSO` | Project 右键 → Create → BaseGames → Quest → Quest Database保存到 `Assets/_Game/Data/Quests/` |
> | `AchievementDatabaseSO` | Project 右键 → Create → BaseGames → Progression → Achievement Database保存到 `Assets/_Game/Data/Achievements/` |
> | `ShopInventorySO` | 已由 Create Test Assets 创建为 `ShopInventory_Test.asset`;点 Inspector 的 `+` 按钮添加 `ShopItem` 条目 |
>
> **步骤 4 — 绑定 Manager 字段**Play Mode 前):
> - 找到 Player 上的 `SkillManager` 组件 → Inspector → `_formSkillSets` 数组,按形态(天魂/地魂/命魂)逐项填入 `soulSkill` + `spiritSkill1` + `spiritSkill2`(对应 `FormSkillSO` 资产)
> - 找到 `ShopNPC` GameObjectTab 10 → 添加商店 NPC→ `_inventory` 字段拖入 `ShopInventory_Test.asset`
---
## MT-PROG-01形态技能与施放
**目的**:验证 `SkillManager` 的形态技能注入、技能施放、冷却管理、魂力/灵力消耗,以及 `FormSkillPanel`(只读技能一览)的展示。
> **架构说明(务必先读)**
> - 技能 = `FormSkillSO` 资产,**不通过技能点解锁**。每个形态绑定 3 个技能槽:魂技(`soulSkill`+ 灵技1`spiritSkill1`+ 灵技2`spiritSkill2`)。
> - `FormController` 在切换形态时回调 `SkillManager.UpdateSkillSet(...)`,把当前形态的三个技能注入到输入槽。玩家无须"学习"技能,切到该形态即可用。
> - 施放消耗的是**魂力SoulPower或灵力SpiritPower**(由 `FormSkillSO.resourceType` 决定),不是 MP。
> - `FormSkillPanel`(形态技能一览面板)只是只读一览:翻页查看各形态的技能图标/名称/描述/消耗/冷却,**没有解锁交互、没有技能点、没有节点**。
> - 技能数值可被护符改写,见 MT-PROG-02 与 `SkillModifierRegistry`。
> **🔧 资源准备**
> 1. 确认 Player 上 `SkillManager._formSkillSets` 已为待测形态填好三个 `FormSkillSO`。
> 2. 若待测形态尚未解锁(地魂/命魂),先解锁其形态能力:编辑 `PlayerConfigSO.InitialAbilities` 勾选 `FormDiHun` / `FormMingHun`,或临时写 Editor 脚本调用 `PlayerStats.UnlockAbility(AbilityType.FormDiHun)`。天魂(`FormTianHun`)默认初始解锁。
> 3. 确认输入动作已绑定:魂技 = `SoulSkillEvent`灵技1 = `SpiritSkill1StartedEvent`灵技2 = `SpiritSkill2StartedEvent`(见 `InputReaderSO`)。
### 步骤
**步骤 A形态切换注入技能**
1. 进入 Play Mode通过 `FormController` 切换到目标形态(切换输入键,或 Inspector 下调用 `FormController.SwitchForm(FormType.XXX)`)。
2. 观察 `SkillManager` 的当前技能(`SoulSkill` / `Spirit1` / `Spirit2` 属性)。
**预期**
- 切换形态后,`SkillManager` 的三个技能引用更新为该形态 `_formSkillSets` 中配置的技能。
- 冷却字典 `_cooldowns` 重建并清零(切换后立即可施放)。
- 若切换的是未解锁形态,`FormController.SwitchForm``HasAbility(FormXXX)` 拦截,技能集不变。
**步骤 B技能施放**
1. 进入战斗场景,按魂技/灵技1/灵技2 输入键。
**预期**
- 技能动画播放(`AnimancerComponent.Play(castAnimation)`)。
- 资源扣减:`SoulPower`/`SpiritPower -= effectiveCost``PlayerStats.ConsumeSoulPower/ConsumeSpiritPower`)。
- 命中判定生成(若技能配了 `SkillHitBoxPrefab`,从对象池取实例并 `Activate`)。
- 进入冷却(`effectiveCooldown` 秒内再次按键无效)。
- 触发 `skill_cast` 反馈预设。
**步骤 C资源不足时**
1. 使当前魂力/灵力 < `effectiveCost`(可在 Inspector 消耗资源或调小上限)。
2. 按技能键。
**预期**`ConsumeXxxPower` 返回 false技能不释放无动画、无判定、不进冷却
**步骤 D技能冷却**
1. 施放技能后立即再次按同一技能键。
**预期**:冷却期内 `_cooldowns[skill] > 0`不触发HUD 冷却指示(`SoulCooldownRatio`)显示剩余比例。
**步骤 EFormSkillPanel 只读一览**
1. 打开技能一览面板(`FormSkillPanel`)。
2. 左右翻页浏览各形态,确认当前实际形态被高亮(`_activeFormIndicator`)。
**预期**:面板展示各形态三技能的图标/名称/描述/消耗/冷却;**无任何"解锁/锁定"状态或点击解锁交互**(纯查看)。
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 形态注入 | 切换形态后 SkillManager 三技能引用随之更新 | ☐ |
| 未解锁形态拦截 | 切到未解锁形态被 HasAbility 拦截 | ☐ |
| 技能施放 | 动画播放,判定生成,魂力/灵力扣减 | ☐ |
| 资源不足 | 无法释放,不进冷却 | ☐ |
| 冷却 | 冷却期无法再次使用,比例显示 | ☐ |
| 一览面板 | 只读展示各形态技能,无解锁交互 | ☐ |
---
## MT-PROG-02装备系统护符/武器)
**目的**:验证 `EquipmentManager` 护符槽管理、装备属性叠加、超出槽数无法装备。
### 步骤
**步骤 A装备护符**
1. 打开装备 UI默认 Tab 键或 E 键进入背包)
2. 拖拽/确认护符到空槽位
**预期**
- 护符装备成功,护符图标显示在槽位
- 护符效果立即生效(如 HP+20查看 `PlayerStats.MaxHP`
- `EquipmentManager.IsEquipped(amuletId) == true`
**步骤 B槽位已满**
1. 将所有护符槽填满(`maxAmuletSlots` 个护符)
2. 尝试装备第 `maxAmuletSlots + 1` 个护符
**预期**:系统提示"护符栏已满",无法装备(不会覆盖现有护符)。
**步骤 C卸下护符**
1. 选中已装备的护符,点击"卸下"
**预期**
- 护符移回背包
- 护符提供的属性加成撤销HP 恢复原值)
**步骤 D武器切换FormController 联动)**
1. 切换形态Sky/Earth/Death
**预期**:装备的武器 SO 根据形态切换,攻击力/攻击动画随形态变化。
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 装备护符 | 效果立即生效,图标显示 | ☐ |
| 槽位限制 | 超出槽数无法装备 | ☐ |
| 卸下护符 | 属性加成撤销 | ☐ |
| 形态武器 | 不同形态武器属性不同 | ☐ |
---
## MT-PROG-03任务系统QuestManager
**目的**:验证 `QuestManager` 的任务激活→进度追踪→完成→奖励全流程。
> **🔧 资源准备**
> 1. 在 **Tab 10 → `添加任务触发器QuestTrigger`** 一键放置 `QuestTrigger` GameObject含 CapsuleCollider2D
> 2. 在 Inspector 中将 `QuestTriggerSO`手动创建Project 右键 → Create → BaseGames → Quest → QuestSO拖入 `QuestTrigger._questToStart`
> 3. 确认 `QuestDatabaseSO` 中已注册该 QuestSO 条目
### 步骤
**步骤 A任务激活**
1. 找到场景中的任务触发器(如 NPC 对话后触发任务)或手动调用 `QuestManager.StartQuest(questId)`
2. 打开任务日志 UI
**预期**:任务出现在"进行中"列表,任务目标文本正确显示。
**步骤 B进度追踪**
1. 完成部分任务目标(如击杀 X 敌人/收集 X 物品)
2. 查看任务日志
**预期**:任务进度更新(如 "击杀 2/5 只敌人"`EVT_QuestProgressUpdated` 事件触发。
**步骤 C任务完成**
1. 完成所有任务目标
**预期**
- `EVT_QuestCompleted` 事件触发
- 任务移入"已完成"列表
- 奖励自动发放Geo/能力解锁/道具)
- 存档文件中 `SaveData.Quests[questId].IsCompleted == true`
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 任务激活 | 任务出现在进行中列表 | ☐ |
| 进度追踪 | 完成目标后进度数字更新 | ☐ |
| 完成奖励 | 奖励正确发放 | ☐ |
| 持久化 | 存档中 IsCompleted == true | ☐ |
---
## MT-PROG-04成就系统AchievementManager
**目的**:验证 `AchievementManager` 触发条件监听、达成弹窗、持久化。
### 步骤
1. 触发某个成就的条件(如"首次击杀 Boss"、"连续弹反 5 次"等)
**预期**
- 屏幕右上角弹出成就解锁通知(`AchievementPopup`
- 通知显示成就名称和图标
- `EVT_AchievementUnlocked` 触发
2. 打开成就列表 UI
**预期**:该成就显示为已解锁状态(金色)。
3. 退出并重新进入 Play Mode
**预期**:成就状态仍为已解锁(`SaveData.Achievements` 持久化)。
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 触发弹窗 | 条件达成后弹出通知 | ☐ |
| 列表状态 | 成就列表中显示已解锁 | ☐ |
| 持久化 | 重进后仍为已解锁 | ☐ |
---
## MT-PROG-05商店系统Shop
**目的**:验证 `ShopKeeper`/`ShopInventory` 的购买/售出流程、Geo 扣减、背包更新。
> **🔧 资源准备**
> 1. 手动在场景中创建 `ShopNPC` GameObject添加 `CapsuleCollider2D`,并挂载 `ShopNPC` 组件
> 2. 在 Inspector 中将 `ShopInventory_Test.asset` 拖入 `ShopNPC._inventory`
> 3. 打开 `ShopInventory_Test.asset`,在 Inspector 展开 `_items` 数组,添加几个 `ShopItem`(配置 itemId、price、count
> 4. Play Mode 中在 Inspector 直接将 `PlayerController` / `GeoManager._geoCount` 设为 500 快速获取购物用 Geo
### 步骤
**步骤 A打开商店**
1. 走到商店 NPC按交互键
**预期**:商店 UI 打开,显示 `ShopInventorySO` 中的物品列表(价格、图标、名称)。
**步骤 B购买物品**
1. 选择一个 Geo 充足的物品,确认购买
**预期**
- `CurrentGeo -= item.price`
- 物品出现在背包
- HUD Geo 数量更新
**步骤 CGeo 不足**
1. 选择价格超过当前 Geo 的物品
**预期**:购买失败,提示"Geo 不足"Geo 不变。
**步骤 D售出物品**
1. 在商店卖出背包中的物品
**预期**
- `CurrentGeo += item.sellPrice`
- 物品从背包移除
- HUD Geo 数量更新
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 商店 UI 打开 | 物品列表正确显示 | ☐ |
| 购买成功 | Geo 减少,物品进背包 | ☐ |
| Geo 不足 | 购买失败Geo 不变 | ☐ |
| 售出 | Geo 增加,物品移除 | ☐ |
---
## MT-PROG-06能力解锁AbilityUnlock
**目的**验证特殊能力DoubleJump、WallCling、Dash 等 `AbilityType` 位)的解锁与 `AbilityGate` 联动。
### 步骤
1. 确认某能力(如 DoubleJump当前**未解锁**
2. 找到对应的能力解锁点Boss 击败后掉落,或特定区域触发)
3. 触发解锁
**预期**
- `EVT_AbilityUnlocked(AbilityType)` 触发(`AbilityTypeEventChannelSO`payload 为解锁的能力位)
- `PlayerStats.HasAbility(ability) == true`(位掩码 `_unlockedAbilities |= ability`
- 存档中 `SaveData.Player.AbilityFlags` 含该能力位(`(uint)_unlockedAbilities`
- 对应 `AbilityGate` 自动开启(若当前场景有联动门)
4. 测试新解锁的能力(如 DoubleJump跳跃后再次跳跃
**预期**:能力生效(二段跳可用)。
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 解锁事件 | EVT_AbilityUnlocked 触发 | ☐ |
| HasAbility == true | PlayerStats.HasAbility 返回 true | ☐ |
| AbilityGate 开启 | 对应能力门自动开启 | ☐ |
| 能力可用 | 新能力实际可使用 | ☐ |
| 持久化 | 存档 AbilityFlags 含该能力位 | ☐ |