- EnemyAnimationController가 보스 런타임 페이즈를 Animator Phase 파라미터로 동기화\n- AC_Boss_Drog에 1/2페이즈 공용 Idle과 3페이즈 전용 Idle 상태 및 전이 추가\n- 정지 중 페이즈 변경과 이동/피격 후 복귀가 현재 페이즈 Idle로 이어지도록 정리
152 lines
4.9 KiB
C#
152 lines
4.9 KiB
C#
using UnityEngine;
|
|
using Unity.Netcode;
|
|
|
|
namespace Colosseum.Enemy
|
|
{
|
|
/// <summary>
|
|
/// 적 캐릭터 애니메이션 컨트롤러
|
|
/// NavMeshAgent 속도에 따라 Idle/Move 애니메이션 제어
|
|
/// </summary>
|
|
public class EnemyAnimationController : NetworkBehaviour
|
|
{
|
|
[Header("Animation Parameters")]
|
|
[SerializeField] private string speedParam = "Speed";
|
|
[SerializeField] private string phaseParam = "Phase";
|
|
[SerializeField] private string attackTriggerParam = "Attack";
|
|
[SerializeField] private string skillTriggerParam = "Skill";
|
|
|
|
[Header("Settings")]
|
|
[SerializeField] private float speedSmoothTime = 0.1f;
|
|
[SerializeField] private float stopThreshold = 0.05f;
|
|
|
|
private Animator animator;
|
|
private UnityEngine.AI.NavMeshAgent navMeshAgent;
|
|
private EnemyBase enemyBase;
|
|
private BossBehaviorRuntimeState runtimeState;
|
|
private float currentSpeed;
|
|
private float speedVelocity;
|
|
|
|
private void Awake()
|
|
{
|
|
animator = GetComponent<Animator>();
|
|
navMeshAgent = GetComponent<UnityEngine.AI.NavMeshAgent>();
|
|
enemyBase = GetComponent<EnemyBase>();
|
|
runtimeState = GetComponent<BossBehaviorRuntimeState>();
|
|
}
|
|
|
|
public override void OnNetworkSpawn()
|
|
{
|
|
if (!IsServer)
|
|
{
|
|
enabled = false;
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (!IsServer) return;
|
|
|
|
UpdateAnimationParameters();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 애니메이션 파라미터 업데이트
|
|
/// </summary>
|
|
private void UpdateAnimationParameters()
|
|
{
|
|
// 사망 상태에서는 애니메이션 파라미터 업데이트 중단
|
|
if (enemyBase != null && enemyBase.IsDead)
|
|
return;
|
|
|
|
if (animator == null || navMeshAgent == null)
|
|
return;
|
|
|
|
// NavMeshAgent의 속도를 기반으로 타겟 속도 계산
|
|
float targetSpeed = navMeshAgent.velocity.magnitude;
|
|
|
|
// 정지 임계값 처리
|
|
if (targetSpeed < stopThreshold)
|
|
targetSpeed = 0f;
|
|
|
|
// 부드러운 속도 변화
|
|
currentSpeed = Mathf.SmoothDamp(currentSpeed, targetSpeed, ref speedVelocity, speedSmoothTime);
|
|
|
|
// 애니메이터 파라미터 설정
|
|
animator.SetFloat(speedParam, currentSpeed);
|
|
|
|
if (HasAnimatorParameter(animator, phaseParam, AnimatorControllerParameterType.Int))
|
|
{
|
|
int currentPhase = runtimeState != null ? runtimeState.CurrentPatternPhase : 1;
|
|
animator.SetInteger(phaseParam, Mathf.Max(1, currentPhase));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 공격 애니메이션 트리거 (외부에서 호출)
|
|
/// </summary>
|
|
public void PlayAttack()
|
|
{
|
|
if (!IsServer || animator == null)
|
|
return;
|
|
|
|
// 사망 상태에서는 공격 애니메이션 재생하지 않음
|
|
if (enemyBase != null && enemyBase.IsDead)
|
|
return;
|
|
|
|
animator.SetTrigger(attackTriggerParam);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 스킬 애니메이션 트리거 (외부에서 호출)
|
|
/// </summary>
|
|
public void PlaySkill()
|
|
{
|
|
if (!IsServer || animator == null)
|
|
return;
|
|
|
|
// 사망 상태에서는 스킬 애니메이션 재생하지 않음
|
|
if (enemyBase != null && enemyBase.IsDead)
|
|
return;
|
|
|
|
animator.SetTrigger(skillTriggerParam);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 특정 애니메이션 트리거 재생
|
|
/// </summary>
|
|
/// <param name="triggerName">트리거 파라미터 이름</param>
|
|
public void PlayTrigger(string triggerName)
|
|
{
|
|
if (!IsServer || animator == null)
|
|
return;
|
|
|
|
// 사망 상태에서는 일반 애니메이션 재생하지 않음
|
|
if (enemyBase != null && enemyBase.IsDead)
|
|
return;
|
|
|
|
animator.SetTrigger(triggerName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 현재 애니메이션 속도
|
|
/// </summary>
|
|
public float CurrentSpeed => currentSpeed;
|
|
|
|
private static bool HasAnimatorParameter(Animator targetAnimator, string parameterName, AnimatorControllerParameterType parameterType)
|
|
{
|
|
if (targetAnimator == null || string.IsNullOrEmpty(parameterName))
|
|
return false;
|
|
|
|
AnimatorControllerParameter[] parameters = targetAnimator.parameters;
|
|
for (int i = 0; i < parameters.Length; i++)
|
|
{
|
|
AnimatorControllerParameter parameter = parameters[i];
|
|
if (parameter.type == parameterType && parameter.name == parameterName)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|