몬스터가 코어를 제대로 공격하지 못하는 문제 수정
navMesh는 다시 이전으로 되돌림 코어의 중심이 아닌, 코어의 표면을 기준으로 공격하도록 함
This commit is contained in:
@@ -2821,6 +2821,10 @@ PrefabInstance:
|
||||
propertyPath: GlobalObjectIdHash
|
||||
value: 1153289458
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6473738761679328420, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
|
||||
propertyPath: m_Convex
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 6727958582834582256, guid: ace4a11b046dac9498e6897c2b5eb245, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 10
|
||||
@@ -3027,6 +3031,10 @@ PrefabInstance:
|
||||
propertyPath: GlobalObjectIdHash
|
||||
value: 1738409839
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 9130994837512732106, guid: 368961a0f2d71ce4aad5d8ffe52e0b7f, type: 3}
|
||||
propertyPath: m_Convex
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
@@ -3415,6 +3423,14 @@ PrefabInstance:
|
||||
propertyPath: m_Name
|
||||
value: Core
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8929210192865157768, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
|
||||
propertyPath: m_Convex
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8929210192865157768, guid: e56926eda34629f4fbf3e4c53f0f8bd4, type: 3}
|
||||
propertyPath: m_Enabled
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
namespace Northbound
|
||||
{
|
||||
@@ -332,5 +333,44 @@ namespace Northbound
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Navigation
|
||||
|
||||
/// <summary>
|
||||
/// AI가 코어에 접근할 수 있는 NavMesh 위치 반환 (콜라이더 표면 근처)
|
||||
/// </summary>
|
||||
public Vector3 GetNavMeshPosition()
|
||||
{
|
||||
Collider coreCollider = GetComponent<Collider>();
|
||||
if (coreCollider == null)
|
||||
{
|
||||
return transform.position;
|
||||
}
|
||||
|
||||
// 1. 코어 콜라이더 표면에서 남쪽(앞쪽) 방향으로 검색 시작
|
||||
// 적들이 보통 남쪽에서 오기 때문에 전면부 검색
|
||||
Vector3 searchDirection = Vector3.back; // -Z 방향 (남쪽)
|
||||
Vector3 searchCenter = coreCollider.ClosestPoint(transform.position + searchDirection * 5f);
|
||||
|
||||
// 2. 표면 방향으로 attackRange(약 2m)보다 조금 더 큰 거리에서 NavMesh 샘플링
|
||||
NavMeshHit hit;
|
||||
float maxDistance = 3f; // 콜라이더 표면에서 탐색할 거리
|
||||
|
||||
if (NavMesh.SamplePosition(searchCenter, out hit, maxDistance, NavMesh.AllAreas))
|
||||
{
|
||||
return hit.position;
|
||||
}
|
||||
|
||||
// 3. 실패 시 코어 중심에서 더 넓게 탐색 (fallback)
|
||||
if (NavMesh.SamplePosition(transform.position, out hit, 10f, NavMesh.AllAreas))
|
||||
{
|
||||
return hit.position;
|
||||
}
|
||||
|
||||
Debug.LogWarning("[Core] 코어 주변에서 NavMesh를 찾을 수 없습니다.");
|
||||
return transform.position;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,7 @@ namespace Northbound
|
||||
|
||||
private NavMeshAgent _agent;
|
||||
private EnemyUnit _enemyUnit;
|
||||
private Core _core;
|
||||
private Transform _coreTransform;
|
||||
private Collider _coreCollider;
|
||||
private Vector3 _originPosition;
|
||||
@@ -99,7 +100,7 @@ namespace Northbound
|
||||
_agent.speed = moveSpeed;
|
||||
_agent.acceleration = 8f;
|
||||
_agent.angularSpeed = 120f;
|
||||
_agent.stoppingDistance = attackRange * 0.7f;
|
||||
_agent.stoppingDistance = attackRange * 0.9f; // 공격 범위까지 더 가까이 이동
|
||||
_agent.autoBraking = true;
|
||||
_agent.updateRotation = true;
|
||||
_agent.updateUpAxis = false;
|
||||
@@ -164,7 +165,22 @@ namespace Northbound
|
||||
if (_isRecalculatingPath) return; // 코루틴 대기 중이면 중단
|
||||
if (_coreTransform == null) { FindCore(); return; }
|
||||
|
||||
// 0. Player 감지 (코어로 가는 도중에도 Player를 타겟팅)
|
||||
// 0. 경로 계산 중이거나 이동 중이 아니면 아무것도 하지 않음
|
||||
if (_agent.pathPending) return; // 경로 계산 중
|
||||
|
||||
// 0.5. 실제로 이동 중인지 확인 (velocity로 판단)
|
||||
if (_agent.hasPath && _agent.velocity.sqrMagnitude > 0.01f)
|
||||
{
|
||||
// 이동 중이면 코어 콜라이더 표면까지의 거리로 도달 확인
|
||||
if (GetDistanceToCoreSurface() <= attackRange)
|
||||
{
|
||||
SetTargetPlayer(_coreTransform.gameObject);
|
||||
TransitionToState(EnemyAIState.Attack);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Player 감지 (코어로 가는 도중에도 Player를 타겟팅)
|
||||
GameObject detectedPlayer = DetectTarget();
|
||||
if (detectedPlayer != null)
|
||||
{
|
||||
@@ -173,26 +189,19 @@ namespace Northbound
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 코어로 가는 경로가 '완전(Complete)'한지 먼저 확인
|
||||
// 2. 코어로 가는 경로가 '완전(Complete)'한지 확인
|
||||
// NavMesh가 갱신되었다면 에이전트는 즉시 Complete 상태가 됩니다.
|
||||
if (_agent.hasPath && _agent.pathStatus == NavMeshPathStatus.PathComplete)
|
||||
{
|
||||
if (!_hasSetCoreDestination)
|
||||
{
|
||||
_agent.SetDestination(_coreTransform.position);
|
||||
_agent.SetDestination(_core.GetNavMeshPosition());
|
||||
_hasSetCoreDestination = true;
|
||||
}
|
||||
// [중요] 길이 열렸으므로 아래의 장애물 탐지 로직을 아예 실행하지 않고 리턴!
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 코어 도달 확인
|
||||
if (GetDistanceToCoreSurface() <= attackRange)
|
||||
{
|
||||
TransitionToState(EnemyAIState.Attack);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 길이 막혔을 때(Partial)만 아주 좁은 범위에서 장애물을 찾음
|
||||
GameObject obstacle = DetectObstacle();
|
||||
if (obstacle != null)
|
||||
@@ -205,7 +214,7 @@ namespace Northbound
|
||||
// 4. 경로가 유효하지 않을 때만 재설정
|
||||
if (!_agent.hasPath || _agent.pathStatus == NavMeshPathStatus.PathInvalid)
|
||||
{
|
||||
_agent.SetDestination(_coreTransform.position);
|
||||
_agent.SetDestination(_core.GetNavMeshPosition());
|
||||
_hasSetCoreDestination = true;
|
||||
}
|
||||
}
|
||||
@@ -267,31 +276,35 @@ namespace Northbound
|
||||
return;
|
||||
}
|
||||
|
||||
// 핵심: ClosestPoint를 사용해 '벽 표면'까지의 실제 거리 계산
|
||||
float distance = GetDistanceToTarget(target);
|
||||
// 코어 공격 시에는 도달 시점부터 항상 공격 가능하다고 가정 (거리 체크 생략)
|
||||
bool isCoreTarget = (target == _coreTransform?.gameObject);
|
||||
|
||||
// 코어 혹은 일반 타겟 공격 범위 체크 (공격 시 약간의 거리 여유 1.2f 부여)
|
||||
if (distance <= attackRange * 1.2f)
|
||||
if (!isCoreTarget)
|
||||
{
|
||||
// 타겟 바라보기
|
||||
Vector3 direction = (target.transform.position - transform.position).normalized;
|
||||
direction.y = 0;
|
||||
if (direction != Vector3.zero)
|
||||
{
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(direction), Time.deltaTime * 5f);
|
||||
}
|
||||
// 일반 타겟(플레이어, 장애물)은 거리 체크 필요
|
||||
float distance = GetDistanceToTarget(target);
|
||||
|
||||
// 공격 실행
|
||||
if (Time.time - _lastAttackTime >= attackInterval)
|
||||
// 공격 범위 체크 (공격 시 약간의 거리 여유 1.2f 부여)
|
||||
if (distance > attackRange * 1.2f)
|
||||
{
|
||||
AttackTarget(target);
|
||||
// 거리가 멀어지면 추적 상태로 전환
|
||||
TransitionToState(EnemyAIState.ChasePlayer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// 타겟 바라보기
|
||||
Vector3 direction = (target.transform.position - transform.position).normalized;
|
||||
direction.y = 0;
|
||||
if (direction != Vector3.zero)
|
||||
{
|
||||
// 거리가 멀어지면 타겟 종류에 따라 상태 전환
|
||||
if (target == _coreTransform?.gameObject) TransitionToState(EnemyAIState.MoveToCore);
|
||||
else TransitionToState(EnemyAIState.ChasePlayer);
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(direction), Time.deltaTime * 5f);
|
||||
}
|
||||
|
||||
// 공격 실행
|
||||
if (Time.time - _lastAttackTime >= attackInterval)
|
||||
{
|
||||
AttackTarget(target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,9 +516,9 @@ namespace Northbound
|
||||
case EnemyAIState.MoveToCore:
|
||||
_agent.isStopped = false;
|
||||
_agent.speed = moveSpeed;
|
||||
if (_coreTransform != null)
|
||||
if (_core != null)
|
||||
{
|
||||
_agent.SetDestination(_coreTransform.position);
|
||||
_agent.SetDestination(_core.GetNavMeshPosition());
|
||||
_hasSetCoreDestination = true;
|
||||
}
|
||||
break;
|
||||
@@ -579,11 +592,25 @@ namespace Northbound
|
||||
|
||||
private void FindCore()
|
||||
{
|
||||
Core core = FindFirstObjectByType<Core>();
|
||||
if (core != null)
|
||||
_core = FindFirstObjectByType<Core>();
|
||||
if (_core != null)
|
||||
{
|
||||
_coreTransform = core.transform;
|
||||
_coreCollider = core.GetComponent<Collider>() ?? core.GetComponentInChildren<Collider>();
|
||||
_coreTransform = _core.transform;
|
||||
// 물리적 충돌을 막는 MeshCollider를 우선 찾기 (Trigger 콜라이더 무시)
|
||||
Collider[] allColliders = _core.GetComponentsInChildren<Collider>();
|
||||
foreach (Collider col in allColliders)
|
||||
{
|
||||
if (!col.isTrigger)
|
||||
{
|
||||
_coreCollider = col;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Fallback: 모든 콜라이더가 Trigger이면 첫 번째 콜라이더 사용
|
||||
if (_coreCollider == null && allColliders.Length > 0)
|
||||
{
|
||||
_coreCollider = allColliders[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,9 +71,9 @@ NavMeshProjectSettings:
|
||||
cost: 1
|
||||
m_LastAgentTypeID: -887442657
|
||||
m_Settings:
|
||||
- serializedVersion: 2
|
||||
- serializedVersion: 3
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentRadius: 0.05
|
||||
agentHeight: 2
|
||||
agentSlope: 45
|
||||
agentClimb: 0.75
|
||||
@@ -84,7 +84,9 @@ NavMeshProjectSettings:
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
buildHeightMesh: 0
|
||||
maxJobWorkers: 0
|
||||
preserveTilesOutsideBounds: 0
|
||||
debug:
|
||||
m_Flags: 0
|
||||
m_SettingNames:
|
||||
|
||||
Reference in New Issue
Block a user