AiMovement 구조 작성

This commit is contained in:
NTG_Lenovo 2025-08-06 18:58:03 +09:00
parent d930358fe5
commit 52881e4d75
4 changed files with 176 additions and 2 deletions

View File

@ -0,0 +1,26 @@
using UnityEngine;
namespace DDD
{
public interface IAiMovement
{
Vector3 CurrentPosition { get; }
Vector3 Destination { get; }
float CurrentSpeed { get; }
bool IsMoving { get; }
void EnableMove();
void DisableMove();
void PlayMove();
void StopMove();
void SetMoveSpeed(float speed);
bool TryMoveToPosition(Vector3 position);
bool TryMoveToTarget(Collider targetCollider);
Vector3 GetRandomBetweenTwoPoints(Vector2? normalizedRange = null);
bool TryTeleportToPosition(Vector3 position);
bool HasReachedDestination();
bool IsPositionMovable(Vector3 endPosition);
bool TryMoveToRandomPositionInRange(float range, int graphIndex = 0);
}
}

View File

@ -0,0 +1,146 @@
using Pathfinding;
using UnityEngine;
namespace DDD
{
public class RestaurantNpcMovement : RestaurantCharacterMovement, IAiMovement
{
private IAstarAI _iAstarAi;
protected override void Awake()
{
base.Awake();
_iAstarAi = GetComponent<IAstarAI>();
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;
}
}
}

View File

@ -35,8 +35,10 @@ public class RestaurantPlayerMovement : RestaurantCharacterMovement
#region Unity Lifecycle
private void Awake()
protected override void Awake()
{
base.Awake();
InitializeComponents();
}

View File

@ -5,7 +5,7 @@ namespace DDD
public class RestaurantCharacterMovement : MonoBehaviour
{
private RestaurantCharacterMovementConstraint _constraint;
private void Awake()
protected virtual void Awake()
{
_constraint = gameObject.AddComponent<RestaurantCharacterMovementConstraint>();
}