01 Navigation Mesh
- NavMeshAgent : 네비게이션 메시 정보를 바탕으로 이동하는 오브젝트
- OffMeshLink : 연결이 끊어져 있는 절벽, 낭떠러지, 사다리 등을 이동 가능하게 설정
- Navigation Mesh : 게임월드에 이동 가능, 이동 불가능 등의 경로를 데이터로 저장
- NavMeshObstacle : 이동하는 장애물의 네비게이션 메시 정보를 실시간으로 설정
유니티 네비게이션 시스템 - NavMesh (2023.09.26)
Window >> Package Manager >> Unity Registry >> AI Navigation위 순서로 'AI Navigation' 에셋을 다운받는다.다시 Window >> AI >> Navigation(Obsolete)를 눌러준다.아래 창이 뜨면 된다.
velog.io
나는 Navigation View가 없어서 위의 글을 참고했다.
그리고 설치 후 에러가 떠서 재로그인을 했다.
Navigation View : Navigation Mesh 설정
02 Navigation View
Agents
네비게이션 메시 정보를 바탕으로 움직이는 에이전트에 대한 설정 (NavMeshAgent 컴포넌트)
- Agent Type
- 에이전트 속성
- “+”로 새로운 에이전트 속성을 추가할 수 있다
- Agnet 정보
- Name : Agent Type에 보이는 이름
- Radius : 에이전트의 반지름
- Height : 에이전트의 높이(키)
- Step Height : 오르내릴 수 있는 계단의 높이
- Max Slope : 올라갈 수 있는 경사 각도
Areas
네비게이션 메시로 사용되는 오브젝트들의 구역 설정
- Name
- 구역 이름으로 기본으로 Walkable(이동 가능), Not Walkable(이동 불가능), Jump(뛰기)가 제공되고, User 3부터 원하는 구역을 추가로 설정할 수 있다
- Cost
- 구역과 함께 등록. 이동하는데 소요되는 비용 (1 이상) 경로를 탐색할 때 Cost 정보를 기준으로 최단거리를 찾게 된다
- Cost가 2인 Jump는 Cost가 1인 Walkable을 지나갈 때 보다 2배의 시간이 걸린다는 뜻으로 사용된다 (실제 오브젝트의 물리적인 이동 속도가 느려지는 것이 아닌 경로를 계산할 때 활용된다)
Bake
네비게이션 메시 데이터를 생성
- Baked Agent Size
- Agent Radius : 에이전트가 지나갈 수 있는 반지름
- Agent Height : 에이전트가 아래로 지나갈 수 있는 높이
- Max Slope : 에이전트가 올라갈 수 있는 경사 각도
- Step Height : 에이전트가 오르내릴 수 있는 계단의 높이
- Generated Off Mesh Links
- 오프 메시 링크는 올라가기 힘든 언덕, 사다리, 절벽 등을 연결해서 이동 가능하게 만드는 옵션이다
- Drop Height : 이동할 수 있는 절벽 아래의 높이
- Jump Distance : 뛰어서 넘을 수 있는 절벽 거리 Bake 네비게이션 메시 데이터를 생성
- “Bake” 버튼
- Navigation에 설정된 옵션들을 바탕으로 네비게이션 정보를 데이터로 굽는다
Object
현재 씬(Scene)에 있는 오브젝트 설정 (하나 or 다수)
- Scene Filter
- 현재 씬에서 원하는 오브젝트만 선택해서 볼 수 있다 (Mesh Renderer 컴포넌트, Terrain 컴포넌트 선택 가능)
- 선택된 오브젝트
- Navigation Static : 네비게이션 메시로 사용할지 설정
- Generate OffMeshLinks : 자동으로 Off Mesh를 생성할지 설정
- Navigation Area : 해당 오브젝트의 구역 설정 (설정되는 구역에 따라 해당 오브젝트의 Cost가 설정된다)
03 Navigation Mesh 데이터 생성
게임 오브젝트의 "Navigation Static" 설정 방법
원하는 게임오브젝트를 선택한 후 Navigation View의 Object 탬에 있는 Navigation Static 변수 체크
Navigation View의 Bake 탭에서 “Bake” 버튼 선택하면 현재 설정된 정보를 바탕으로 Navigation Mesh 데이터 생성
Scene View를 보면 하늘색으로 표시되는 부분이 이동 가능한 부분 (Navigation View가 활성화되어 있어야 NavMesh가 출력된다)
Bake된 네비게이션 메시 데이터는 현재 씬 이름과 동일한 폴더 안에 생성됨
04 경사각(Max Slope)과 계단 높이(Step Height) 설정
Max Slope가 45이기 때문에 45보다 높은 “Slope02”는 경로가 이어지지 않는다
Step Height가 0.4이고, 인접한 두 계단 사이의 높이가 0.4이기 때문에 Step Height 값을 넘지 않아 이동 경로가 생성된다
하지만 오른쪽의 경우 Step Height가 0.4이고, 인접한 두 계단 사이의 높이가 0.5이기 때문에 Step Height 값을 넘어 이동 경로가 생성되지 않는다.
- 플레이어 오브젝트 생성
- GameObject - 3D Object - Capsule
- 오브젝트에 적용할 material 생성
- Project View - “+” - Material
05 NavMeshAgent 기반의 캐릭터 이동
NavMeshAgent를 Player의 컴포넌트로 등록한다.
NavMeshAgnet 컴포넌트
네비게이션 메시 정보를 기반으로 이동하는 에이전트
에이전트 이동(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 : 해당 에이전트의 이동 가능한 구역 지정
이동 제어를 위한 스크립트 작성(Movement3D)
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 )
{
// 목표 위치(navMeshAgent.destination)와 내 위치(transform.position)의 거리가 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)의 오브젝트를 제어해야 한다.
구현 원리
1. 카메라로부터 플레이어가 클릭한 마우스 위치를 관통하는 광선을 쏜다
2. 현재 카메라에 보이는 화면을 관통해 뻗어나가는 광선은 우리가 지정한 길이에 도달하거나 오브젝트에 부딪히면 멈춘다
3. 오브젝트에 부딪혀 멈추게 되면 부딪힌 오브젝트의 정보를 반환한다 (광선에 부딪혔다 = 마우스로 선택한 오브젝트이다)
PlayerController 스크립트
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private Movement3D movement3D;
private void Awake()
{
movement3D = GetComponent<Movement3D>();
}
private void Update()
{
// 마우스 왼쪽 버튼을 눌렀을 때
if ( Input.GetMouseButtonDown(0) )
{
RaycastHit hit;
// Camera.main : 태그가 "Camera"인 오브젝트 = "Main Camera"
// 카메라로부터 마우스 좌표(Input.mousePosition) 위치를 관통하는 광선 생성
// ray.origin : 광선의 시작 위치
// ray.direction : 광선의 진행 방향
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
// Physics.Raycast() : 광선을 발사해서 부딪히는 오브젝트를 검출
// (광선에 부딪히는 오브젝트가 있으면 true 반환)
// ray.origin 위치로부터 ray.direction 방향으로 무한한 길이(Mathf.Infinity)의 광선 발사
// 광선에 부딪히는 오브젝트의 정보를 hit에 저장
if ( Physics.Raycast(ray, out hit, Mathf.Infinity) )
{
// hit.transform.position : 부딪힌 오브젝트의 위치
// hit.point : 광선과 오브젝트가 부딪힌 세부 위치
// hit.point를 목표위치로 이동!
movement3D.MoveTo(hit.point);
}
}
}
}
Player 오브젝트에 작성한 두 스크립트를 적용하고
카메라가 게임월드를 전체적으로 볼 수 있도록 위치와 회전값을 수정하고 실행한다.
우리가 선택하는 위치로 Player 오브젝트가 이동하는 것을 확인할 수 있다.
현재 이동경로가 없는 사다리나 높은 경사면, 절벽 등을 선택하게 되면 근처까지만 이동을 하고 더 이상 이동을 하지 못한다.
'PBL > Unity' 카테고리의 다른 글
유니티 3D 기초 - 3D Model / Animations (0) | 2024.05.14 |
---|---|
유니티 3D 기초 - Navigation Mesh 응용 (0) | 2024.05.14 |
유니티 3D 기초 - CharacterController 기반의 오브젝트 이동 (0) | 2024.05.07 |
유니티 2D 기초 - 2D Tilemap Editor (0) | 2024.05.07 |
유니티 2D 기초 - 2D Animation 실습 (0) | 2024.04.30 |