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>
This commit is contained in:
@@ -379,13 +379,15 @@ public class PauseMenuController : MonoBehaviour, IFocusable
|
|||||||
|
|
||||||
## 10. 扩展指南
|
## 10. 扩展指南
|
||||||
|
|
||||||
### 添加新的游戏内面板(如技能树)
|
### 添加新的游戏内面板(以图鉴 Codex 为例)
|
||||||
|
|
||||||
1. 在 `Assets/_Game/Scenes/Persistent.unity` 的 `UIRoot` 下新建 `SkillTreeRoot`,初始 `SetActive(false)`。
|
> 说明:本项目**没有技能树**,技能随形态绑定(见 `FormSkillPanel` 与 `09_ProgressionModule`)。下方以一个假想的"图鉴面板"演示通用接入流程。
|
||||||
2. 在 `PanelId` 枚举中添加 `SkillTree`。
|
|
||||||
3. 在 `UIManager._panels` 数组中注册:`PanelId.SkillTree → SkillTreeRoot`。
|
1. 在 `Assets/_Game/Scenes/Persistent.unity` 的 `UIRoot` 下新建 `CodexRoot`,初始 `SetActive(false)`。
|
||||||
4. 创建 `EVT_SkillTreeOpen`(VoidEventChannelSO)并在 `UIManager.OnEnable` 中订阅 `_onSkillTreeOpen → () => OpenPanel(PanelId.SkillTree)`。
|
2. 在 `PanelId` 枚举中添加 `Codex`。
|
||||||
5. 在 `InputReader` 中添加 `SkillTree` 输入动作,触发时 Raise `EVT_SkillTreeOpen`。
|
3. 在 `UIManager._panels` 数组中注册:`PanelId.Codex → CodexRoot`。
|
||||||
|
4. 创建 `EVT_CodexOpen`(VoidEventChannelSO)并在 `UIManager.OnEnable` 中订阅 `_onCodexOpen → () => OpenPanel(PanelId.Codex)`。
|
||||||
|
5. 在 `InputReader` 中添加 `Codex` 输入动作,触发时 Raise `EVT_CodexOpen`。
|
||||||
|
|
||||||
### 使用 Addressable 按需加载大型面板
|
### 使用 Addressable 按需加载大型面板
|
||||||
|
|
||||||
|
|||||||
117
Docs/Guides/07_UI_Authoring_For_Designers_Guide.md
Normal file
117
Docs/Guides/07_UI_Authoring_For_Designers_Guide.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
# 07 · UI 编辑指南(面向策划 / 美术)
|
||||||
|
|
||||||
|
> 目的:不写代码,在 Unity 里改 UI 的**样式**和**内容**,并让**按键提示自动适配输入设备**。
|
||||||
|
> 工程架构细节见 `05_UISystem_Architecture_Guide.md`,本篇只讲「怎么改」。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 一句话心智模型
|
||||||
|
|
||||||
|
每个 UI 由四层组成,各自有独立的编辑入口,**互不影响**:
|
||||||
|
|
||||||
|
| 层 | 改什么 | 在哪改 | 谁负责 |
|
||||||
|
|----|--------|--------|--------|
|
||||||
|
| **Prefab(预制件)** | 样式 / 布局 / 图片 / 字体 / 装饰 | 双击预制件进 **Prefab Mode** | 美术 |
|
||||||
|
| **Config(配置 SO)** | 数据:条目 / 文案 key / 参数 | 选中 `.asset` 在 **Inspector** | 策划 |
|
||||||
|
| **Theme(主题)** | 全局配色 / 字体令牌 | `UI_Theme_Default.asset` | 美术 |
|
||||||
|
| **Localization(本地化)** | 文案译文 | 表格编辑器(菜单 `BaseGames/Localization/`) | 策划 |
|
||||||
|
|
||||||
|
原则:**样式进 Prefab、数据进 Config、配色进 Theme、文案进本地化表**。改任意一层都所见即所得,不用动代码。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 已数据驱动的 UI(直接照下表改)
|
||||||
|
|
||||||
|
| UI | 改样式(Prefab) | 配数据(Config 资产) |
|
||||||
|
|----|------------------|------------------------|
|
||||||
|
| 主菜单 | `Prefabs/UI/Controls/UI_MainMenu_Button.prefab` | `Data/UI/UI_MainMenuConfig.asset`(增删/重排菜单项、标签 key、图标、动作) |
|
||||||
|
| 设置面板 | `Prefabs/UI/Controls/UI_SettingsPanel.prefab` + `UI_Setting_*Row.prefab` | `Data/UI/UI_SettingsSchema.asset`(增删/重排设置项、分节) |
|
||||||
|
| 加载界面 | `Prefabs/UI/UI_LoadingScreen.prefab` | `Data/UI/UI_LoadingConfig.asset`(提示文案 key、标题 key、加载时长/手感) |
|
||||||
|
| 对话 | 对话面板预制件 | `DialogueSequenceSO` / `DialogueDataSO` 资产 |
|
||||||
|
|
||||||
|
> 例:想给主菜单加一个「成就」按钮 → 选 `UI_MainMenuConfig.asset`,在 Inspector 的 Items 里加一项,填 labelKey/动作即可,**不用碰场景和代码**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 改样式(美术,Prefab Mode)
|
||||||
|
|
||||||
|
1. 在 Project 窗口双击预制件(如 `UI_LoadingScreen.prefab`)→ 进入 Prefab Mode。
|
||||||
|
2. 自由操作:替换 `Image` 的 Sprite、调颜色/字体/字号、移动/缩放、加装饰节点(logo、光效、spinner、边框)。
|
||||||
|
3. 退出 Prefab Mode 即保存 → **所有用到该预制件的地方全局生效**。
|
||||||
|
|
||||||
|
注意:
|
||||||
|
- 节点上若挂了 **`UIThemeRole`**(如 `Graphic_Accent` / `Text_Header`),其颜色由主题统一控制;想让它用固定色,去掉该组件或直接在主题里调。
|
||||||
|
- 进度条填充:`ProgressBarFill` 的 Image 必须是 `Filled` / `Horizontal`(已配好,换 Sprite 即可)。
|
||||||
|
- 随机背景:在加载预制件里复制多个 `Background` 子物体(各配不同图),接到 `LoadingScreenManager._backgroundArts` 数组 → 运行时随机选一张。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 配数据 / 文案(策划)
|
||||||
|
|
||||||
|
- **数据**:选中对应 Config `.asset`,在 Inspector 改数组/参数。
|
||||||
|
- **文案**:UI 上显示的文字走**本地化 key**(不是直接写中文)。
|
||||||
|
1. 在 Config 里填 key(如 `LOADING_TITLE`、`MENU_NEW_GAME`)。
|
||||||
|
2. 用菜单 `BaseGames/Localization/表格编辑器` 给该 key 填中/英译文。
|
||||||
|
3. 缺译文时界面会显示 key 原文,便于发现遗漏。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 输入设备适配(按键提示,零代码)
|
||||||
|
|
||||||
|
系统已内置:会自动识别**当前设备**(键鼠 / PlayStation / Xbox / Switch),并随设备切换 / 改键自动换图标。
|
||||||
|
|
||||||
|
### 加一个「按键提示」到任意 UI
|
||||||
|
1. 选中目标 Canvas/节点 → 菜单 **`BaseGames/UI/控件库/向选中节点放置 ▸ InputPrompt`**。
|
||||||
|
2. 选中放进来的 `UI_Control_InputPrompt` → 在 `Icon` 的 **InputIconImage** 组件填 **ActionName**(如 `Interact`/`Jump`/`Attack`,对应输入表里的 Action)。
|
||||||
|
3. 在 `Label` 填提示文字(可挂 `LocalizedText` 走本地化)。
|
||||||
|
4. 完成 —— 运行时图标会显示**当前设备**对应的那颗按键,玩家切手柄/改键自动更新。
|
||||||
|
|
||||||
|
> 没有预制件?先跑菜单 `BaseGames/UI/控件库/生成输入提示控件(UI_Control_InputPrompt)`。
|
||||||
|
|
||||||
|
### ⚠️ 美术必做:填按键图标
|
||||||
|
图标系统代码已就绪,但**图标 sprite 还没填**。在这些资产里把每个按键路径对应的图片拖进去:
|
||||||
|
- `Data/UI/InputIcons/ICN_Keyboard.asset`(已列 32 个按键路径,逐个填 Icon)
|
||||||
|
- `Data/UI/InputIcons/ICN_Xbox.asset` / `ICN_PlayStation.asset` / `ICN_Switch.asset`(需先按需补按键路径条目再填图)
|
||||||
|
|
||||||
|
每条 = `BindingPath`(如 `<Gamepad>/buttonSouth`)→ `Icon`(sprite)。填完后所有 InputPrompt / 交互提示自动显示。**没填图时图标会自动隐藏,不会报错或显示错图。**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 改全局配色(美术,Theme)
|
||||||
|
|
||||||
|
选 `Data/UI/Themes/UI_Theme_Default.asset`,在 Inspector 调色板 / 字体令牌 → 所有挂了 `UIThemeRole` 的元素(背景/强调/标题/正文等)全局套用。想要多套皮肤可另存为多个主题资产切换。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 做一个全新 UI(不重复开发)
|
||||||
|
|
||||||
|
优先用脚手架菜单生成「预制件 + 配置」,而不是裸搭:
|
||||||
|
|
||||||
|
| 菜单(`BaseGames/UI/控件库/`) | 产出 |
|
||||||
|
|------|------|
|
||||||
|
| 生成或更新控件预制件 | Button/SelectableRow/Slider/Dropdown/Panel/TabBar 通用控件 |
|
||||||
|
| 生成设置面板(行预制件 + 默认表 + 面板) | 设置面板整套 |
|
||||||
|
| 生成主菜单(按钮预制件 + 默认表) | 主菜单整套 |
|
||||||
|
| 生成加载界面(预制件 + 默认配置) | 加载界面整套 |
|
||||||
|
| 生成输入提示控件 / 向选中节点放置 ▸ InputPrompt | 设备自适应按键提示 |
|
||||||
|
| 向选中节点放置 ▸ Button / Panel / ... | 把通用控件拖进选中 Canvas |
|
||||||
|
|
||||||
|
新面板:继承 `UIPanelBase`(统一生命周期 / 焦点 / 淡入 / 手柄导航),用上面的控件预制件拼,数据走一个新的 Config SO(仿 `MainMenuConfigSO` 写法)。这样**新 UI = 配 Prefab + 填 Config**,无需每次重写交互/导航/设备适配代码。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 手柄 / 焦点(已内置,无需配置)
|
||||||
|
- 方向键 / 摇杆导航、确认/取消由 `EventSystem` + `InputSystemUIInputModule` 统一处理。
|
||||||
|
- 焦点恢复(点空白不丢高亮)由 `UISelectionRestorer`(挂在 Persistent 的 EventSystem)负责。
|
||||||
|
- 面板栈、ESC 逐层返回、Modal 屏蔽下层由 `UINavigator` 负责。
|
||||||
|
- 你只需保证新面板有一个默认选中项(`UIPanelBase._firstSelected` 或重写 `ResolveFirstSelected()`)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 现状与待办(迁移进度)
|
||||||
|
|
||||||
|
- **已通用(照本指南直接改)**:主菜单、设置、加载、对话。
|
||||||
|
- **半通用**(有预制件可改样式,但调参仍在脚本 Inspector,正逐屏补 Config SO):HUD、Boss 血条、确认框、存档槽、死亡屏、Splash、背包/护符/任务、地图、商店。
|
||||||
|
- **待升级为数据驱动**:暂停菜单、新游戏难度选择、形态技能一览(`FormSkillPanel`,只读展示,非技能树)。
|
||||||
|
|
||||||
|
> 这些会按路线图逐屏迁到「Prefab + Config」。迁移完成后本表会更新;在此之前,半通用屏的样式仍可在各自预制件里改,调参在对应控制器的 Inspector 改。
|
||||||
@@ -11,14 +11,16 @@
|
|||||||
|
|
||||||
| 工具 | 用途 | 菜单路径 |
|
| 工具 | 用途 | 菜单路径 |
|
||||||
|------|------|----------|
|
|------|------|----------|
|
||||||
| **Validate All ScriptableObjects** | 遍历所有实现 `IValidatable` 的 SO,输出验证结果(含 SkillTreeSO、QuestDatabaseSO 等) | `BaseGames → Tools → Validate All ScriptableObjects` |
|
| **Validate All ScriptableObjects** | 遍历所有实现 `IValidatable` 的 SO,输出验证结果(含 FormSkillSO、QuestDatabaseSO 等) | `BaseGames → Tools → Validate All ScriptableObjects` |
|
||||||
|
|
||||||
> **注意**:PlayModeDebugOverlay 已移除。Geo 注入、技能点测试等请通过 Inspector 直接修改对应 Manager 字段,或临时编写 Editor 脚本触发。
|
> **注意**:PlayModeDebugOverlay 已移除。Geo 注入、能力解锁测试等请通过 Inspector 直接修改对应 SO/Manager 字段,或临时编写 Editor 脚本触发。
|
||||||
> Tab 10 的场景摆放工具(Add Quest Trigger、Add Shop NPC)已不再提供;请参照下方各节**手动步骤**手工创建对应对象。
|
> Tab 10 的场景摆放工具(Add Quest Trigger、Add Shop NPC)已不再提供;请参照下方各节**手动步骤**手工创建对应对象。
|
||||||
|
>
|
||||||
|
> **重要:本项目没有"技能点 + 技能树解锁"系统。** 技能(`FormSkillSO`)随形态绑定,由 `FormController` 在切换形态时注入 `SkillManager`,无需花费技能点解锁;`SkillTreePanel` 仅为只读的形态技能一览面板。能力(二段跳/冲刺/形态等)通过 `AbilityType` 位掩码解锁(见 MT-PROG-06),不涉及任何技能树。
|
||||||
|
|
||||||
**典型工作流**:
|
**典型工作流**:
|
||||||
1. 测试前:`BaseGames → Tools → Validate All ScriptableObjects` 一键确认 SO 存在;若有缺失,Console 给出路径提示。
|
1. 测试前:`BaseGames → Tools → Validate All ScriptableObjects` 一键确认 SO 存在;若有缺失,Console 给出路径提示。
|
||||||
2. `MT-PROG-01` 技能:进入 Play Mode,通过 Inspector 直接修改 `SkillManager._skillPoints` 字段,在技能树 UI 解锁目标技能。
|
2. `MT-PROG-01` 技能:进入 Play Mode,通过 `FormController` 切换形态,确认 `SkillManager` 注入对应形态的三个技能,施放消耗魂力/灵力并进入冷却。
|
||||||
3. `MT-PROG-03` 任务:手动放置 `QuestGiver` NPC(见下方步骤),将 `QuestSO` 拖入 Inspector,Play Mode 中交互验证。
|
3. `MT-PROG-03` 任务:手动放置 `QuestGiver` NPC(见下方步骤),将 `QuestSO` 拖入 Inspector,Play Mode 中交互验证。
|
||||||
4. `MT-PROG-05` 商店:手动放置 `ShopNPC`(见下方步骤),通过 Inspector 修改 `_geo` 字段给玩家加钱,交互购买。
|
4. `MT-PROG-05` 商店:手动放置 `ShopNPC`(见下方步骤),通过 Inspector 修改 `_geo` 字段给玩家加钱,交互购买。
|
||||||
|
|
||||||
@@ -27,7 +29,7 @@
|
|||||||
## 目录
|
## 目录
|
||||||
|
|
||||||
1. [前置数据检查](#1-前置数据检查)
|
1. [前置数据检查](#1-前置数据检查)
|
||||||
2. [MT-PROG-01:技能解锁与使用](#mt-prog-01技能解锁与使用)
|
2. [MT-PROG-01:形态技能与施放](#mt-prog-01形态技能与施放)
|
||||||
3. [MT-PROG-02:装备系统(护符/武器)](#mt-prog-02装备系统护符武器)
|
3. [MT-PROG-02:装备系统(护符/武器)](#mt-prog-02装备系统护符武器)
|
||||||
4. [MT-PROG-03:任务系统(QuestManager)](#mt-prog-03任务系统questmanager)
|
4. [MT-PROG-03:任务系统(QuestManager)](#mt-prog-03任务系统questmanager)
|
||||||
5. [MT-PROG-04:成就系统(AchievementManager)](#mt-prog-04成就系统achievementmanager)
|
5. [MT-PROG-04:成就系统(AchievementManager)](#mt-prog-04成就系统achievementmanager)
|
||||||
@@ -40,7 +42,7 @@
|
|||||||
|
|
||||||
| 资产 | 路径(示例) | 必要性 | ✓ |
|
| 资产 | 路径(示例) | 必要性 | ✓ |
|
||||||
|------|------------|--------|---|
|
|------|------------|--------|---|
|
||||||
| SkillTreeSO | `Assets/Data/Skills/SkillTree.asset` | 技能测试必须 | ☐ |
|
| FormSkillSO ×N | `Assets/_Game/Data/Skills/SKL_*.asset` | 技能测试必须(每形态 3 个:魂技+灵技1+灵技2) | ☐ |
|
||||||
| EquipmentSlotConfigSO | `Assets/Data/Equipment/SlotConfig.asset` | 装备测试必须 | ☐ |
|
| EquipmentSlotConfigSO | `Assets/Data/Equipment/SlotConfig.asset` | 装备测试必须 | ☐ |
|
||||||
| QuestDatabaseSO | `Assets/Data/Quests/` | 任务测试必须 | ☐ |
|
| QuestDatabaseSO | `Assets/Data/Quests/` | 任务测试必须 | ☐ |
|
||||||
| AchievementDatabaseSO | `Assets/Data/Achievements/` | 成就测试必须 | ☐ |
|
| AchievementDatabaseSO | `Assets/Data/Achievements/` | 成就测试必须 | ☐ |
|
||||||
@@ -59,71 +61,85 @@
|
|||||||
>
|
>
|
||||||
> | 资产 | 创建方法 |
|
> | 资产 | 创建方法 |
|
||||||
> |------|----------|
|
> |------|----------|
|
||||||
> | `SkillTreeSO` | Project 右键 → Create → BaseGames → Skills → Skill Tree,保存到 `Assets/_Game/Data/Skills/` |
|
> | `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/` |
|
> | `EquipmentSlotConfigSO` | Project 右键 → Create → BaseGames → Equipment → Slot Config,保存到 `Assets/_Game/Data/Equipment/` |
|
||||||
> | `QuestDatabaseSO` | Project 右键 → Create → BaseGames → Quest → Quest Database,保存到 `Assets/_Game/Data/Quests/` |
|
> | `QuestDatabaseSO` | Project 右键 → Create → BaseGames → Quest → Quest Database,保存到 `Assets/_Game/Data/Quests/` |
|
||||||
> | `AchievementDatabaseSO` | Project 右键 → Create → BaseGames → Progression → Achievement Database,保存到 `Assets/_Game/Data/Achievements/` |
|
> | `AchievementDatabaseSO` | Project 右键 → Create → BaseGames → Progression → Achievement Database,保存到 `Assets/_Game/Data/Achievements/` |
|
||||||
> | `ShopInventorySO` | 已由 Create Test Assets 创建为 `ShopInventory_Test.asset`;点 Inspector 的 `+` 按钮添加 `ShopItem` 条目 |
|
> | `ShopInventorySO` | 已由 Create Test Assets 创建为 `ShopInventory_Test.asset`;点 Inspector 的 `+` 按钮添加 `ShopItem` 条目 |
|
||||||
>
|
>
|
||||||
> **步骤 4 — 绑定 Manager 字段**(Play Mode 前):
|
> **步骤 4 — 绑定 Manager 字段**(Play Mode 前):
|
||||||
> - 找到 `SkillManager` GameObject → Inspector → `_skillTree` 字段拖入 `SkillTree.asset`
|
> - 找到 Player 上的 `SkillManager` 组件 → Inspector → `_formSkillSets` 数组,按形态(天魂/地魂/命魂)逐项填入 `soulSkill` + `spiritSkill1` + `spiritSkill2`(对应 `FormSkillSO` 资产)
|
||||||
> - 找到 `ShopNPC` GameObject(Tab 10 → 添加商店 NPC)→ `_inventory` 字段拖入 `ShopInventory_Test.asset`
|
> - 找到 `ShopNPC` GameObject(Tab 10 → 添加商店 NPC)→ `_inventory` 字段拖入 `ShopInventory_Test.asset`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## MT-PROG-01:技能解锁与使用
|
## MT-PROG-01:形态技能与施放
|
||||||
|
|
||||||
**目的**:验证 `SkillManager` 的技能解锁、技能使用、冷却管理、MP 消耗。
|
**目的**:验证 `SkillManager` 的形态技能注入、技能施放、冷却管理、魂力/灵力消耗,以及 `FormSkillPanel`(只读技能一览)的展示。
|
||||||
|
|
||||||
|
> **架构说明(务必先读)**
|
||||||
|
> - 技能 = `FormSkillSO` 资产,**不通过技能点解锁**。每个形态绑定 3 个技能槽:魂技(`soulSkill`)+ 灵技1(`spiritSkill1`)+ 灵技2(`spiritSkill2`)。
|
||||||
|
> - `FormController` 在切换形态时回调 `SkillManager.UpdateSkillSet(...)`,把当前形态的三个技能注入到输入槽。玩家无须"学习"技能,切到该形态即可用。
|
||||||
|
> - 施放消耗的是**魂力(SoulPower)或灵力(SpiritPower)**(由 `FormSkillSO.resourceType` 决定),不是 MP。
|
||||||
|
> - `FormSkillPanel`(形态技能一览面板)只是只读一览:翻页查看各形态的技能图标/名称/描述/消耗/冷却,**没有解锁交互、没有技能点、没有节点**。
|
||||||
|
> - 技能数值可被护符改写,见 MT-PROG-02 与 `SkillModifierRegistry`。
|
||||||
|
|
||||||
> **🔧 资源准备**
|
> **🔧 资源准备**
|
||||||
> 1. 确认 `SkillTree.asset` 已绑定到 `SkillManager._skillTree` 字段
|
> 1. 确认 Player 上 `SkillManager._formSkillSets` 已为待测形态填好三个 `FormSkillSO`。
|
||||||
> 2. 在 Inspector 中直接将 `SkillManager._skillPoints` 设为 5(Play Mode 下修改字段值)快速获取技能点(跳过进程解锁流程)
|
> 2. 若待测形态尚未解锁(地魂/命魂),先解锁其形态能力:编辑 `PlayerConfigSO.InitialAbilities` 勾选 `FormDiHun` / `FormMingHun`,或临时写 Editor 脚本调用 `PlayerStats.UnlockAbility(AbilityType.FormDiHun)`。天魂(`FormTianHun`)默认初始解锁。
|
||||||
> 3. 若 `SkillManager` 不在场景中,手动在空 GameObject 上挂载 `SkillManager` 组件并绑定 `SkillTree.asset`
|
> 3. 确认输入动作已绑定:魂技 = `SoulSkillEvent`,灵技1 = `SpiritSkill1StartedEvent`,灵技2 = `SpiritSkill2StartedEvent`(见 `InputReaderSO`)。
|
||||||
|
|
||||||
### 步骤
|
### 步骤
|
||||||
|
|
||||||
**步骤 A:技能解锁**
|
**步骤 A:形态切换注入技能**
|
||||||
|
|
||||||
1. 打开技能树 UI(默认 P 键)
|
1. 进入 Play Mode,通过 `FormController` 切换到目标形态(切换输入键,或 Inspector 下调用 `FormController.SwitchForm(FormType.XXX)`)。
|
||||||
2. 确认有足够的技能点(`SkillPoints > 0`)
|
2. 观察 `SkillManager` 的当前技能(`SoulSkill` / `Spirit1` / `Spirit2` 属性)。
|
||||||
3. 点击未解锁的技能节点,确认解锁
|
|
||||||
|
|
||||||
**预期**:
|
**预期**:
|
||||||
- 技能节点视觉变为已解锁状态
|
- 切换形态后,`SkillManager` 的三个技能引用更新为该形态 `_formSkillSets` 中配置的技能。
|
||||||
- `SkillPoints - skillCost`
|
- 冷却字典 `_cooldowns` 重建并清零(切换后立即可施放)。
|
||||||
- `SkillManager.IsUnlocked(skillId) == true`
|
- 若切换的是未解锁形态,`FormController.SwitchForm` 被 `HasAbility(FormXXX)` 拦截,技能集不变。
|
||||||
- 技能快捷键绑定生效
|
|
||||||
|
|
||||||
**步骤 B:技能使用(主动技能)**
|
**步骤 B:技能施放**
|
||||||
|
|
||||||
1. 进入 Play Mode 战斗场景
|
1. 进入战斗场景,按魂技/灵技1/灵技2 输入键。
|
||||||
2. 按已绑定技能快捷键(如 1/2/3 或 Q/E/R)
|
|
||||||
|
|
||||||
**预期**:
|
**预期**:
|
||||||
- 技能动画播放(`AnimancerComponent` 播放技能动画片段)
|
- 技能动画播放(`AnimancerComponent.Play(castAnimation)`)。
|
||||||
- MP 消耗(`CurrentMP -= mpCost`)
|
- 资源扣减:`SoulPower`/`SpiritPower -= effectiveCost`(`PlayerStats.ConsumeSoulPower/ConsumeSpiritPower`)。
|
||||||
- 技能效果触发(伤害、范围、特效)
|
- 命中判定生成(若技能配了 `SkillHitBoxPrefab`,从对象池取实例并 `Activate`)。
|
||||||
- 进入冷却(`cooldown` 秒内无法再次使用)
|
- 进入冷却(`effectiveCooldown` 秒内再次按键无效)。
|
||||||
|
- 触发 `skill_cast` 反馈预设。
|
||||||
|
|
||||||
**步骤 C:MP 不足时**
|
**步骤 C:资源不足时**
|
||||||
|
|
||||||
1. 使 `CurrentMP < skill.mpCost`
|
1. 使当前魂力/灵力 < `effectiveCost`(可在 Inspector 消耗资源或调小上限)。
|
||||||
2. 按技能键
|
2. 按技能键。
|
||||||
|
|
||||||
**预期**:技能无法释放,UI 技能图标显示 MP 不足提示(灰色)。
|
**预期**:`ConsumeXxxPower` 返回 false,技能不释放(无动画、无判定、不进冷却)。
|
||||||
|
|
||||||
**步骤 D:技能冷却**
|
**步骤 D:技能冷却**
|
||||||
|
|
||||||
1. 使用技能后立即再次按技能键
|
1. 施放技能后立即再次按同一技能键。
|
||||||
|
|
||||||
**预期**:冷却期内不触发,UI 冷却进度条显示。
|
**预期**:冷却期内 `_cooldowns[skill] > 0`,不触发;HUD 冷却指示(`SoulCooldownRatio`)显示剩余比例。
|
||||||
|
|
||||||
|
**步骤 E:FormSkillPanel 只读一览**
|
||||||
|
|
||||||
|
1. 打开技能一览面板(`FormSkillPanel`)。
|
||||||
|
2. 左右翻页浏览各形态,确认当前实际形态被高亮(`_activeFormIndicator`)。
|
||||||
|
|
||||||
|
**预期**:面板展示各形态三技能的图标/名称/描述/消耗/冷却;**无任何"解锁/锁定"状态或点击解锁交互**(纯查看)。
|
||||||
|
|
||||||
| 检查点 | 期望 | ✓ |
|
| 检查点 | 期望 | ✓ |
|
||||||
|--------|------|---|
|
|--------|------|---|
|
||||||
| 解锁技能 | 技能节点标记已解锁,SkillPoints 减少 | ☐ |
|
| 形态注入 | 切换形态后 SkillManager 三技能引用随之更新 | ☐ |
|
||||||
| 技能释放 | 动画播放,效果触发,MP 扣减 | ☐ |
|
| 未解锁形态拦截 | 切到未解锁形态被 HasAbility 拦截 | ☐ |
|
||||||
| MP 不足 | 无法释放,UI 提示 | ☐ |
|
| 技能施放 | 动画播放,判定生成,魂力/灵力扣减 | ☐ |
|
||||||
| 冷却 | 冷却期无法再次使用,进度条显示 | ☐ |
|
| 资源不足 | 无法释放,不进冷却 | ☐ |
|
||||||
|
| 冷却 | 冷却期无法再次使用,比例显示 | ☐ |
|
||||||
|
| 一览面板 | 只读展示各形态技能,无解锁交互 | ☐ |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -205,7 +221,7 @@
|
|||||||
**预期**:
|
**预期**:
|
||||||
- `EVT_QuestCompleted` 事件触发
|
- `EVT_QuestCompleted` 事件触发
|
||||||
- 任务移入"已完成"列表
|
- 任务移入"已完成"列表
|
||||||
- 奖励自动发放(Geo/技能点/道具)
|
- 奖励自动发放(Geo/能力解锁/道具)
|
||||||
- 存档文件中 `SaveData.Quests[questId].IsCompleted == true`
|
- 存档文件中 `SaveData.Quests[questId].IsCompleted == true`
|
||||||
|
|
||||||
| 检查点 | 期望 | ✓ |
|
| 检查点 | 期望 | ✓ |
|
||||||
@@ -299,7 +315,7 @@
|
|||||||
|
|
||||||
## MT-PROG-06:能力解锁(AbilityUnlock)
|
## MT-PROG-06:能力解锁(AbilityUnlock)
|
||||||
|
|
||||||
**目的**:验证特殊能力(DoubleJump、WallSlide、Dash 等)的解锁与 `AbilityGate` 联动。
|
**目的**:验证特殊能力(DoubleJump、WallCling、Dash 等 `AbilityType` 位)的解锁与 `AbilityGate` 联动。
|
||||||
|
|
||||||
### 步骤
|
### 步骤
|
||||||
|
|
||||||
@@ -308,9 +324,9 @@
|
|||||||
3. 触发解锁
|
3. 触发解锁
|
||||||
|
|
||||||
**预期**:
|
**预期**:
|
||||||
- `EVT_AbilityUnlocked(abilityId)` 触发
|
- `EVT_AbilityUnlocked(AbilityType)` 触发(`AbilityTypeEventChannelSO`,payload 为解锁的能力位)
|
||||||
- `SkillManager.HasAbility(abilityId) == true`
|
- `PlayerStats.HasAbility(ability) == true`(位掩码 `_unlockedAbilities |= ability`)
|
||||||
- 存档中 `SaveData.Abilities` 包含该 abilityId
|
- 存档中 `SaveData.Player.AbilityFlags` 含该能力位(`(uint)_unlockedAbilities`)
|
||||||
- 对应 `AbilityGate` 自动开启(若当前场景有联动门)
|
- 对应 `AbilityGate` 自动开启(若当前场景有联动门)
|
||||||
|
|
||||||
4. 测试新解锁的能力(如 DoubleJump:跳跃后再次跳跃)
|
4. 测试新解锁的能力(如 DoubleJump:跳跃后再次跳跃)
|
||||||
@@ -320,7 +336,7 @@
|
|||||||
| 检查点 | 期望 | ✓ |
|
| 检查点 | 期望 | ✓ |
|
||||||
|--------|------|---|
|
|--------|------|---|
|
||||||
| 解锁事件 | EVT_AbilityUnlocked 触发 | ☐ |
|
| 解锁事件 | EVT_AbilityUnlocked 触发 | ☐ |
|
||||||
| HasAbility == true | SkillManager 返回 true | ☐ |
|
| HasAbility == true | PlayerStats.HasAbility 返回 true | ☐ |
|
||||||
| AbilityGate 开启 | 对应能力门自动开启 | ☐ |
|
| AbilityGate 开启 | 对应能力门自动开启 | ☐ |
|
||||||
| 能力可用 | 新能力实际可使用 | ☐ |
|
| 能力可用 | 新能力实际可使用 | ☐ |
|
||||||
| 持久化 | 存档中有该 abilityId | ☐ |
|
| 持久化 | 存档 AbilityFlags 含该能力位 | ☐ |
|
||||||
|
|||||||
@@ -126,17 +126,17 @@
|
|||||||
|
|
||||||
## MT-UI-02:UI 面板管理(PanelManager)
|
## MT-UI-02:UI 面板管理(PanelManager)
|
||||||
|
|
||||||
**目的**:验证多个 UI 面板(技能树/装备/任务/暂停)的互斥打开和关闭逻辑。
|
**目的**:验证多个 UI 面板(形态技能一览/装备/任务/暂停)的互斥打开和关闭逻辑。
|
||||||
|
|
||||||
### 步骤
|
### 步骤
|
||||||
|
|
||||||
1. 按技能树快捷键(P)打开技能树面板
|
1. 按形态技能一览快捷键(P)打开 `FormSkillPanel`
|
||||||
|
|
||||||
**预期**:技能树面板打开,游戏暂停(`Time.timeScale = 0`)。
|
**预期**:形态技能一览面板打开,游戏暂停(`Time.timeScale = 0`)。
|
||||||
|
|
||||||
2. 按装备快捷键(Tab)(在技能树面板开启的情况下)
|
2. 按装备快捷键(Tab)(在形态技能一览面板开启的情况下)
|
||||||
|
|
||||||
**预期**:技能树关闭,装备面板打开(面板互斥,不同时显示多个菜单面板)。
|
**预期**:形态技能一览关闭,装备面板打开(面板互斥,不同时显示多个菜单面板)。
|
||||||
|
|
||||||
3. 按 ESC 键
|
3. 按 ESC 键
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user