Files
zeling_v2/Docs/Verification/13_Manual_PlayerAbilities_Skills.md
2026-05-19 11:50:21 +08:00

33 KiB
Raw Permalink Blame History

手动测试 13 · 玩家能力与技能系统

测试类型Unity Editor 手动测试Play Mode
覆盖模块BaseGames.PlayerBaseGames.Player.StatesBaseGames.Skills
依赖组件PlayerControllerPlayerMovementPlayerStatsPlayerCombatFormControllerSkillManagerSpringSystemParrySystem
场景要求:包含玩家 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 已放置 PlayerControllerPlayerMovementPlayerStatsPlayerCombatFormControllerSkillManagerSpringSystemParrySystemHurtBoxAnimancerComponentWeaponManager
地面平台 Layer = Ground,至少一块宽平台
垂直墙壁 Layer = Ground,高度 ≥ 4 格,用于抓墙/蹬墙跳测试
测试用敌人 HurtBoxEnemyBase,初始静止,用于攻击/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地面三连击与攻击缓冲
  2. MT-ABILITY-02上劈地面 / 空中)
  3. MT-ABILITY-03下劈与 Pogo 弹起
  4. MT-ABILITY-04空中水平攻击
  5. MT-ABILITY-05攻击取消窗口
  6. MT-ABILITY-06抓墙与高度记忆机制
  7. MT-ABILITY-07蹬墙跳背墙跳 / 对墙跳)
  8. MT-ABILITY-08二段跳
  9. MT-ABILITY-09无敌冲刺
  10. MT-ABILITY-10三形态切换
  11. MT-ABILITY-11三套资源系统
  12. MT-ABILITY-12灵泉使用
  13. MT-ABILITY-13灵泉充能击杀积累
  14. MT-ABILITY-14魂技能施放
  15. MT-ABILITY-15魄技能施放技能 1 / 2
  16. MT-ABILITY-16弹反系统

MT-ABILITY-01地面三连击与攻击缓冲

目的:验证地面三段连击的前摇/有效帧/后摇三阶段、HitBox 激活时序、攻击缓冲机制。

前置条件

  • 玩家站于地面
  • 在玩家攻击范围内放置测试用敌人

步骤 A三段连击完整触发

  1. 进入 Play Mode
  2. 玩家站立地面,按 Attack 键(默认 J

预期

  • 播放第 1 段攻击动画(AnimationConfigSO.GroundAttacks[0]
  • 动画前摇结束时 HitBox 激活(可在 Scene 视图 Gizmos 中观察 HitBox 矩形出现)
  • 命中敌人后敌人 HP 减少,玩家方向上有微小横向反嵈位移
  1. 动画进入后摇阶段后(有效帧结束),再次按 Attack 键

预期

  • 无缝衔接第 2 段攻击动画(GroundAttacks[1]
  • 第 2 段 HitBox 重新激活
  1. 同样方式触发第 3 段

预期

  • 播放 GroundAttacks[2],第三段攻击完成后动画自然结束
  • 玩家返回 IdleStateRunState

步骤 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
  1. 二段跳后再次按 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
  • 武器切换到天魂武器 PrefabWeaponManager.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
  1. 消耗至 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 观察)
  1. 再次击杀一个敌人

预期

  • _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.spiritSkill1spiritSkill2
  • 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 是否为 GroundPlayerWallDetectorwallLayer 掩码包含该 Layer
蹬墙跳无效 受限模式(高于 wallGrabY 在受限模式(下滑状态)时蹬墙跳设计上不可用,属预期行为
魄技能冷却独立验证失败 技能 SO 资产共用同一实例 确认技能 1、技能 2 使用的是不同 FormSkillSO 资产(不同 .asset 文件)
Pogo 未弹起 DownAttackState OnDownHitConfirmed 未订阅 检查 PlayerCombat._currentHitBoxInstance 是否正确订阅Console 查看 HandleWeaponChanged 是否调用
Console 出现 NullReferenceException Inspector 中某 SO/组件字段未赋值 运行时在 PlayerController.AwakeDebug.Assert 输出中查看具体缺失字段