角色能力,存档

This commit is contained in:
2026-05-19 11:50:21 +08:00
parent d25f237e76
commit 2dcb7a961a
136 changed files with 36035 additions and 27551 deletions

View File

@@ -0,0 +1,937 @@
# 手动测试 13 · 玩家能力与技能系统
> **测试类型**Unity Editor 手动测试Play Mode
> **覆盖模块**`BaseGames.Player`、`BaseGames.Player.States`、`BaseGames.Skills`
> **依赖组件**`PlayerController`、`PlayerMovement`、`PlayerStats`、`PlayerCombat`、`FormController`、`SkillManager`、`SpringSystem`、`ParrySystem`
> **场景要求**:包含玩家 Prefab 的测试场景,至少一块地面平台、一面垂直墙、若干测试用敌人
---
## 快速工具
| 工具 | 用途 | 菜单路径 |
|------|------|----------|
| **Place Player** | 放置完整玩家 GameObject | `BaseGames → Scene → Place → Player` |
| **Place Ground Platform** | 放置地面平台Layer=Ground | `BaseGames → Scene → Place → Ground Platform` |
| **Place Obstacle (Static)** | 放置垂直墙壁(用于抓墙测试) | `BaseGames → Scene → Place → Obstacle (Static)` |
| **Place Test Enemy** | 放置静止测试用敌人(带 HurtBox | `BaseGames → Scene → Place → Test Enemy` |
| **Place Room Camera** | 放置 Cinemachine 相机 | `BaseGames → Scene → Place → Room Camera` |
---
## 场景搭建要求
在运行所有测试前,请确认以下清单:
| 检查项 | 说明 | ✓ |
|--------|------|---|
| 玩家 Prefab 已放置 | 带 `PlayerController``PlayerMovement``PlayerStats``PlayerCombat``FormController``SkillManager``SpringSystem``ParrySystem``HurtBox``AnimancerComponent``WeaponManager` | ☐ |
| 地面平台 | Layer = `Ground`,至少一块宽平台 | ☐ |
| 垂直墙壁 | Layer = `Ground`,高度 ≥ 4 格,用于抓墙/蹬墙跳测试 | ☐ |
| 测试用敌人 | 带 `HurtBox``EnemyBase`,初始静止,用于攻击/Pogo/灵泉充能测试 | ☐ |
| InputReaderSO | 已绑定 `_inputReader` 字段 | ☐ |
| PlayerMovementConfigSO | 已绑定,含跳跃/冲刺/墙壁相关参数 | ☐ |
| PlayerAnimationConfigSO | 已绑定,含所有动画 Clip 资产 | ☐ |
| FormConfigSO | 已绑定到 `FormController._config`,三形态 SO 已配置 | ☐ |
| SkillManager._formSkillSets | Inspector 中已配置三个 `FormSkillSet`,每项指定对应形态的三个技能 SO | ☐ |
| SkillManager._formController | Inspector 中已绑定 `FormController` 引用 | ☐ |
| Physics2D Layer 矩阵 | PlayerHitBox ↔ EnemyHurtBox、Player ↔ Ground 碰撞均已开启 | ☐ |
| Console 无红色 Error | 进入 Play Mode 前 Error = 0 | ☐ |
---
## 目录
1. [MT-ABILITY-01地面三连击与攻击缓冲](#mt-ability-01地面三连击与攻击缓冲)
2. [MT-ABILITY-02上劈地面 / 空中)](#mt-ability-02上劈地面--空中)
3. [MT-ABILITY-03下劈与 Pogo 弹起](#mt-ability-03下劈与-pogo-弹起)
4. [MT-ABILITY-04空中水平攻击](#mt-ability-04空中水平攻击)
5. [MT-ABILITY-05攻击取消窗口](#mt-ability-05攻击取消窗口)
6. [MT-ABILITY-06抓墙与高度记忆机制](#mt-ability-06抓墙与高度记忆机制)
7. [MT-ABILITY-07蹬墙跳背墙跳 / 对墙跳)](#mt-ability-07蹬墙跳背墙跳--对墙跳)
8. [MT-ABILITY-08二段跳](#mt-ability-08二段跳)
9. [MT-ABILITY-09无敌冲刺](#mt-ability-09无敌冲刺)
10. [MT-ABILITY-10三形态切换](#mt-ability-10三形态切换)
11. [MT-ABILITY-11三套资源系统](#mt-ability-11三套资源系统)
12. [MT-ABILITY-12灵泉使用](#mt-ability-12灵泉使用)
13. [MT-ABILITY-13灵泉充能击杀积累](#mt-ability-13灵泉充能击杀积累)
14. [MT-ABILITY-14魂技能施放](#mt-ability-14魂技能施放)
15. [MT-ABILITY-15魄技能施放技能 1 / 2](#mt-ability-15魄技能施放技能-1--2)
16. [MT-ABILITY-16弹反系统](#mt-ability-16弹反系统)
---
## MT-ABILITY-01地面三连击与攻击缓冲
**目的**:验证地面三段连击的前摇/有效帧/后摇三阶段、HitBox 激活时序、攻击缓冲机制。
### 前置条件
- 玩家站于地面
- 在玩家攻击范围内放置测试用敌人
### 步骤 A三段连击完整触发
1. 进入 Play Mode
2. 玩家站立地面,按 **Attack 键**(默认 `J`
**预期**
- 播放第 1 段攻击动画(`AnimationConfigSO.GroundAttacks[0]`
- 动画前摇结束时 HitBox 激活(可在 Scene 视图 Gizmos 中观察 HitBox 矩形出现)
- 命中敌人后敌人 HP 减少,玩家方向上有微小横向反嵈位移
3. 动画进入后摇阶段后(有效帧结束),再次按 **Attack 键**
**预期**
- 无缝衔接第 2 段攻击动画(`GroundAttacks[1]`
- 第 2 段 HitBox 重新激活
4. 同样方式触发第 3 段
**预期**
- 播放 `GroundAttacks[2]`,第三段攻击完成后动画自然结束
- 玩家返回 `IdleState``RunState`
### 步骤 B攻击缓冲后摇内预输入
1. 按下 **Attack 键** 触发第 1 段攻击
2. **在后摇期间**(有效帧结束前后)提前再次按 **Attack 键**
**预期**
- 第 1 段后摇结束后**自动**衔接第 2 段,无需再次按键
- 缓冲窗口内的输入被 `InputBuffer` 记录并消耗
### 步骤 C攻击中断复位
1. 第 1 段攻击完成后等待后摇完全结束(约 1.5 秒不操作)
2. 再次按 **Attack 键**
**预期**
- 从第 1 段重新开始,而非继续第 2 段(连击计数已重置)
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 三段动画各不相同 | 三段 Clip 依次切换 | ☐ |
| HitBox 仅在有效帧激活 | 前摇期间无碰撞Gizmos 不显示 HitBox | ☐ |
| 命中反嵈 | 命中敌人时玩家微小位移(打击感) | ☐ |
| 攻击缓冲生效 | 后摇内按键可自动续接下一段 | ☐ |
| 连击计数超时重置 | 久未续接后从第 1 段重新开始 | ☐ |
| Console 无 Error | 0 个红色 Error | ☐ |
---
## MT-ABILITY-02上劈地面 / 空中)
**目的**验证上劈的组合键判定Move Y 轴正向 + Attack、向上 HitBox 激活、空中向下反嵈。
### 前置条件
- 在玩家正上方位置放置测试用敌人(调高 Y 坐标)
### 步骤 A地面上劈
1. 玩家站立地面
2. 按住 **Move 上方向键**`W` 或上方向键Y 轴正向),同时按 **Attack 键**
**预期**
- 触发上劈动画(`AnimationConfigSO.UpAttack` 对应 Clip
- HitBox 在角色**正上方**激活Scene 视图 Gizmos 可见)
- 命中正上方敌人,敌人 HP 减少
- 玩家仍停留地面,无明显上移(地面上劈无空中反嵈)
### 步骤 B空中上劈与向下反嵈
1. 跳跃至空中
2. 在空中按住 **Move 上方向键** + **Attack 键**
**预期**
- 触发上劈动画
- **玩家 Y 轴速度减少约 3向下反嵈**,可在 Inspector → `Rigidbody2D.velocity.y` 观察到短暂下移
- 上劈动画结束后进入 `FallState`
- 命中敌人后敌人 HP 减少
### 步骤 CMove Y 阈值边界
1. 空中仅按轻推上方向Y 轴输入 < 0.5),同时按 **Attack 键**
**预期**
- 触发普通空中水平攻击而非上劈Y 阈值未达到 0.5 不判定为上劈)
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 地面上劈 HitBox 在上方 | Scene Gizmos 可见上方碰撞盒 | ☐ |
| 空中上劈向下反嵈 | velocity.y 降低约 3玩家微向下位移 | ☐ |
| Y 轴阈值正确 | 轻推不触发上劈 | ☐ |
| 动画正确 | 播放上劈专属 Clip | ☐ |
---
## MT-ABILITY-03下劈与 Pogo 弹起
**目的**:验证下劈仅限空中触发、向下速度施加、命中 Pogo 弹起机制(重置空中能力)、未命中继续下落。
### 前置条件
- 玩家位于测试敌人正上方(高度 ≥ 3 格)
- 测试敌人带有 `HurtBox` 组件
### 步骤 A空中下劈命中 Pogo
1. 跳跃至测试敌人正上方
2. 按住 **Move 下方向键**`S` 或下方向键Y 轴负向),同时按 **Attack 键**
**预期**
- 触发下劈动画(`AnimationConfigSO.DownAttack` 对应 Clip
- 玩家 Y 轴速度被设为约 `-18`,快速向下冲击
- 下方 HitBox 激活
- **命中敌人后**:玩家立即向上弹起(`Pogo Jump`,高度固定),与普通跳跃力度相似
- Pogo 触发后空中冲刺次数重置(`_airDashUsed = false`
- Pogo 触发后空中跳跃次数重置(`AirJumpsLeft` 恢复为最大值)
### 步骤 B空中下劈未命中
1. 在空旷区域(无敌人/无特殊物体)跳跃
2. 空中使用下劈
**预期**
- 下劈动画和向下速度正常
- **未命中任何目标**:玩家**不弹起**,继续受重力下落至地面
- 落地后进入 `IdleState`
### 步骤 C地面下劈无效
1. 玩家站立地面
2. 按住 **Move 下方向键** + **Attack 键**
**预期**
- **触发普通地面水平攻击**(或无响应),不触发下劈
- 下劈判定限制在空中状态 `!IsGrounded`
### 步骤 DPogo 后续接二段跳
1. 解锁二段跳(`PlayerStats.UnlockAbility(AbilityType.DoubleJump)`,可在 Inspector 勾选)
2. 空中下劈命中 Pogo 弹起
3. 弹起途中按 **Jump 键**
**预期**
- Pogo 重置空中跳跃次数,可再次使用二段跳
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 仅限空中触发 | 地面不触发下劈 | ☐ |
| 向下冲击速度 | velocity.y ≈ -18 | ☐ |
| 命中 Pogo 弹起 | 玩家向上弹起,高度固定 | ☐ |
| Pogo 重置冲刺次数 | Pogo 后可再次空中冲刺 | ☐ |
| Pogo 重置跳跃次数 | Pogo 后可再次二段跳(已解锁时) | ☐ |
| 未命中不弹起 | 继续下落至地面 | ☐ |
---
## MT-ABILITY-04空中水平攻击
**目的**:验证空中水平攻击(`AirAttackState`)的触发条件、单次攻击、动画、结束返回 FallState。
### 步骤 A空中普通攻击
1. 跳跃至空中
2.**Attack 键**不按方向或左右方向Y 轴绝对值 < 0.5
**预期**
- 触发空中水平攻击动画(`AnimationConfigSO.AirAttack`
- HitBox 在角色侧面激活(`AttackDirection.Air`
- 动画完成后进入 `FallState`,继续下落
- 命中敌人 HP 减少
### 步骤 B空中攻击不循环
1. 空中连续多次按 **Attack 键**
**预期**
- 空中攻击为单次,不进行连段
- 每次须等动画结束后重新输入才能再次攻击
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 触发空中攻击动画 | 播放 AirAttack Clip | ☐ |
| HitBox 侧面激活 | Scene Gizmos 可见侧面碰撞盒 | ☐ |
| 结束后 FallState | 攻击完成后继续下落,不卡住 | ☐ |
| 单次不循环 | 无法连续多段空中攻击 | ☐ |
---
## MT-ABILITY-05攻击取消窗口
**目的**:验证攻击后摇期间的取消窗口允许通过跳跃/冲刺打断攻击动作。
### 步骤 A攻击后跳跃取消
1. 地面攻击触发第 1 段
2. 在**有效帧结束后、后摇结束前**(取消窗口期间)按 **Jump 键**
**预期**
- 立即从 `AttackState` 转入 `JumpState`
- 不必等待后摇完全结束即可起跳
- 取消窗口关闭后(后摇末尾)按 Jump 则无法打断
### 步骤 B攻击后冲刺取消
1. 地面攻击触发第 1 段
2. 在取消窗口期间按 **Dash 键**
**预期**
- 立即进入 `DashState`,打断后摇
### 步骤 C取消窗口外不可取消
1. 地面攻击触发第 1 段
2. 在**前摇期间**(有效帧之前)按 **Jump 键**
**预期**
- 跳跃**无效**,必须等待取消窗口开放后才可取消
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 取消窗口内可跳跃 | Jump 立即打断后摇 | ☐ |
| 取消窗口内可冲刺 | Dash 立即打断后摇 | ☐ |
| 前摇内无法取消 | Jump/Dash 在前摇期间无响应 | ☐ |
---
## MT-ABILITY-06抓墙与高度记忆机制
**目的**:验证触发条件、无需持续按键维持、高度记忆防无限攀爬逻辑(正常模式静止 / 受限模式下滑)。
### 前置条件
- 在玩家右侧放置高度 ≥ 6 格的垂直墙壁Layer=Ground
### 步骤 A基本抓墙触发
1. 向右跳跃,在空中接触右侧墙壁
2. 按住 **Move 右方向键**朝向墙壁方向X 轴正向)
**预期**
- 进入 `WallSlideState`
- 播放抓墙动画
- **松开方向键**后角色仍保持抓墙状态(无需持续按键)
### 步骤 B主动松墙
1. 抓墙状态下按下 **Move 左方向键**(反方向键)
**预期**
- 立即解除抓墙,进入 `FallState`
### 步骤 C正常模式抓墙高度 ≤ wallGrabY—— 静止悬挂
1. 跳跃至墙壁中部,触发抓墙(记录 `wallGrabY`
2. 松开方向键,观察角色是否移动
**预期**
- 角色**静止悬挂**Y 坐标不变
- 可以在此状态触发蹬墙跳
### 步骤 D受限模式抓墙高度 > wallGrabY—— 持续下滑且无法蹬墙跳
1. 在 C 的基础上,直接跳跃后**更高处再次贴墙**(同一面墙,但 Y 坐标高于 `wallGrabY`
2. 触发抓墙,松开方向键
**预期**
- 角色**持续向下滑动**(受限模式)
- **无法触发蹬墙跳**(按 Jump 键无效)
> **💡 操作技巧**:从地面站立后直接跳上更高位置并贴墙,此时 Y > wallGrabY因为上一次落地已重置也可以先蹬墙跳到更高处再贴同一面墙来制造 Y > wallGrabY 的情况。
### 步骤 E落地重置 wallGrabY
1. 完成 C 的抓墙后蹬墙跳离墙,落地
2. 再次跳跃贴同一面墙(高度与 C 中相同)
**预期**
- 落地后 `wallGrabY` 已重置,该高度重新进入**正常模式**(静止悬挂,可蹬墙跳)
### 步骤 F贴另一面墙重置 wallGrabY
1. 在步骤 C 中抓右侧墙壁后,蹬墙跳至左侧墙壁
2. 在左侧墙壁比之前更高处抓墙
**预期**
- 切换到另一面墙壁时 `wallGrabY` 重置为新值
- 该高度为正常模式(可静止,可蹬墙跳)
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 朝墙方向键触发抓墙 | 接触墙 + 朝墙输入 → WallSlideState | ☐ |
| 无需持续按键 | 松开方向键后仍保持抓墙 | ☐ |
| 反向键松墙 | FallState | ☐ |
| 正常模式静止 | Y 坐标不变,不下滑 | ☐ |
| 受限模式下滑 | 高于 wallGrabY 时持续下滑 | ☐ |
| 受限模式无蹬墙跳 | Jump 键在受限模式无效 | ☐ |
| 落地重置 | 落地后 wallGrabY 清零 | ☐ |
| 换墙重置 | 抓另一面墙时记录新 wallGrabY | ☐ |
---
## MT-ABILITY-07蹬墙跳背墙跳 / 对墙跳)
**目的**验证背墙跳Away和对墙跳Toward的方向判定与施力、视为第一段跳、可变高度支持。
### 前置条件
- 玩家处于正常抓墙状态(高度 ≤ wallGrabY可触发蹬墙跳
### 步骤 A背墙跳Away Jump
1. 抓右侧墙壁,**不按任何水平方向键**(或按左键,即反方向)
2.**Jump 键**
**预期**
- 玩家朝**远离右墙方向**弹出(向左上方),播放 WallJumpAway 动画
- 弹出后有约 0.2-0.3 秒的水平输入锁定(`_inputLockTimer`),锁定结束后可自由控制水平方向
- `AirJumpsLeft` 恢复(视为第一段跳)
### 步骤 B对墙跳Toward Jump
1. 抓右侧墙壁,按住 **Move 右方向键**(朝墙方向)
2.**Jump 键**
**预期**
- 玩家朝**朝向右墙方向弹出**(向右上方),施力偏向竖直,水平分量较小
- 播放 WallJumpToward 动画
- 同样视为第一段跳,`AirJumpsLeft` 恢复
### 步骤 C蹬墙跳后可接二段跳已解锁时
1. 背墙跳后,在空中再次按 **Jump 键**
**预期**
- 若已解锁二段跳,此时可触发二段跳(`AirJumpsLeft > 0`
- 若未解锁,按 Jump 无效
### 步骤 D蹬墙跳可变高度
1. 背墙跳后立即松开 **Jump 键**
**预期**
- 跳跃高度降低(同普通跳跃可变高度,提前松键截断上升速度)
### 步骤 E受限模式下无蹬墙跳
1. 使玩家抓墙高度 > wallGrabY受限模式
2.**Jump 键**
**预期**
- 蹬墙跳不触发(按 Jump 在受限模式无反应)
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 背墙跳方向正确 | 远离墙壁斜上方弹出 | ☐ |
| 对墙跳方向正确 | 朝墙壁斜上方弹出,更偏垂直 | ☐ |
| 输入锁定(背墙跳) | 弹出后短时无法控制水平方向 | ☐ |
| 视为第一段跳 | AirJumpsLeft 重置 | ☐ |
| 可接二段跳 | 蹬墙跳后可再次按 Jump已解锁 | ☐ |
| 可变高度 | 提前松键降低弹跳高度 | ☐ |
| 受限模式无效 | 受限抓墙时 Jump 无响应 | ☐ |
---
## MT-ABILITY-08二段跳
**目的**:验证二段跳的解锁门控、空中二次起跳、高度低于一段跳、可变高度支持。
### 前置条件
-`PlayerStats` Inspector 中确认 `AbilityType.DoubleJump` 是否已解锁
- **步骤 A 使用未解锁状态,步骤 B 及以后需先解锁**
### 步骤 A未解锁时空中 Jump 无效
1. 确认二段跳**未解锁**`AbilityFlags` 中无 `DoubleJump`
2. 跳跃至空中
3. 在下落途中按 **Jump 键**
**预期**
- Jump 无效,不产生二次跳跃
### 步骤 B解锁后空中二段跳
1. 在 Inspector 中勾选 `DoubleJump` 解锁(或调用 `Stats.UnlockAbility(DoubleJump)` 通过 Console
2. 跳跃至空中,在最高点前或下落时按 **Jump 键**
**预期**
- 触发二段跳动画(`DoubleJump` Clip
- 玩家再次向上弹起,高度明显低于一段跳
- `AirJumpsLeft` 由 1 减为 0
3. 二段跳后再次按 **Jump 键**
**预期**
- 无响应(`AirJumpsLeft == 0`,无更多空中跳跃机会)
### 步骤 C二段跳可变高度
1. 二段跳后立即松开 **Jump 键**
**预期**
- 跳跃高度降低(提前松键截断上升速度)
### 步骤 D落地重置二段跳次数
1. 使用二段跳后落地
2. 再次跳跃,在空中按 **Jump 键**
**预期**
- `AirJumpsLeft` 已重置(落地时 `ResetAirJumps()` 调用),可再次使用二段跳
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 未解锁时无效 | 空中 Jump 无响应 | ☐ |
| 解锁后可二段跳 | 空中第二次 Jump 触发 | ☐ |
| 二段跳高度低于一段 | 弹起高度明显更低 | ☐ |
| 二段跳次数限制 | 第三次 Jump 无响应 | ☐ |
| 可变高度 | 提前松键降低高度 | ☐ |
| 落地后重置 | 落地后可再次二段跳 | ☐ |
---
## MT-ABILITY-09无敌冲刺
**目的**:验证无敌冲刺的解锁门控、冲刺期间无敌帧(不受伤害)、独立冷却机制。
### 前置条件
-`PlayerStats` Inspector 中确认 `AbilityType.InvincibleDash` 是否已解锁
- 在测试场景中放置一个会持续攻击的测试敌人(或使用调试工具手动给玩家造成伤害)
### 步骤 A未解锁时冲刺无无敌帧
1. 确认无敌冲刺**未解锁**
2. 在敌人攻击范围内进行冲刺
**预期**
- 冲刺期间受到伤害,进入 `HurtState`(基础冲刺无无敌帧)
### 步骤 B解锁后冲刺无敌帧
1. 解锁 `InvincibleDash`
2. 在敌人攻击方向上冲刺穿越
**预期**
- 冲刺期间**不受伤害**`Stats.IsInvincible == true` 持续 `DashInvincibilityDuration` 约 0.20s
- 无敌期间 Inspector 中 `IsInvincible` 字段为 true
- 无敌帧结束后恢复正常受伤判定
### 步骤 C无敌冲刺独立冷却
1. 无敌冲刺后立即再次冲刺
**预期**
- 第 2 次冲刺可正常触发(冲刺本身冷却 ≈ 0.4s
- 但第 2 次冲刺**无无敌帧**(无敌帧有独立冷却,需等待更长时间恢复)
- Inspector 中 `_invincibilityCooldownTimer > 0` 时不授予无敌
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 未解锁无无敌 | 冲刺中受伤进入 HurtState | ☐ |
| 解锁后有无敌帧 | 冲刺期间 IsInvincible=true不受伤 | ☐ |
| 无敌帧持续时间 | 约 0.20s 后 IsInvincible 变 false | ☐ |
| 独立冷却 | 短时间内第 2 次冲刺无无敌帧 | ☐ |
---
## MT-ABILITY-10三形态切换
**目的**:验证三形态切换的输入响应、武器/动画随形态更新、技能集随形态更新。
### 前置条件
- `FormConfigSO` 中三个 FormSO天魂/地魂/命魂)已配置,各有不同武器 Prefab
- `SkillManager._formSkillSets` 数组已填写三形态对应的技能 SO
- `WeaponManager` 已绑定 `FormController`
### 步骤 A切换至天魂SwitchSkyForm
1. 进入 Play Mode玩家默认形态
2.**SwitchSkyForm 键**(默认 `1`
**预期**
- `FormController.CurrentForm.formType == TianHun`
- 武器切换到天魂武器 Prefab`WeaponManager.ActiveWeapon` 更新)
- `SkillManager``_soulSkill``_spirit1``_spirit2` 替换为天魂对应技能
- HUD 形态颜色/图标更新(若已实现 UI 订阅)
- Console 无 Error
### 步骤 B切换至地魂SwitchEarthForm
1.**SwitchEarthForm 键**(默认 `2`
**预期**:同 A武器和技能集更换为地魂版本。
### 步骤 C切换至命魂SwitchDeathForm
1.**SwitchDeathForm 键**(默认 `3`
**预期**:同 A武器和技能集更换为命魂版本。
### 步骤 D切换后攻击使用新武器
1. 切换形态后立即攻击
**预期**
- HitBox 来自新形态武器实例
- 伤害值使用新形态武器 `WeaponSO.Damage`
### 步骤 E重复切换同一形态
1. 当前已在天魂,再次按 **SwitchSkyForm 键**
**预期**
- 无副作用(不重复切换,也不报错)
- `OnFormChanged` 事件视实现可能不触发(取决于 `FormController` 是否有相同形态判断)
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 形态正确更新 | CurrentForm.formType 对应键值 | ☐ |
| 武器随形态切换 | WeaponManager.ActiveWeapon 更新 | ☐ |
| 技能集随形态切换 | SkillManager _soulSkill/_spirit1/_spirit2 更新 | ☐ |
| 攻击使用新武器 | 新武器 HitBox 生效 | ☐ |
| Console 无 Error | 0 个红色 Error | ☐ |
---
## MT-ABILITY-11三套资源系统
**目的**:验证灵力、魄元、灵泉次数三者相互独立、各自消耗/恢复逻辑。
### 步骤 A灵力SoulPower—— 攻击积累
1. 在 Inspector 中观察 `PlayerStats._currentSoulPower`(初始 = 0
2. 攻击命中测试敌人多次
**预期**
- 每次命中后 `_currentSoulPower` 增加
- 不影响 `_currentSpiritPower``_currentSpringCharges`
3. 消耗至 0触发魂技能见 MT-ABILITY-14
**预期**
- `_currentSoulPower` 降低
- `_currentSpiritPower` 不变
### 步骤 B魄元SpiritPower—— 时间恢复
1. 使 `_currentSpiritPower` 低于上限(触发魄技能消耗)
2. 等待约 3 秒
**预期**
- `_currentSpiritPower` 每秒自动增加(`SpiritRegenRate` 配置值)
- 不影响 `_currentSoulPower``_currentSpringCharges`
### 步骤 C灵泉次数SpringCharges—— 三者独立
1. 攻击积累灵力,同时魄元自然恢复,灵泉次数保持不变
**预期**
- 三个字段**完全独立变动**,互无影响
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 灵力随攻击命中增加 | 每次命中 SoulPower 增加 | ☐ |
| 魄元随时间自动恢复 | 未满时 SpiritPower 逐秒增加 | ☐ |
| 三者独立 | 任一变化不影响其他两项 | ☐ |
---
## MT-ABILITY-12灵泉使用
**目的**:验证灵泉使用的前置条件(地面 + 有充能、HP 恢复、Overlay 动画、充能消耗。
### 前置条件
- `PlayerStats._currentSpringCharges > 0`(至少 1 次充能)
- 玩家 HP 不满(降低 HP 以观察回复效果)
### 步骤 A地面使用灵泉
1. 玩家站立地面(`IsGrounded == true`
2. HP 低于上限
3.**UseSpring 键**(默认 `E`
**预期**
- 播放 Overlay 动画Layer 1 叠加于 Base Layer 之上),不打断移动动画
- `_currentSpringCharges` 减少 1
- `PlayerStats.CurrentHP` 增加(`SpringHealAmount` 配置值)
- 动画结束后玩家返回正常状态
### 步骤 B空中使用灵泉无效
1. 跳跃至空中(`IsGrounded == false`
2.**UseSpring 键**
**预期**
- **无响应**`OnUseSpring` 检测到非地面,直接返回)
### 步骤 C充能为 0 时无效
1. 确认 `_currentSpringCharges == 0`
2. 地面按 **UseSpring 键**
**预期**
- **无响应**(充能为 0 时不进入 `SpringState`
### 步骤 DOverlay 动画不打断移动
1. 地面移动中按 **UseSpring 键**
**预期**
- 使用灵泉 Overlay 动画在 Layer 1 播放
- 玩家可继续移动Layer 0 移动动画继续)
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 地面使用成功 | HP 增加ChargesCount 减 1 | ☐ |
| 空中无效 | 空中按键无任何响应 | ☐ |
| 充能为 0 无效 | 无充能时按键无响应 | ☐ |
| Overlay 动画叠加 | Layer 1 动画播放Layer 0 不中断 | ☐ |
---
## MT-ABILITY-13灵泉充能击杀积累
**目的**:验证 `SpringSystem` 通过 EVT_EnemyDied 事件积累点数、达到阈值后自动增加灵泉次数。
### 前置条件
- 场景内有可被击杀的测试敌人
- `SpringSystem` 组件挂在玩家或管理器 GameObject 上,`_onEnemyDied` 字段已绑定 `EVT_EnemyDied` SO 事件资产
- 在 Inspector 中调低 `PlayerStatsSO.SpringKillThreshold`(如设为 2以方便观察
### 步骤 A击杀积累点数
1. 攻击并击杀第 1 个测试敌人
**预期**
- EVT_EnemyDied 事件触发
- `PlayerStats._springKillPoints` 增加 1可在 Inspector 观察)
2. 再次击杀一个敌人
**预期**
- `_springKillPoints` 增加至阈值
- 自动调用 `RestoreSpringCharges(1)``_currentSpringCharges` 增加 1
- `_springKillPoints` 清零
### 步骤 B充能上限限制
1.`_currentSpringCharges` 调至上限(`MaxSpringCharges`
2. 继续击杀敌人
**预期**
- `_springKillPoints` 继续积累
-`_currentSpringCharges == MaxSpringCharges` 时,`RestoreSpringCharges` 不超过上限
### 步骤 C存档点恢复次数至上限
1. 消耗 1 次灵泉
2. 与测试场景中的存档点 GameObject 交互(或调用 `Stats.RestoreOnSave()`
**预期**
- `_currentSpringCharges` 恢复至 `MaxSpringCharges`
- `_springKillPoints` 清零(存档点重置积累点)
| 检查点 | 期望 | ✓ |
|--------|------|---|
| EVT_EnemyDied 触发点数积累 | 击杀后 _springKillPoints 增加 | ☐ |
| 达阈值自动 +1 次充能 | 积累满后 ChargesCount 增加,点数清零 | ☐ |
| 充能不超上限 | MaxSpringCharges 限制 | ☐ |
| 存档点恢复至上限 | ChargesCount = MaxSpringCharges | ☐ |
---
## MT-ABILITY-14魂技能施放
**目的**:验证 `SkillManager` 响应 SoulSkill 输入、消耗灵力、播放技能动画、冷却限制。
### 前置条件
- 当前形态已配置 `FormSkillSet.soulSkill`(有效的 `FormSkillSO` 资产)
- `PlayerStats._currentSoulPower` 达到技能消耗量以上
### 步骤 A灵力充足时施放魂技能
1. 攻击敌人积累足够灵力(`_currentSoulPower ≥ soulSkill.Cost`
2.**SoulSkill 键**(默认 `Q`
**预期**
- 技能动画播放(`FormSkillSO.animationClip`
- `_currentSoulPower` 减少 `soulSkill.Cost`
- 技能特效实例化(若 `FormSkillSO` 中配置了 VFX
- 技能进入冷却(`_cooldowns[soulSkill]` 开始计时)
### 步骤 B冷却中无法再次施放
1. 技能施放后立即再次按 **SoulSkill 键**
**预期**
- 无响应(冷却剩余 `> 0` 时拒绝施放)
### 步骤 C灵力不足时无法施放
1. `_currentSoulPower < soulSkill.Cost`(可通过消耗后立即尝试)
2.**SoulSkill 键**
**预期**
- 无响应(灵力不足,`SkillManager` 内部判断拒绝)
### 步骤 D形态切换后技能变更
1. 切换到另一个形态
2.**SoulSkill 键**
**预期**
- 施放的是**新形态**的魂技能(不同动画、不同效果)
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 灵力充足时施放成功 | 动画播放SoulPower 减少 | ☐ |
| 冷却中无法施放 | 再次按键无响应 | ☐ |
| 灵力不足无法施放 | 资源不足时无响应 | ☐ |
| 形态切换后使用新技能 | 切换形态后施放新形态魂技能 | ☐ |
---
## MT-ABILITY-15魄技能施放技能 1 / 2
**目的**:验证 `SpiritSkill1`/`SpiritSkill2` 的消耗魄元、独立冷却、形态切换更新。
### 前置条件
- 当前形态已配置 `FormSkillSet.spiritSkill1``spiritSkill2`
- `PlayerStats._currentSpiritPower` 充足
### 步骤 A施放魄技能 1
1.**SpiritSkill1 键**(默认 `R`,长按触发 Start松开触发 Cancelled
**预期**
- 技能动画播放
- `_currentSpiritPower` 减少 `spiritSkill1.Cost`
- 若技能为蓄力型,按住触发蓄力动画,松开触发释放
### 步骤 B施放魄技能 2
1.**SpiritSkill2 键**(默认 `F`
**预期**
- 施放魄技能 2不同动画/效果)
- 消耗独立的魄元量(`spiritSkill2.Cost`
### 步骤 C技能 1 和技能 2 冷却独立
1. 依次施放技能 1 和技能 2
**预期**
- 技能 1 冷却中**不影响**技能 2 的施放(`_cooldowns` 字典各自独立计时)
### 步骤 D魄元自动恢复后可再次施放
1. 魄技能消耗魄元后等待恢复
2. 再次施放
**预期**
- 魄元恢复至足够后可再次施放(`SpiritRegenRate` 自动回复)
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 技能 1 施放成功 | 动画播放SpiritPower 减少 | ☐ |
| 技能 2 施放成功 | 不同动画SpiritPower 减少 | ☐ |
| 冷却独立 | 技能 1 冷却不阻止技能 2 | ☐ |
| 形态切换后使用新技能 | 新形态的魄技能 1/2 生效 | ☐ |
| 魄元恢复后可再施放 | 等待后 SpiritPower 恢复,可用 | ☐ |
---
## MT-ABILITY-16弹反系统
**目的**:验证 `ParrySystem`/`ParryState` 的触发窗口、弹反成功判定、灵力奖励、护盾恢复。
### 前置条件
- 场景中有能发动近战攻击的测试敌人(或使用 Debug 工具手动触发弹反机会)
- `ParrySystem` 已绑定 `InputReaderSO`
- `ShieldComponent` 已配置(若需验证护盾恢复)
### 步骤 A弹反触发与成功
1. 敌人发起攻击时,在攻击即将命中前按下**弹反键**`Parry`,默认 `K`
**预期**
- 进入 `ParryState`,播放弹反动画
- 若在弹反窗口内成功拦截敌人攻击:
- 弹反命中判定成功,敌人受到弹反反馈(硬直或被弹飞)
- `PlayerStats._currentSoulPower` 增加(`ParryInfo.SoulGained`
- `ShieldComponent.OnParrySuccess()` 调用(护盾恢复)
- 玩家**不受任何伤害**(弹反期间有效)
### 步骤 B弹反窗口外受伤
1. 弹反动画开始后**等待窗口结束**(约 0.2-0.3s 后),此时再受到敌人攻击
**预期**
- 玩家正常受伤,进入 `HurtState`(弹反窗口已关闭)
### 步骤 C空弹反无敌人攻击
1. 地面不受攻击时按弹反键
**预期**
- 播放弹反动画
- 弹反窗口结束后自动返回 `IdleState`
- 无报错,无副作用
| 检查点 | 期望 | ✓ |
|--------|------|---|
| 弹反动画播放 | ParryState 正确进入 | ☐ |
| 弹反成功不受伤 | 窗口内拦截,玩家 HP 不减少 | ☐ |
| 灵力奖励 | SoulPower 增加 SoulGained 值 | ☐ |
| 护盾恢复 | ShieldComponent.OnParrySuccess 调用 | ☐ |
| 窗口外受伤 | 窗口关闭后受攻击进入 HurtState | ☐ |
| 空弹反无副作用 | 无敌人攻击时弹反后正常返回 Idle | ☐ |
---
## 附录 AInspector 调试辅助字段
以下字段在 Play Mode 下可在 Inspector 中实时观察,便于调试:
| GameObject | 组件 | 字段 | 含义 |
|-----------|------|------|------|
| Player | `PlayerController` | `_dbg_CurrentState` | 当前 FSM 状态名 |
| Player | `PlayerController` | `_dbg_IsGrounded` | 是否落地 |
| Player | `PlayerController` | `_dbg_AirJumpsLeft` | 剩余空中跳跃次数 |
| Player | `PlayerController` | `_dbg_CanDash` | 当前是否可冲刺 |
| Player | `PlayerController` | `_dbg_IsInvincible` | 当前是否无敌 |
| Player | `PlayerStats` | `_currentHP` | 当前 HP |
| Player | `PlayerStats` | `_currentSoulPower` | 当前灵力 |
| Player | `PlayerStats` | `_currentSpiritPower` | 当前魄元 |
| Player | `PlayerStats` | `_currentSpringCharges` | 当前灵泉次数 |
| Player | `PlayerStats` | `_springKillPoints` | 当前灵泉积累点 |
| Player | `FormController` | `CurrentForm` | 当前形态 SO |
| Player | `SkillManager` | `_soulSkill` | 当前魂技能 |
| Player | `SkillManager` | `_spirit1` | 当前魄技能 1 |
| Player | `SkillManager` | `_spirit2` | 当前魄技能 2 |
---
## 附录 B常见问题排查
| 问题现象 | 可能原因 | 排查步骤 |
|---------|---------|---------|
| 攻击无 HitBox 效果 | WeaponManager 武器未实例化 | Inspector 检查 `WeaponManager.ActiveHitBoxInstance` 是否为 null |
| 形态切换后技能未更新 | `SkillManager._formController` 未赋值 | 确认 Inspector 中已拖入 `FormController` 引用,并检查 `_formSkillSets` 数组长度 ≥ 3 |
| 灵泉使用无响应 | `UseSpringEvent` 未绑定 | 检查 `InputReaderSO` 中 UseSpring Action 名称拼写,确认 PlayerController 已订阅 |
| 抓墙后立即滑落 | WallDetector 未检测到墙 | 检查墙壁 Layer 是否为 `Ground``PlayerWallDetector``wallLayer` 掩码包含该 Layer |
| 蹬墙跳无效 | 受限模式(高于 wallGrabY | 在受限模式(下滑状态)时蹬墙跳设计上不可用,属预期行为 |
| 魄技能冷却独立验证失败 | 技能 SO 资产共用同一实例 | 确认技能 1、技能 2 使用的是**不同** `FormSkillSO` 资产(不同 `.asset` 文件) |
| Pogo 未弹起 | DownAttackState `OnDownHitConfirmed` 未订阅 | 检查 `PlayerCombat._currentHitBoxInstance` 是否正确订阅Console 查看 `HandleWeaponChanged` 是否调用 |
| Console 出现 NullReferenceException | Inspector 中某 SO/组件字段未赋值 | 运行时在 `PlayerController.Awake``Debug.Assert` 输出中查看具体缺失字段 |