enemy AI의 공격도 애니메이션 이벤트로 타이밍을 제어하도록 함
This commit is contained in:
27643
Assets/Animations/Monster Attack 1.anim
Normal file
27643
Assets/Animations/Monster Attack 1.anim
Normal file
File diff suppressed because it is too large
Load Diff
8
Assets/Animations/Monster Attack 1.anim.meta
Normal file
8
Assets/Animations/Monster Attack 1.anim.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5c4b0e294c51551499712a4aa2161713
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 7400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -120,7 +120,7 @@ AnimatorState:
|
|||||||
m_MirrorParameterActive: 0
|
m_MirrorParameterActive: 0
|
||||||
m_CycleOffsetParameterActive: 0
|
m_CycleOffsetParameterActive: 0
|
||||||
m_TimeParameterActive: 0
|
m_TimeParameterActive: 0
|
||||||
m_Motion: {fileID: 5005478036900451222, guid: bbfa9cc7ae2f16448b3adb4300f439e9, type: 3}
|
m_Motion: {fileID: 7400000, guid: 5c4b0e294c51551499712a4aa2161713, type: 2}
|
||||||
m_Tag:
|
m_Tag:
|
||||||
m_SpeedParameter:
|
m_SpeedParameter:
|
||||||
m_MirrorParameter:
|
m_MirrorParameter:
|
||||||
|
|||||||
@@ -564,6 +564,7 @@ RectTransform:
|
|||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 1053830688}
|
- {fileID: 1053830688}
|
||||||
- {fileID: 1458057163}
|
- {fileID: 1458057163}
|
||||||
|
- {fileID: 462053114}
|
||||||
m_Father: {fileID: 860732961}
|
m_Father: {fileID: 860732961}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
@@ -591,6 +592,11 @@ MonoBehaviour:
|
|||||||
buildingDescriptionText: {fileID: 22654986}
|
buildingDescriptionText: {fileID: 22654986}
|
||||||
buildingCostText: {fileID: 426416072}
|
buildingCostText: {fileID: 426416072}
|
||||||
maxSlots: 8
|
maxSlots: 8
|
||||||
|
--- !u!224 &462053114 stripped
|
||||||
|
RectTransform:
|
||||||
|
m_CorrespondingSourceObject: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
m_PrefabInstance: {fileID: 829812757}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
--- !u!4 &500303526 stripped
|
--- !u!4 &500303526 stripped
|
||||||
Transform:
|
Transform:
|
||||||
m_CorrespondingSourceObject: {fileID: 922888705413710451, guid: 5662d0b0d0eb5f54290edd8dd0980b57, type: 3}
|
m_CorrespondingSourceObject: {fileID: 922888705413710451, guid: 5662d0b0d0eb5f54290edd8dd0980b57, type: 3}
|
||||||
@@ -1261,6 +1267,151 @@ Transform:
|
|||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 576429380}
|
m_Father: {fileID: 576429380}
|
||||||
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||||
|
--- !u!1001 &829812757
|
||||||
|
PrefabInstance:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Modification:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TransformParent: {fileID: 457600247}
|
||||||
|
m_Modifications:
|
||||||
|
- target: {fileID: 2206383192760330694, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchorMax.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2206383192760330694, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchorMin.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2206383192760330694, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 2206383192760330694, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4388086439464652406, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchorMax.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4388086439464652406, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchorMin.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4388086439464652406, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 4388086439464652406, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5112555873318329611, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_Name
|
||||||
|
value: RespawnPanel
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_Pivot.x
|
||||||
|
value: 0.5
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_Pivot.y
|
||||||
|
value: 0.5
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchorMax.x
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchorMax.y
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchorMin.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchorMin.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_SizeDelta.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_SizeDelta.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_LocalPosition.z
|
||||||
|
value: 34.253292
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.w
|
||||||
|
value: 1
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_LocalRotation.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 5292594068365800785, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_LocalEulerAnglesHint.z
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 7942973741237334281, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchorMax.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 7942973741237334281, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchorMin.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 7942973741237334281, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.x
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
- target: {fileID: 7942973741237334281, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
|
propertyPath: m_AnchoredPosition.y
|
||||||
|
value: 0
|
||||||
|
objectReference: {fileID: 0}
|
||||||
|
m_RemovedComponents: []
|
||||||
|
m_RemovedGameObjects: []
|
||||||
|
m_AddedGameObjects: []
|
||||||
|
m_AddedComponents: []
|
||||||
|
m_SourcePrefab: {fileID: 100100000, guid: 9257920ba4a6256499ad89eeb7d7098a, type: 3}
|
||||||
--- !u!1 &860732960
|
--- !u!1 &860732960
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@@ -85,6 +85,12 @@ namespace Northbound
|
|||||||
);
|
);
|
||||||
|
|
||||||
private GameObject _cachedTargetPlayer;
|
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()
|
public override void OnNetworkSpawn()
|
||||||
{
|
{
|
||||||
@@ -92,6 +98,8 @@ namespace Northbound
|
|||||||
|
|
||||||
_agent = GetComponent<NavMeshAgent>();
|
_agent = GetComponent<NavMeshAgent>();
|
||||||
_enemyUnit = GetComponent<EnemyUnit>();
|
_enemyUnit = GetComponent<EnemyUnit>();
|
||||||
|
_animator = GetComponent<Animator>();
|
||||||
|
_networkAnimator = GetComponent<Unity.Netcode.Components.NetworkAnimator>();
|
||||||
_originPosition = transform.position;
|
_originPosition = transform.position;
|
||||||
|
|
||||||
if (IsServer)
|
if (IsServer)
|
||||||
@@ -247,6 +255,13 @@ namespace Northbound
|
|||||||
|
|
||||||
private void UpdateAttack()
|
private void UpdateAttack()
|
||||||
{
|
{
|
||||||
|
// 공격 타임아웃 체크 (애니메이션 이벤트가 발생하지 않은 경우)
|
||||||
|
if (_isAttacking && Time.time - _attackStartTime > ATTACK_TIMEOUT)
|
||||||
|
{
|
||||||
|
_isAttacking = false;
|
||||||
|
_pendingAttackTarget = null;
|
||||||
|
}
|
||||||
|
|
||||||
GameObject target = GetTargetPlayer();
|
GameObject target = GetTargetPlayer();
|
||||||
if (target == null)
|
if (target == null)
|
||||||
{
|
{
|
||||||
@@ -434,7 +449,10 @@ namespace Northbound
|
|||||||
|
|
||||||
private void AttackTarget(GameObject target)
|
private void AttackTarget(GameObject target)
|
||||||
{
|
{
|
||||||
// 1. 타겟의 자식, 본인, 부모 순으로 샅샅이 뒤져서 IDamageable을 찾습니다.
|
// 이미 공격 중이면 대기
|
||||||
|
if (_isAttacking) return;
|
||||||
|
|
||||||
|
// 1. 타겟의 자식, 본인, 부모 순으로 샅샛이 뒤져서 IDamageable을 찾습니다.
|
||||||
IDamageable damageable = target.GetComponentInChildren<IDamageable>();
|
IDamageable damageable = target.GetComponentInChildren<IDamageable>();
|
||||||
if (damageable == null) damageable = target.GetComponent<IDamageable>();
|
if (damageable == null) damageable = target.GetComponent<IDamageable>();
|
||||||
if (damageable == null) damageable = target.GetComponentInParent<IDamageable>();
|
if (damageable == null) damageable = target.GetComponentInParent<IDamageable>();
|
||||||
@@ -444,9 +462,26 @@ namespace Northbound
|
|||||||
// 2. 공격 쿨타임 체크
|
// 2. 공격 쿨타임 체크
|
||||||
if (Time.time - _lastAttackTime >= attackInterval)
|
if (Time.time - _lastAttackTime >= attackInterval)
|
||||||
{
|
{
|
||||||
damageable.TakeDamage(attackDamage, NetworkObjectId);
|
|
||||||
_lastAttackTime = Time.time;
|
_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
|
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
|
#endregion
|
||||||
|
|
||||||
#region Utilities & Distance
|
#region Utilities & Distance
|
||||||
|
|||||||
Reference in New Issue
Block a user