Unity Navigation System은 AI가 지능적으로 탐색할 수 있도록 하는 기능입니다. 적의 순찰, 동적 경로 탐색까지, 이 시스템은 AI Navigation을 효율적으로 만드는 도구를 제공합니다. 이번 글에서는 Unity Navigation System의 대해 알아보겠습니다.
※ Unity6 기준으로 구현하였습니다.
- 적 AI 구현
- 동료 AI 구현
- 순찰 AI 구현
- 탐색 AI 구현

- Unity Navigation System은 게임 환경에서 AI 캐릭터가 경로를 찾아 따라갈 수 있도록 돕는 시스템입니다. 이 시스템은 NavMesh라는 미리 계산된 지도를 사용하여 장면의 이동 가능한 영역과 이동 불가능한 영역을 정의합니다.
- NavMesh : 이동 가능한 표면을 나타냅니다.
- NavMeshAgent: NavMesh를 따라 탐색할 수 있도록 AI 캐릭터에 추가되는 컴포넌트
- NavMeshObstacle: AI 경로를 동적으로 방해하는 객체를 설정하는 컴포넌트
- NavMeshSurface : 런타임 중 NavMesh를 동적으로 업데이트할 수 있는 컴포넌트
- 효율적인 경로 탐색: AI 캐릭터를 위한 최적 경로를 자동으로 계산합니다
- 장애물 회피: 추가적인 스크립트 없이 정적 및 동적 장애물을 피할 수 있습니다
- 커스터마이징: 에이전트 크기, 속도, 네비게이션 동작에 대한 사용자 지정 설정을 지원합니다.

- AI가 이동할 바닥을 Scene에 추가합니다. 예) Plane,Terrain
- 바닥의 객체에 NavMeshSurface를 추가합니다.

- Agent Type을 Humanoid로 설정합니다.
- Default Area를 Walkable로 설정합니다.
- Bake를 누르면 Navmesh Data가 생성됩니다.

- AI 오브젝트에 NavmeshAgent 컴포넌트를 추가해줍니다.
- Speed: 이동 속도
- Angular Speed: 회전 속도
- Stopping Distance: 목표 지점에 멈출 거리
- Obstacle Avoidance: 장애물 회피 능력
public class TestAiController : MonoBehaviour
{
public Transform target;
private NavMeshAgent agent;
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
private void Update()
{
agent.SetDestination(target.position); // 목표 지점
}
}
- AI가 따라오기만 하는 테스트 코드를 작성해줍시다.

- 이미지와 같이 멈춰있는 것 보단 캐릭터를 따라 점프하는게 자연스러워 보일 듯 합니다. 그러기 위해서는 Off-Mesh Link를 설정해야 합니다.
- Off-Mesh Link : AI가 점프하거나 특정 경로를 건너게 하기 위한 기능

- Navigation 탭에 DropHeight와 JumpDistance의 값을 수정하고 Bake를 누르면 아래와 같이
Off-Mesh Link가 생성됩니다.
이 방법은 자동으로 Navmesh의 길이 끊겼을 때 생성해줍니다. 자동으로 생성되는 만큼 자신이 원하는 곳이나 세밀한 조절이 필요한 경우에는 수동으로 하면 좋을 듯 합니다.


- 플레이어를 따라 낙하합니다.
public class EnemyAI : MonoBehaviour
{
private NavMeshAgent agent;
public Transform player;
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
agent.SetDestination(player.position);
}
}
- Enemy의 경우에는 기존 TestAIController와 변동점이 없습니다. 따라다니기만 하기에..

- 기존 테스트 코드와 동일하게 동작합니다.
public class CompanionAI : MonoBehaviour
{
private NavMeshAgent agent;
public Transform player;
public float followDistance = 2.0f;
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
if (Vector3.Distance(transform.position, player.position) > followDistance)
{
agent.SetDestination(player.position);
}
else
{
agent.ResetPath();
}
}
}
- 플레이어를 따라다니지만 일정 거리 유지하도록 구현하였습니다.

- 플레이어를 따라오다 일정 거리에 도달하면 멈춥니다.
public class PatrollingEnemy : MonoBehaviour
{
private NavMeshAgent agent;
public Transform[] patrolPoints;
private int currentPoint = 0;
void Start()
{
agent = GetComponent<NavMeshAgent>();
agent.SetDestination(patrolPoints[currentPoint].position);
}
void Update()
{
if (!agent.pathPending && agent.remainingDistance < 0.5f)
{
currentPoint = (currentPoint + 1) % patrolPoints.Length;
agent.SetDestination(patrolPoints[currentPoint].position);
}
}
}
- 순찰 지점을 배열로 설정하고 특정 시간마다 다음 지점으로 이동하게끔 하였습니다.

- 순찰 할 나무들의 Transform들을 넣어주고 동작하였습니다. 배열에 들어간 순서대로 순찰합니다.
public class ExplorerAI : MonoBehaviour
{
private NavMeshAgent agent;
void Start()
{
agent = GetComponent<NavMeshAgent>();
InvokeRepeating("MoveToRandomLocation",0f,10f);
}
void MoveToRandomLocation()
{
Vector3 randomDirection = Random.insideUnitSphere * 10;
randomDirection += transform.position;
NavMeshHit hit;
if (NavMesh.SamplePosition(randomDirection, out hit, 10, 1))
{
agent.SetDestination(hit.position);
}
}
}
- Navmesh의 특정 시간마다 랜덤 위치로 이동하게끔 구현하였습니다.

- 랜덤한 위치를 일정한 시간을 기준으로 잡고 움직입니다.
길찾기 사용에 편함을 느꼇습니다. 기존 2D의 경우에는 직접 구현해줘야 했지만 3D의 Navigation의 경우에는 컴포넌트와 사용법만 숙지하면 쉽게 사용이 가능하여 편리하였습니다. 하지만 세밀한 조정이나 사용법이 생각보다 까다로워서 숙달하려면 많이 사용해보고 공부해야할 듯 합니다..