ProjectDDD/Assets/_DDD/_Scripts/RestaurantCharacter/Npc/RestaurantNpcMovement.cs

146 lines
4.5 KiB
C#
Raw Normal View History

2025-08-06 09:58:03 +00:00
using Pathfinding;
using UnityEngine;
namespace DDD
{
public class RestaurantNpcMovement : RestaurantCharacterMovement, IAiMovement
{
private IAstarAI _iAstarAi;
2025-08-07 04:16:10 +00:00
private const int MaxRandomMoveAttempts = 1000;
public Vector3 CurrentPosition => _iAstarAi.position;
public Vector3 Destination => _iAstarAi.destination;
public float CurrentSpeed => _iAstarAi.velocity.magnitude;
public bool IsMoving => !_iAstarAi.isStopped && _iAstarAi.hasPath;
2025-08-06 09:58:03 +00:00
protected override void Awake()
{
base.Awake();
_iAstarAi = GetComponent<IAstarAI>();
Debug.Assert(_iAstarAi != null, "_iAstarAi is null");
}
public void EnableMove()
{
_iAstarAi.canMove = true;
}
public void DisableMove()
{
_iAstarAi.canMove = false;
}
public void PlayMove()
{
_iAstarAi.isStopped = false;
}
public void StopMove()
{
_iAstarAi.isStopped = true;
_iAstarAi.SetPath(null);
}
public void SetMoveSpeed(float speed)
{
_iAstarAi.maxSpeed = speed;
}
public bool TryMoveToPosition(Vector3 position)
{
if (IsPositionMovable(position) == false)
{
Debug.LogWarning($"{gameObject.name}이 이동 불가능한 위치를 대상으로 이동을 시도함");
return false;
}
_iAstarAi.destination = position;
PlayMove();
return true;
}
public bool TryMoveToTarget(Collider targetCollider)
{
if (targetCollider == null)
{
Debug.LogWarning($"{gameObject.name}이 이동하려는 타겟을 찾지 못함");
StopMove();
return false;
}
return TryMoveToPosition(targetCollider.transform.position);
}
public Vector3 GetRandomBetweenTwoPoints(Vector2? normalizedRange = null)
{
var range = normalizedRange ?? new Vector2(0.2f, 0.8f);
var randomFactor = Random.Range(range.x, range.y);
return Vector3.Lerp(_iAstarAi.position, _iAstarAi.destination, randomFactor);
}
public bool TryTeleportToPosition(Vector3 position)
{
if (IsPositionMovable(position) == false)
{
Debug.LogWarning($"{gameObject.name}오브젝트가 이동 불가능한 위치로 텔레포트 시도됨");
return false;
}
_iAstarAi.Teleport(position);
return true;
}
public bool HasReachedDestination()
{
return _iAstarAi.pathPending == false && _iAstarAi.reachedEndOfPath;
}
public bool IsPositionMovable(Vector3 endPosition)
{
var nearestNode = AstarPath.active.GetNearest(endPosition).node;
return nearestNode != null && nearestNode.Walkable;
}
public bool TryMoveToRandomPositionInRange(float range, int graphIndex = 0)
{
if (graphIndex < 0 || graphIndex >= AstarPath.active.graphs.Length)
{
Debug.LogWarning($"{gameObject.name} - 유효하지 않은 그래프 인덱스: {graphIndex}");
return false;
}
int attempts = 0;
Vector3 randomPosition;
var isMovable = false;
var graphBounds = AstarPath.active.graphs[graphIndex].bounds;
do
{
var randomDirection = Random.insideUnitCircle.normalized;
var randomOffset = new Vector3(randomDirection.x, 0, randomDirection.y) * Random.Range(0, range);
randomPosition = _iAstarAi.position + randomOffset;
if (!graphBounds.Contains(randomPosition))
{
continue;
}
isMovable = IsPositionMovable(randomPosition);
attempts++;
} while (!isMovable && attempts < MaxRandomMoveAttempts);
if (isMovable == false)
{
Debug.LogWarning($"{gameObject.name}오브젝트의 랜덤 위치 탐색 실패");
return false;
}
_iAstarAi.destination = randomPosition;
PlayMove();
return true;
}
}
}