- HitReactionController에 경직, 다운 회복 가능 구간, Hit 속도 배율 파라미터 처리를 추가 - DownBegin/Recover 상태 종료를 StateMachineBehaviour로 받아 구르기 허용 구간과 다운 해제를 분리 - 드로그 발구르기를 경직 이펙트로 전환하고 넉백/경직 이펙트에서 Hit 애니메이션 속도 배율을 설정 가능하게 정리 - PlayMode 테스트를 추가해 경직/넉백이 Hit 애니메이션 속도 배율을 실제로 반영하는지 자동 검증
200 lines
6.9 KiB
C#
200 lines
6.9 KiB
C#
using UnityEngine;
|
|
|
|
using Colosseum.Abnormalities;
|
|
using Colosseum.Skills;
|
|
|
|
namespace Colosseum.Player
|
|
{
|
|
/// <summary>
|
|
/// 플레이어의 전투 행동 가능 여부를 한 곳에서 판정하는 상태 관리자.
|
|
/// 이동, 점프, 스킬 사용 가능 여부를 사망/이상 상태/관전/시전 상태와 연동합니다.
|
|
/// </summary>
|
|
[DisallowMultipleComponent]
|
|
public class PlayerActionState : MonoBehaviour
|
|
{
|
|
[Header("References")]
|
|
[Tooltip("플레이어 네트워크 상태")]
|
|
[SerializeField] private PlayerNetworkController networkController;
|
|
|
|
[Tooltip("이상 상태 관리자")]
|
|
[SerializeField] private AbnormalityManager abnormalityManager;
|
|
|
|
[Tooltip("스킬 실행 관리자")]
|
|
[SerializeField] private SkillController skillController;
|
|
|
|
[Tooltip("피격 제어 관리자")]
|
|
[SerializeField] private HitReactionController hitReactionController;
|
|
|
|
[Tooltip("관전 관리자")]
|
|
[SerializeField] private PlayerSpectator spectator;
|
|
|
|
/// <summary>
|
|
/// 사망 상태 여부
|
|
/// </summary>
|
|
public bool IsDead => networkController != null && networkController.IsDead;
|
|
|
|
/// <summary>
|
|
/// 기절 상태 여부
|
|
/// </summary>
|
|
public bool IsStunned => abnormalityManager != null && abnormalityManager.IsStunned;
|
|
|
|
/// <summary>
|
|
/// 경직 상태 여부
|
|
/// </summary>
|
|
public bool IsStaggered => hitReactionController != null && hitReactionController.IsStaggered;
|
|
|
|
/// <summary>
|
|
/// 넉백 상태 여부
|
|
/// </summary>
|
|
public bool IsKnockbackActive => hitReactionController != null && hitReactionController.IsKnockbackActive;
|
|
|
|
/// <summary>
|
|
/// 다운 상태 여부
|
|
/// </summary>
|
|
public bool IsDowned => hitReactionController != null && hitReactionController.IsDowned;
|
|
|
|
/// <summary>
|
|
/// 다운 중 구르기 가능 구간 여부
|
|
/// </summary>
|
|
public bool IsDownRecoverable => hitReactionController != null && hitReactionController.IsDownRecoverable;
|
|
|
|
/// <summary>
|
|
/// 침묵 상태 여부
|
|
/// </summary>
|
|
public bool IsSilenced => abnormalityManager != null && abnormalityManager.IsSilenced;
|
|
|
|
/// <summary>
|
|
/// 관전 상태 여부
|
|
/// </summary>
|
|
public bool IsSpectating => spectator != null && spectator.IsSpectating;
|
|
|
|
/// <summary>
|
|
/// 스킬 애니메이션 재생 중 여부
|
|
/// </summary>
|
|
public bool IsCastingSkill => skillController != null && skillController.IsPlayingAnimation;
|
|
|
|
/// <summary>
|
|
/// 현재 시전 중인 스킬
|
|
/// </summary>
|
|
public SkillData CurrentSkill => skillController != null ? skillController.CurrentSkill : null;
|
|
|
|
/// <summary>
|
|
/// 무적 이상상태 여부
|
|
/// </summary>
|
|
public bool IsDamageImmune => abnormalityManager != null && abnormalityManager.IsInvincible;
|
|
|
|
/// <summary>
|
|
/// 입력을 받아도 되는지 여부
|
|
/// </summary>
|
|
public bool CanReceiveInput => !IsDead && !IsSpectating;
|
|
|
|
/// <summary>
|
|
/// 플레이어가 직접 이동 입력을 사용할 수 있는지 여부
|
|
/// </summary>
|
|
public bool CanMove => CanReceiveInput && !IsStunned && !IsStaggered && !IsKnockbackActive && !IsDowned && !BlocksMovementForCurrentSkill();
|
|
|
|
/// <summary>
|
|
/// 점프 가능 여부
|
|
/// </summary>
|
|
public bool CanJump => CanReceiveInput && !IsStunned && !IsStaggered && !IsKnockbackActive && !IsDowned && !BlocksJumpForCurrentSkill();
|
|
|
|
/// <summary>
|
|
/// 일반 스킬 시작 가능 여부
|
|
/// </summary>
|
|
public bool CanUseSkills => CanReceiveInput && !IsStunned && !IsStaggered && !IsKnockbackActive && !IsDowned && !IsSilenced && !BlocksSkillUseForCurrentSkill();
|
|
|
|
/// <summary>
|
|
/// 회피 스킬 시작 가능 여부
|
|
/// </summary>
|
|
public bool CanEvade => CanReceiveInput
|
|
&& !IsStunned
|
|
&& !IsStaggered
|
|
&& !IsKnockbackActive
|
|
&& !IsSilenced
|
|
&& (!IsDowned || IsDownRecoverable)
|
|
&& !BlocksSkillUseForCurrentSkill();
|
|
|
|
/// <summary>
|
|
/// 특정 스킬의 시작 가능 여부.
|
|
/// 스킬 이름과 무관하게 동일한 시작 규칙을 사용합니다.
|
|
/// </summary>
|
|
public bool CanStartSkill(SkillData skill)
|
|
{
|
|
if (skill == null)
|
|
return false;
|
|
|
|
if (!CanReceiveInput || IsStunned || IsStaggered || IsKnockbackActive || IsSilenced)
|
|
return false;
|
|
|
|
if (IsDowned)
|
|
{
|
|
if (!IsDownRecoverable || !skill.IsEvadeSkill)
|
|
return false;
|
|
}
|
|
|
|
return !BlocksSkillUseForCurrentSkill();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 이동 속도 배율
|
|
/// </summary>
|
|
public float MoveSpeedMultiplier
|
|
{
|
|
get
|
|
{
|
|
if (!CanReceiveInput || IsStunned || IsStaggered || IsKnockbackActive || IsDowned)
|
|
return 0f;
|
|
|
|
return abnormalityManager != null ? abnormalityManager.MoveSpeedMultiplier : 1f;
|
|
}
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
if (networkController == null)
|
|
networkController = GetComponent<PlayerNetworkController>();
|
|
if (abnormalityManager == null)
|
|
abnormalityManager = GetComponent<AbnormalityManager>();
|
|
if (skillController == null)
|
|
skillController = GetComponent<SkillController>();
|
|
if (hitReactionController == null)
|
|
hitReactionController = GetOrCreateHitReactionController();
|
|
if (spectator == null)
|
|
spectator = GetComponentInChildren<PlayerSpectator>();
|
|
}
|
|
|
|
private bool BlocksMovementForCurrentSkill()
|
|
{
|
|
if (!IsCastingSkill)
|
|
return false;
|
|
|
|
return CurrentSkill == null || CurrentSkill.BlockMovementWhileCasting;
|
|
}
|
|
|
|
private bool BlocksJumpForCurrentSkill()
|
|
{
|
|
if (!IsCastingSkill)
|
|
return false;
|
|
|
|
return CurrentSkill == null || CurrentSkill.BlockJumpWhileCasting;
|
|
}
|
|
|
|
private bool BlocksSkillUseForCurrentSkill()
|
|
{
|
|
if (!IsCastingSkill)
|
|
return false;
|
|
|
|
return CurrentSkill == null || CurrentSkill.BlockOtherSkillsWhileCasting;
|
|
}
|
|
|
|
private HitReactionController GetOrCreateHitReactionController()
|
|
{
|
|
HitReactionController foundController = GetComponent<HitReactionController>();
|
|
if (foundController != null)
|
|
return foundController;
|
|
|
|
return gameObject.AddComponent<HitReactionController>();
|
|
}
|
|
}
|
|
}
|