01 Navigation Mesh
바닥, 장애물과 같은 게임 월드의 정보를 미리 저장해두고 에이전트가 이동할 때, 저장된 정보를 바탕으로 장애물을 피해 목표 위치까지 이동하는 경로 탐색을 제공함.
→ 이를 위해 게임 월드에 Navigation Mesh를 설정하고 각각의 컴포넌트를 이동하도록 할 수 있다.
우선 본격적인 실습에 앞서, 영상 강의에서 제공된 실습 자료를 다운받아 인포트해준 후 해당 프리팹을 Hierarchy 뷰로 가져왔다.
▶ Navigation View : Navigation Mesh 설정 (Window - AI - Navigation)
하지만, 이때 나는 네비게이션 뷰가 없어서 패키지 메니저에서 따로 설치를 진행해주었다.
02 Navigation View
(1) Navigation View - Agents
: 네비게이션 메시 정보를 바탕으로 움직이는 에이전트에 대한 설정 (NavMeshAgent 컴포넌트)
✅ Agent Type
에이전트 속성으로, “+”로 새로운 에이전트 속성을 추가할 수 있다
✅ Agnet 정보
- Name : Agent Type에 보여지는 이름
- Radius : 에이전트의 반지름
- Height : 에이전트의 높이 키
- Step Height : 오르내릴 수 있는 계단의 높이
- Max Slope : 올라갈 수 있는 경사 각도
(2) Navigation View - Areas
: 네비게이션 메시로 사용되는 오브젝트들의 구역 설정
✅ Name
구역 이름으로 기본으로 Walkable (이동 가능), Not Walkable (이동 불가능), Jump (뛰기)가 제공되고 User 3부터 원하는 구역을 추가로 설정할 수 있다
✅ Cost
구역과 함께 등록 이동하는데 소요되는 비용 (1 이상) 경로를 탐색할 때 Cost 정보를 기준으로 최단거리를 찾게 된다. Cost가 2인 Jump는 Cost가 1인 Walkable을 지나갈 때 보다 2배의 시간이 걸린다는 뜻으로 사용된다
▶ 실제 오브젝트의 물리적인 이동 속도가 느려 지는 것이 아닌 경로를 계산할 때 활용된다
(3) Navigation View - Bake
: 네비게이션 메시 데이터를 생성
✅ Baked Agent Size
- Agent Radius : 에이전트가 지나갈 수 있는 반지름
- Agent Height : 에이전트가 아래로 지나갈 수 있는 높이
- Max Slope : 에이전트가 올라갈 수 있는 경사 각도
- Step Height : 에이전트가 오르내릴 수 있는 계단의 높이
✅ Generated Off Mesh Links
오프 메시 링크는 올라가기 힘든 언덕, 사다리, 절벽 등을 연결해서 이동 가능하게 만드는 옵션이다
- Drop Height : 이동할 수 있는 절벽 아래의 높이
- Jump Distance : 뛰어서 넘을 수 있는 절벽 거리
✅ "Bake" 버튼
Navigation에 설정된 옵션들을 바탕으로 네비게이션 정보를 데이터로 굽는다
(4) Navigation View - Object
: 현재 씬에 있는 오브젝트 설정 (하나 or 다수)
✅ Scene Filter
현재 씬에서 원하는 오브젝트만 선택해서 볼 수 있다
(Mesh Renderer 컴포넌트, Terrain 컴포넌트 선택 가능)
✅ 선택된 오브젝트
- Navigation Static : 네비게이션 메시로 사용할지 설정
- Generate OffMeshLinks : 자동으로 Off Mesh를 생성할지 설정
- Navigation Area : 해당 오브젝트의 구역 설정
(설정되는 구역에 따라 해당 오브젝트의 Cost가 설정)
03 Navigation Mesh 데이터 생성
📌 게임 오브젝트의 'Navigation Static' 설정 방법
원하는 게임 오브젝트를 선택한 후
방법 1) Inspector View의 Static - Navigation Static 선택
방법 2) Navigation View의 Object 탭에 있는 'Navigation Static' 변수 체크
네비게이션 static 설정을 완료한 후, 다음 단계로 넘어가보자.
Navigation View - Bake 탭의 "Bake" 버튼을 누르면 현재 설정된 정보를 바탕으로 Navigation Mesh 데이터가 생성된다. 그럼 위와 같은 화면을 볼 수 있다.
이때, Scene View를 보면 하늘색으로 표시된 부분이 이동 가능한 부분으로, Navigation View가 활성화되어 있어야 Navigation Mesh가 출력되는 것을 확인할 수 있다.
📌 Tip.
맵에 새로운 바닥, 장애물을 배치하였다면 Navigation Static 설정과 Bake를 다시 진행해야 한다.
04 경사각(Max Slope)과 계단 높이(Step Height) 설정
▶ 경사각 설정 - Max Slope
Bake 탭의 Max Slope 값으로 설정된 경사각까지 이동이 가능하다.
▶ 계단 높이 설정 - Step Height
오르내릴 수 있는 계단의 최대 높이로, 설정된 높이 이하의 계단만 이동할 수 있다.
이후 실습을 위해 3D 오브젝트를 하나 생성하고 Material를 만들어 오브젝트에 색상까지 입혀줄 수 있다.
05 NavMeshAgent 기반의 캐릭터 이동
Navigation Mesh 정보를 바탕으로 작동하려면 NavMeshAgent가 필요하다. 즉, 플레이어 오브젝트의 컴포넌트로 이를 추가해줄 수 있다.
(1) NavMeshAgent 컴포넌트
: 네비게이션 메시 정보를 기반으로 이동하는 에이전트
✅ 에이전트 이동 (Steering)
- Speed : 이동 속도
- Angular Speed : 방향을 바꿀 때의 회전 속도
- Acceleration : 가속도 (정지 상태에서 이동속도가 될 때까지 적용)
- Stopping Distance : 목적지가 이 값까지 가까워지면 이동을 멈추게 된다
- Auto Braking : 목적지에 가까워지면 멈추는 기능
- 목적지에 도착해도 에이전트를 멈추지 않을 때 사용
- 여러 목적지를 계속 탐색하는 Patrol에 주로 사용
✅ 장애물 회피 (Obstacle Avoidance)
- Radius : 장애물을 회피할 때 에이전트의 반지름
- Height : 에이전트의 높이
- Quality : 장애물과 충돌 수준 (None 이면 뚫고 지나간다)
- Priority : 장애물과 충돌했을 때의 우선순위 (낮을 수록 높다)
→ 이동 중인 두 에이전트의 모든 조건이 동일할 때 Priority가 낮은 에이전트가 더 우선권을 가지고 경로를 탐색하게 된다
✅ 경로 탐색 (Path Finding)
- Auto Traverse Off Mesh Link : 오프 메시 링크가 있을 경우 자동으로 탐색해서 찾아갈지 설정
- Auto Repath : 이동 중에 경로 탐색을 다시 할지 설정 (true : 이동 중에 장애물 등으로 막혔을 때 자동으로 재 계산)
- Area Mask : 해당 에이전트의 이동 가능한 구역 지정
📌 Movement.cs 스크립트 코드
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 goalPosition) { // 기존에 이동 행동을 하고 있었다면 코루틴 중지 StopCoroutine("OnMove"); // 이동 속도 설정 navMeshAgent.speed = moveSpeed; // 목표 지점 설정 navMeshAgent.SetDestination(goalPosition); // 이동 행동에 대한 코루틴 시작 StartCoroutine("OnMove"); } IEnumerator OnMove() { while (true) { // 목표 위치와 내 위치의 거리가 0.1 미만일 때 즉, 목표 위치레 거의 도착했을 때 if ( Vector3.Distance(navMeshAgent.destination, transform.position) < 0.1f ) { // 내 위치를 목표 위치로 설정 transform.position = navMeshAgent.destination; // SetDestination()에 의해 설정된 경로를 초기화. 이동을 멈춤 navMeshAgent.ResetPath(); break; } yield return null; } } }
✅ Physics.Raycast()를 이용한 오브젝트 선택
우리가 바라보는 화면은 2차원 모니터이고, 게임 세상은 3차원으로 이루어져 있다. 즉, 2 차원(2D)을 통해 3차원(3D)의 오브젝트를 제어해야 한다.
▶ 구현 원리
- 카메라로부터 플레이어가 클릭한 마우스 위치를 관통하는 광선을 쏜다
- 현재 카메라에 보이는 화면을 관통해 뻗어나가는 광선은 우리가 지정한 길이에 도달하거나 오브젝트에 부딪히면 멈춘다
- 오브젝트에 부딪혀 멈추게 되면 부딪힌 오브젝트의 정보를 반환한다
→ 광선에 부딪혔다 = 마우스로 선택한 오브젝트이다
📌 PlayerController.cs 스크립트 코드
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 = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit, Mathf.Infinity)) { movement3D.MoveTo(hit.point); } } } }
작성한 두 코드를 플레이어 오브젝트의 컴포넌트로 삽입하고 메인 카메라가 게임 화면 전체를 볼 수 있도록 위치를 설정한 후에 게임을 실행해보자.
이후 게임을 실행하면 마우스를 클릭하는 대로 원하는 위치로 이동하는 것을 볼 수 있다.
출처 : 따라하면서 배우는 고박사의 유니티 기초(https://inf.run/sgcy)
'Study > Unity' 카테고리의 다른 글
[Unity 3D Basic] 3D Model / Animations (0) | 2024.05.15 |
---|---|
[Unity 3D Basic] Navigation Mesh 응용 (0) | 2024.05.15 |
[Unity 3D Basic] CharacterController 기반의 오브젝트 이동 (1) | 2024.05.08 |
[Unity 2D Basic] 2D Tilemap - Extras (0) | 2024.05.08 |
[Unity 2D Basic] 2D Tilemap Editor (0) | 2024.05.08 |