Navigation Mesh는 에이전트가 이동할 때 저장된 게임 월드 정보를 바탕으로 장애물을 피해 목표 위치까지 이동하는 경로 탐색을 제공합니다. 사용하는 방법은 다음과 같습니다.
※ Navigation Mesh를 사용하기 위해 Package Manger에서 AI Navigation 설치 후 Window > AI > Navigation(obsolete) 뷰를 활성화합니다.
Navigation Mesh 데이터 생성
Navigation Mesh 데이터를 생성하려면 게임 월드 오브젝트를 Navigation Static 설정해야 합니다. Navigation(obsolete) 뷰의 Object 탭의 Scene Filter 중 Mesh Renderers 선택 후 오브젝트를 선택해 Navigation Static를 활성화합니다.
적절한 오브젝트에 Navigation Static을 활성화했다면, Navigation(obsolete) 뷰의 Bake 탭의 Bake 버튼을 누르면 설정한 정보를 바탕으로 Navigation Mesh 데이터가 생성됩니다.
잘 생성되었다면, Scene의 게임 월드에 이동 가능한 구역이 하늘색으로 표시됩니다.
Nav Mesh Agent 기반 캐릭터 이동
Navigation Mesh 데이터 기반의 캐릭터 이동을 위해 이동 에이전트 오브젝트에 Nav Mesh Agent 컴포넌트를 등록합니다.
Nav Mesh Agent 컴포넌트는 Navigation Mesh 데이터를 기반으로 이동합니다. 에이전트의 타입, 이동, 장애물 회피, 경로 탐색 관련 정보를 설정할 수 있습니다.
이동을 제어하는 Movement3D와 PlayerController 스크립트를 작성합니다.
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
public class Movement3D : MonoBehaviour
{
[SerializeField]
private float moveSpeed = 5.0f; //이동 속도
private NavMeshAgent navMeshAgent;
private void Awake()
{
navMeshAgent = GetComponent<NavMeshAgent>();
}
public void MoveTo(Vector3 direction) //(방향정보)
{
//코루틴 중지(기존 이동 가능성)
StopCoroutine("OnMove");
//이동 속도 저장
navMeshAgent.speed = moveSpeed;
//목표지점 설정 (현재 위치부터 매개변수의 목표 위치까지 경로 계산 후 자동 이동)
navMeshAgent.SetDestination(direction);
//이동 행동 코루틴 시작
StartCoroutine("OnMove");
}
IEnumerator OnMove() //목표 지점까지 이동했는지 검사
{
while (true)
{
//목표와 내 위치 거리 차이가 0.1 미만일 때
if (Vector3.Distance(navMeshAgent.destination, transform.position) < 0.1f)
{
transform.position = navMeshAgent.destination; // 내 위치에 목표 위치 저장
navMeshAgent.ResetPath(); // 경로 초기화(이동 정지)
break;
}
yield return null;
}
}
}
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private Movement3D movement3D;
private void Awake()
{
movement3D = GetComponent<Movement3D>();
}
private void Update()
{
if (Input.GetMouseButtonDown(0)) //마우스 왼쪽 버튼 눌렀을 때
{
RaycastHit hit;
// 카메라에서 마우스 좌표 위치를 관통하는 광선 생성 후 ray 저장
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//광선 발사해 부딪히는 오브젝트 검출
//(ray 위치에서 ray 방향으로 무한 길이 광선 발사, 부딪힌 오브젝트를 hit에 저장)
if (Physics.Raycast(ray, out hit, Mathf.Infinity))
//hit.point: 광선과 오브젝트가 부딪힌 세부 위치
movement3D.MoveTo(hit.point); //hit.point(목표위치)로 이동
}
}
}
작성한 두 스크립트를 이동 에이전트 오브젝트의 컴포넌트로 등록합니다.
Off Mesh Link 설정
Off Mesh Link는 절벽, 사다리 등 메시 연결이 끊어진 지형을 이동할 수 있게 설정합니다. 수직으로 올라가거나 내려가는 길, 절벽 사이를 뛰거나 떨어지는 것 등 액션을 자동 또는 수동으로 설정할 수 있습니다.
Off Mesh Link | 장점 | 단점 |
자동 | - 많은 오브젝트 한번에 설정 가능 | - 낙하 높이, 점프 거리 하나만 설정 가능 ← 다양한 지형 세세한 설정 불가 - 올라가는 설정 불가 (점프, 내려가는 설정만 가능 |
수동 | - 지형에 따라 세세한 설정 가능 - 올라가는 설정 가능 (사다리, 암벽 등) |
- 필요한 모든 위치에 연결 지점이 되는 오브젝트를 생성하고 Off Mesh Link 컴포넌트를 설정해야 함 |
자동 Off Mesh Link 설정
수동 Off Mesh Link 설정
Nav Mesh Obstacle
Navigation Mesh 데이터는 Bake로 미리 저장하기 때문에, 게임 내에서 오브젝트 이동 시 매쉬 데이터가 새로 생성되지 않습니다. 그래서 게임 내에서 이동하는 장애물의 경우, Nav Mesh Obstacle 컴포넌트를 이용해 실시간으로 Navigation Mesh 데이터를 관리해야 합니다.
Nav Mesh Obstacle 컴포넌트는 장애물의 모양, 중심 위치, 공간 데이터 갱신 조건 등을 설정할 수 있습니다.
이동하는 장애물 오브젝트, 장애물이 이동할 위치들의 오브젝트를 생성하고 장애물이 이동할 수 있도록 스크립트를 작성해 추가합니다.
using UnityEngine;
public class SimplePatrol : MonoBehaviour
{
[SerializeField]
private Transform[] paths; //순찰 경로
private int currentPath = 0; //목표지점 인덱스
private float moveSpeed = 3.0f; //이동 속도
void Update()
{
// 이동 방향 = (목표 - 내 위치).정규화
Vector3 direction = (paths[currentPath].position - transform.position).normalized;
// 이동
transform.position += direction * moveSpeed * Time.deltaTime;
// 목표 위치 거의 도달 시
if ((paths[currentPath].position - transform.position).sqrMagnitude < 0.1f)
{
//목표 위치 변경
if (currentPath < paths.Length - 1) currentPath++; //0이면 1
else currentPath = 0; // 1이면 0
}
}
}
위 코드를 통해 장애물 오브젝트가 paths 배열에 등록된 오브젝트 위치들로 순차적으로 이동합니다. 이 스크립트를 장애물 오브젝트의 컴포넌트로 등록 후 추가했던 이동 위치 오브젝트들을 paths 배열에 등록합니다.
그 후 장애물에 NavMeshObstacle 컴포넌트를 추가해 위와 같이 설정 후 게임을 실행하면, 장애물이 이동하고, 해당 위치가 이동 불가능하도록 Navigation Mesh 데이터가 실시간으로 변화합니다.
해당 포스트는 고박사, 따라하면서 배우는 고박사의 유니티 기초, (2020, 7월 6일), 섹션 3. 유니티 3D 기초 (Unity 3D Basic) (126:31) 강의를 참고하여 작성하였습니다.
Corner Unity
Editor : 동동
[유니티 소소모임] 3주차. 유니티 에디터 배우기 2 (Editor: 니나노) (1) | 2024.11.08 |
---|---|
[유니티 소소모임] 3주차. 유니티 에디터 배우기 2 (Editor : Ijin) (0) | 2024.11.08 |
[유니티 소소모임] 3주차. 유니티 에디터 배우기 2 (Editor: Borybop) (0) | 2024.11.08 |
[유니티 소소모임] 3주차. 유니티 에디터 배우기 2 (Editor : Hetbahn) (0) | 2024.11.08 |
[유니티 소소모임] 3주차. 유니티 에디터 배우기 2 (Editor: Luna) (0) | 2024.11.08 |