08/13 NavMesh를 사용한 추적, 순찰, 시야, 충돌 처리

심지태
∙∙조회 8
08/13 NavMesh를 사용한 추적, 순찰, 시야, 충돌 처리

거리 3개 설계: 감지·공격·포기

csharp
using UnityEngine;
using UnityEngine.AI;

public class EnemyChaser : MonoBehaviour
{
    [SerializeField] Transform target;
    [SerializeField] float detectionRange = 4f;
    [SerializeField] float attackRange = 1f;
    [SerializeField] float giveUpRange = 6f;
    [SerializeField] float rotateSensitivity;
    NavMeshAgent agent;
    bool hasDetectionTarget;

    void Awake()
    {
        agent = GetComponent<NavMeshAgent>();
        agent.stoppingDistance = attackRange;
    }

    private void Update()
    {
        if (target == null)
            return;

        // 다만 이렇게 했었을 때는, 벽 유무와 상관없이 거리만 좁혀지면 인식함.
        float distance = Vector3.Distance(transform.position, target.position);

        // 감지
        if (!hasDetectionTarget && distance < detectionRange)
        {
            hasDetectionTarget = true;
        }

        // 포기
        if (hasDetectionTarget && distance >= giveUpRange)
        {
            hasDetectionTarget = false;
            agent.ResetPath();
            return;
        }

        // 대기
        if (!hasDetectionTarget)
        {
            return;
        }

        if (distance > attackRange)
        {
            // 추적
            agent.isStopped = false;
            agent.SetDestination(target.position);
        }
        else
        {
            // 공격
            agent.isStopped = true;
            LookAtTarget();
            Debug.Log("공격중");
        }
    }

    private void LookAtTarget()
    {
        Vector3 direction = target.position - transform.position;
        direction.y = 0;

        // 떨림 현상 방지
        if (direction.sqrMagnitude < 0.01f)
        {
            return;
        }

        // 회전값을 부드럽게 보간
        transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(direction), Time.deltaTime * rotateSensitivity);
    }
}

주요 내용

  1. 각 감지 범위 별로 Enemy의 행동을 설정하였다.
  2. agent.ResetPath()는 NavMeshAgent가 현재 가지고 있는 이동 경로를 삭제하고 이동을 멈추게 하는 함수를 사용하였다.
  3. agent.isStopped 값을 바꾸어, 현재 경로와 목적지는 유지한 채, NavMeshAgent의 이동만 일시적으로 멈췄다.
  4. 적과 타깃의 위치가 거의 겹쳐서 방향 벡터가 너무 작을 때, 회전할 때의 떨림 현상을 방지하기 위해 if (direction.sqrMagnitude < 0.01f) {
    return;
    }를 사용하였다.
  5. Quaternion.Slerp를 사용하여, 바라보는 방향으로 부드럽게 보간하도록 하였다.

Nav Mesh Obstacle

Nav Mesh Obstacle은 NavMesh Agent가 해당 오브젝트를 장애물로 인식하고 피해 이동하도록 만드는 컴포넌트입니다.

항목현재 설정설명
ShapeBox장애물 영역의 모양입니다. Box 또는 Capsule을 사용할 수 있습니다.
CenterX 0, Y 0, Z 0오브젝트 기준 장애물 영역의 중심 위치입니다.
SizeX 1, Y 1, Z 1Box 장애물 영역의 가로·높이·깊이 크기입니다.
Carve켜짐NavMesh에 구멍을 만들어 Agent가 장애물을 우회하도록 경로를 다시 계산합니다.
Move Threshold0.1장애물이 이 거리 이상 움직이면 Carve 영역을 갱신합니다. 값이 작을수록 자주 갱신됩니다.
Time To Stationary0.1초장애물이 멈춘 뒤 정지 상태로 판단할 때까지 기다리는 시간입니다.
Carve Only Stationary꺼짐켜면 장애물이 정지했을 때만 NavMesh를 파냅니다. 현재 설정에서는 이동 중에도 Carve가 갱신될 수 있습니다.