feat: 플레이어 경직/다운 회복 구간 추가

- HitReactionController에 경직, 다운 회복 가능 구간, Hit 속도 배율 파라미터 처리를 추가

- DownBegin/Recover 상태 종료를 StateMachineBehaviour로 받아 구르기 허용 구간과 다운 해제를 분리

- 드로그 발구르기를 경직 이펙트로 전환하고 넉백/경직 이펙트에서 Hit 애니메이션 속도 배율을 설정 가능하게 정리

- PlayMode 테스트를 추가해 경직/넉백이 Hit 애니메이션 속도 배율을 실제로 반영하는지 자동 검증
This commit is contained in:
2026-04-06 18:03:50 +09:00
parent daaf54169a
commit 147e9baa25
28 changed files with 1665 additions and 38 deletions

View File

@@ -106,6 +106,7 @@ namespace Colosseum.Player
Verify("초기 상태: 사망 아님", !networkController.IsDead);
Verify("초기 상태: 이동 가능", actionState.CanMove);
Verify("초기 상태: 스킬 사용 가능", actionState.CanUseSkills);
Verify("초기 상태: 구르기 가능", actionState.CanEvade);
Verify("초기 상태: 무적 상태 아님", !actionState.IsDamageImmune);
Verify("초기 상태: 마지막 취소 이유 없음", skillController == null || skillController.LastCancelReason == SkillCancelReason.None);
@@ -331,6 +332,12 @@ namespace Colosseum.Player
Vector3 knockbackVelocity = Vector3.back * 6f;
RequestKnockbackRpc(knockbackVelocity, 0.2f);
yield return new WaitForSeconds(0.05f);
Verify("넉백 적용: IsKnockbackActive", actionState.IsKnockbackActive);
Verify("넉백 적용: 스킬 사용 불가", !actionState.CanUseSkills);
Verify("넉백 적용: 구르기 불가", !actionState.CanEvade);
yield return new WaitForSeconds(0.3f);
float movedDistance = Vector3.Distance(startPosition, transform.position);
@@ -371,13 +378,32 @@ namespace Colosseum.Player
Verify("다운 적용: 이동 불가", !actionState.CanMove);
Verify("다운 적용: 점프 불가", !actionState.CanJump);
Verify("다운 적용: 스킬 사용 불가", !actionState.CanUseSkills);
Verify("다운 적용: 초기 구르기 불가", !actionState.CanEvade);
Verify("다운 적용: 이동속도 0", Mathf.Approximately(actionState.MoveSpeedMultiplier, 0f));
yield return WaitForConditionOrTimeout(() => !hitReactionController.IsDowned, 1.5f);
RequestDownBeginExitedRpc();
yield return WaitForConditionOrTimeout(() => hitReactionController.IsDownRecoverable, settleDelay + 1f);
Verify("다운 회복 가능 진입: IsDownRecoverable", hitReactionController.IsDownRecoverable);
Verify("다운 회복 가능 진입: 일반 스킬 사용 불가 유지", !actionState.CanUseSkills);
SkillData evadeSkill = skillInput != null ? skillInput.GetSkill(6) : null;
if (evadeSkill != null)
{
Verify("다운 회복 가능 진입: 구르기 시작 가능", actionState.CanStartSkill(evadeSkill));
}
else
{
AppendLine("[SKIP] 다운 회복 가능 진입: 구르기 스킬이 없습니다.");
}
yield return WaitForConditionOrTimeout(() => !hitReactionController.IsDowned, 2.5f);
Verify("다운 해제: IsDowned false", !hitReactionController.IsDowned);
Verify("다운 해제: IsDownRecoverable false", !hitReactionController.IsDownRecoverable);
Verify("다운 해제: 이동 가능 복구", actionState.CanMove);
Verify("다운 해제: 스킬 사용 가능 복구", actionState.CanUseSkills);
Verify("다운 해제: 구르기 가능 복구", actionState.CanEvade);
}
[Rpc(SendTo.Server)]
@@ -386,6 +412,12 @@ namespace Colosseum.Player
hitReactionController?.ApplyDown(duration);
}
[Rpc(SendTo.Server)]
private void RequestDownBeginExitedRpc()
{
hitReactionController?.NotifyDownBeginExited();
}
[Rpc(SendTo.Server)]
private void RequestKnockbackRpc(Vector3 velocity, float duration)
{