먼저 NavMesh가 뭔지 알아보자. Unity에서는 한 위치에서 다른 위치로의 경로를 계산하고 실시간으로 장애물을 피하며 이동하는 인공지능을 만드는 Navigation
시스템을 제공한다. 이 Navigation 시스템에 사용되는 오브젝트가 크게 4가지가 있는데 다음과 같다.
- NavMesh : Agent가 걸어 다닐 수 있는 표면
- NavMesh Agent : NavMesh 위에서 경로를 계산하고 이동하는 캐릭터
- NavMesh Obstacle : Agent의 경로를 막는 장애물
- Off Mesh Link : 끊어진 NavMesh 영역 사이를 잇는 연결 지점 (뛰어넘을 수 있는 울타리나 타고 올라갈 수 있는 담벼락을 구현할 때 사용)
이러한 지식을 갖고 2D에서 NavMesh를 사용하는 법에 대해 알아보자.
Unity에서는 아쉽게도 2D에서 사용할 수 있는 NavMesh를 지원하지 않는다. 그래서 다른 사람이 만든 NavMeshPlus
를 사용하여 구현해야한다.
다운로드 및 사용법 : https://github.com/h8man/NavMeshPlus
위 깃허브에 적혀있는 사용법은 다음과 같다.
- 깃허브에서 다운로드한 NavMeshPlus-master 폴더를 내 프로젝트 Asset폴더에 넣는다.
- Scene에 빈 오브젝트를 만든다.
- 빈 오브젝트에
"Navigation Surface"
와"NavMeshCollecSources2d "
컴포넌트를 추가한다.- NavMeshCollecSources2d 컴포넌트에서
Rotate Surface to XY
를 클릭한다.- 장애물 오브젝트에
"Navigation Modifier"
컴포넌트를 추가하고 Override Area를 통해 Agent가 걸어다닐 수 있는 영역을 정한다.- Navigation Surface에서 Bake를 클릭한다.
이제 한번 예시를 통해 사용법을 익혀보자.
먼저 NavMeshPlus-master 폴더를 프로젝트의 Asset폴더에 넣는다.
그 다음 Unity에서 지원하는 오브젝트들을 활용해서 아래 사진과 같이 만든다.
Tilemap : Hierarchy창에서 우클릭 -> 2D Object -> Tilemap -> Rectangular
Plane : Hierarchy창에서 우클릭 -> 2D Object -> Sprites -> Square -> inspector창에서 크기 및 색상 변경
Wall : Plane과 동일
Agent : Hierarchy창에서 우클릭 -> 2D Object -> Sprites -> Circle
NavMesh : Hierarchy창에서 우클릭 -> Create Empty
그 후 NavMesh 오브젝트에 Navigation Surface와 NavMeshCollecSources2d 컴포넌트를 추가하고, Rotate Surface to XY를 클릭한다.
그리고 Plane과 Wall에 Navigation Modifier 컴포넌트를 추가해서 Override Area를 체크하고 Plane은 Walkable, Wall은 Not Walkable로 설정해준다.
다음으로 NaviMesh의 컴포넌트인 Navigation Surface에서 Bake를 클릭한다.
마지막으로 Agent 오브젝트에 Nav Mesh Agent 컴포넌트를 추가하고 테스트를 위한 아래 스크립트도 추가해주면 끝이다.
<예시> : 클릭시 클릭한 곳으로 Agent가 이동하는 스크립트
// NavMoveTest.cs
using UnityEngine;
using UnityEngine.AI;
public class NavMoveTest : MonoBehaviour
{
public Vector3 target;
NavMeshAgent agent;
void Awake()
{
agent = GetComponent<NavMeshAgent>();
agent.updateRotation = false;
agent.updateUpAxis = false;
}
void Update()
{
SetTargetPosition();
SetAgentPosition();
}
void SetTargetPosition()
{
if (Input.GetMouseButton(0))
{
target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
}
void SetAgentPosition()
{
agent.SetDestination(new Vector3(target.x, target.y, transform.position.z));
}
}
클릭한 위치로 이동할 때 벽을 피해서 이동하는 모습