enemy AI의 공격도 애니메이션 이벤트로 타이밍을 제어하도록 함
This commit is contained in:
@@ -85,6 +85,12 @@ namespace Northbound
|
||||
);
|
||||
|
||||
private GameObject _cachedTargetPlayer;
|
||||
private Animator _animator;
|
||||
private Unity.Netcode.Components.NetworkAnimator _networkAnimator;
|
||||
private bool _isAttacking = false;
|
||||
private GameObject _pendingAttackTarget;
|
||||
private float _attackStartTime;
|
||||
private const float ATTACK_TIMEOUT = 3f; // 애니메이션 이벤트 미발생 시 타임아웃
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
@@ -92,6 +98,8 @@ namespace Northbound
|
||||
|
||||
_agent = GetComponent<NavMeshAgent>();
|
||||
_enemyUnit = GetComponent<EnemyUnit>();
|
||||
_animator = GetComponent<Animator>();
|
||||
_networkAnimator = GetComponent<Unity.Netcode.Components.NetworkAnimator>();
|
||||
_originPosition = transform.position;
|
||||
|
||||
if (IsServer)
|
||||
@@ -247,6 +255,13 @@ namespace Northbound
|
||||
|
||||
private void UpdateAttack()
|
||||
{
|
||||
// 공격 타임아웃 체크 (애니메이션 이벤트가 발생하지 않은 경우)
|
||||
if (_isAttacking && Time.time - _attackStartTime > ATTACK_TIMEOUT)
|
||||
{
|
||||
_isAttacking = false;
|
||||
_pendingAttackTarget = null;
|
||||
}
|
||||
|
||||
GameObject target = GetTargetPlayer();
|
||||
if (target == null)
|
||||
{
|
||||
@@ -434,7 +449,10 @@ namespace Northbound
|
||||
|
||||
private void AttackTarget(GameObject target)
|
||||
{
|
||||
// 1. 타겟의 자식, 본인, 부모 순으로 샅샅이 뒤져서 IDamageable을 찾습니다.
|
||||
// 이미 공격 중이면 대기
|
||||
if (_isAttacking) return;
|
||||
|
||||
// 1. 타겟의 자식, 본인, 부모 순으로 샅샛이 뒤져서 IDamageable을 찾습니다.
|
||||
IDamageable damageable = target.GetComponentInChildren<IDamageable>();
|
||||
if (damageable == null) damageable = target.GetComponent<IDamageable>();
|
||||
if (damageable == null) damageable = target.GetComponentInParent<IDamageable>();
|
||||
@@ -444,9 +462,26 @@ namespace Northbound
|
||||
// 2. 공격 쿨타임 체크
|
||||
if (Time.time - _lastAttackTime >= attackInterval)
|
||||
{
|
||||
damageable.TakeDamage(attackDamage, NetworkObjectId);
|
||||
_lastAttackTime = Time.time;
|
||||
OnAttackPerformed?.Invoke(target);
|
||||
_isAttacking = true;
|
||||
_pendingAttackTarget = target;
|
||||
_attackStartTime = Time.time;
|
||||
|
||||
// 애니메이션 재생 (서버에서 NetworkAnimator로 동기화)
|
||||
if (_networkAnimator != null)
|
||||
{
|
||||
_networkAnimator.SetTrigger("Attack");
|
||||
}
|
||||
else if (_animator != null)
|
||||
{
|
||||
_animator.SetTrigger("Attack");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 애니메이션이 없으면 즉시 공격 실행
|
||||
PerformAttack();
|
||||
_isAttacking = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -456,6 +491,41 @@ namespace Northbound
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 애니메이션 이벤트: 공격 타격 시점에 호출
|
||||
/// </summary>
|
||||
public void OnAttackHit()
|
||||
{
|
||||
PerformAttack();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 애니메이션 이벤트: 공격 완료 시 호출
|
||||
/// </summary>
|
||||
public void OnAttackComplete()
|
||||
{
|
||||
_isAttacking = false;
|
||||
_pendingAttackTarget = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 실제 공격 수행 (데미지 적용)
|
||||
/// </summary>
|
||||
private void PerformAttack()
|
||||
{
|
||||
if (_pendingAttackTarget == null) return;
|
||||
|
||||
IDamageable damageable = _pendingAttackTarget.GetComponentInChildren<IDamageable>();
|
||||
if (damageable == null) damageable = _pendingAttackTarget.GetComponent<IDamageable>();
|
||||
if (damageable == null) damageable = _pendingAttackTarget.GetComponentInParent<IDamageable>();
|
||||
|
||||
if (damageable != null && !damageable.IsDead())
|
||||
{
|
||||
damageable.TakeDamage(attackDamage, NetworkObjectId);
|
||||
OnAttackPerformed?.Invoke(_pendingAttackTarget);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utilities & Distance
|
||||
|
||||
Reference in New Issue
Block a user