using Pathfinding; using UnityEngine; namespace DDD { public class RestaurantNpcMovement : RestaurantCharacterMovement, IAiMovement { private IAstarAI _iAstarAi; protected override void Awake() { base.Awake(); _iAstarAi = GetComponent(); Debug.Assert(_iAstarAi != null, "_iAstarAi is null"); } 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; 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; } } }