오늘 한 일
- 팀 프로젝트 기획 후 진행
- AI 내비게이터 배우기
유니티의 기능 AI 길찾기 기능 중 하나로 런타임 이전에 이동 가능한 영역을 지정하고, Nav Mesh Agent 컴포넌트를 활용하여 해당 AI에게 길찾기 능력을 부여해주는 기능이다.
Navigation Mesh (네비게이션 매쉬)
- 3D 공간을 그리드로 나누어 이동 가능한 영역과 불가능한 영역을 구분하는 매쉬입니다.
캐릭터는 이 영역을 기반으로 경로를 계산해서 이동합니다.
- 하나는 움직이지 않는 지형을 위한 영역 지정이고 또 다른 하나는 움직이는 오브젝트를 위한 영역 지정이다.
Pathfinding(경로 탐색)
- 캐릭터의 현재 위치에서 목표 지점까지 가장 적절한 경로를 찾는 알고리즘입니다.
- 주로 A* 알고리즘 등이 사용되며, 지정된 목표 위치까지 최단 경로를 탐색합니다.
Steering Behavior (스티어링 동작)
- 캐릭터나 NPC가 경로를 따라 이동할 때보다 자연스러운 동작을 구현하는데 사용됩니다.
- 동적으로 캐릭터의 이동 방향과 속력을 조정하여 부드럽고 현실적인 이동을 시뮬레이션 합니다.
Obstacle Avoidance (장애물 피하기)
- 캐릭터가 이동 중에 장애물과 충돌하지 않도록 하는 기술입니다.
각종 센서나 알고리즘을 사용하여 장애물을 감지하고 피하는 동작을 수행합니다.
Local Avoidance (근접 회피)
- 여러 캐릭터나 NPC가 서로 충돌하지 않도록 하는 기술입니다.
캐릭터들 사이의 거리를 유지하거나 회피 동작을 수행하여 서로 부딪히지 않도록 합니다.
NavMesh 영역 정하기
1. 내비게이션 (Obsolete)
들어가기 전에 기초 설명
Agents
- 길 찾기를 수행할 Agent들의 Obstacle Avoidance를 설정하고 모으는 리스트이다.
Areas
- 각 영역의 가중치 값을 정하는데 사용하는 항목이다.
Bake
- 모든 기초 설정이 완료되었다면, Bake를 하여 Agents들의 이동 영역을 산출해준다.
Object
- 선택한 오브젝트들에게 Area를 부여해주는 곳이다
- Navigation Static을 선택해주지 않으면, 해당 오브젝트에게서 이동 영역을 산출해줄 수 없다.
이동 가능 영역 Bake하기
- 내비게이션(Obsolete) 창 열기
- Object를 선택하고 Inspector창에 있는 Navigation (Obsolete) 창을 선택한다.
- Bake를 하기 전에 Static을 활성화하고, 원하는 Area를 설정한다.
- 산출하고자 하는 오브젝트들에게 Object 설정을 해줬다면 Bake를 해주자
- 필자는 이동영역이 붕뜨는 것을 방지하기 위해서 Radius를 0.1로 설정하고 Bake한다.
- 아래와 같이 보이긴한데 흐릿하게 보인다면 잘 산출된 것이다.
NavMeshAgent로 영역 통한 이동 구현하기
이제 이동 영역을 정했으니 이동 영역을 사용하는 동물을 만들어보자
NavMeshAgent 컴포넌트
- AI Navigation을 활용한 캐릭터의 이동을 위해서는 들어가야하는 컴포넌트로 오브젝트의 자연스러운 이동이나 장애물 피하기 경로 찾기 설정들을 할 수 있다.
- 원하는 오브젝트에다가 위 컴포넌트를 추가시키자!
각종 설정
Steering
- Speed 최대 이동 속도(초당 월드 단위로)
- Angular Speed 최대 회전 속도(초당 각도)
- Acceleration 최대 가속(제곱 초당 월드 단위로)
- Stopping distance 에이전트는 목표 위치에 가까워졌을 시 정지합니다.
- Auto Braking 활성화 시 에이전트는 목적지에 다다를 때 속도를 줄입니다.
에이전트가 멀티플 포인트 사이에서 부드럽게 움직여야 하는 순찰과 같은 동작을 할 때에는 반드시 비활성화 시켜야 합니다.Obstacle Avoidance
Radius 에이전트의 반경은 장애물과 다른 에이전트 간의 충돌 계산하기 위해 사용됩니다.
Height 에이전트가 장애물 밑으로 지나갈 수 있는 높이 간격입니다.
Quality 장애물 회피 품질입니다. 에이전트의 수가 많다면 장애물 회피 품질을 줄임으로써 CPU 시간을 절약할 수 있습니다. 회피를 없음으로 설정할 경우 충돌만 해결할 수 있을 뿐 다른 에이전트와 장애물에 대한 적극적인 회피는 하지 않습니다.
Priority 낮은 우선 순위의 에이전트는 이 에이전트의 회피 대상에서 제외됩니다.
값은 0에서 99사이에서 설정되어야 하며 낮은 숫자가 높은 우선 순위임을 의미합니다.
필요한 기초 코드
// 네임스페이스 using UnityEngine.AI; // 컴포넌트 가져오기 NavMeshAgent agent; void Awake() { agent = GetComponent<NavMeshAgent>(); }
기초적으로 사용하게될 각종 NavMeshAgent의 멤버들
프로퍼티
- isStopped: NavMesh 에이전트가 현재 경로를 따라 이동을 중지하거나 계속하는지를 설정하거나 가져옵니다.
( 해당 설정을 활성화 시에는 NavMeshAgent를 이용한 움직임이 정지됩니다.)- remainingDistance: 에이전트의 위치와 현재 경로의 목적지 사이의 거리를 나타냅니다.
메서드
- bool SamplePosition(Vector3 sourcePosition, out AI.NavMeshHit hit, float maxDistance, int areaMask)
(NavMesh) sourcePosition으로부터 지정된 maxDistance 내에서 가장 가까운 NavMesh의 지점을 찾습니다.- bool SetDestination(Vector3 target)
목적지를 설정하거나 업데이트하여 새 경로에 대한 계산을 트리거합니다.추가적인 설명
- NavMeshHit
-> NavMesh 쿼리에 대한 결과 정보가 담겨져있다.
프로퍼티 : distance, hit, mask, normal, position
배회하는 코드
void Update() { // 플레이어 감지 playerDistance = (transform.position - CharacterManager.Instance.Player.transform.position).sqrMagnitude; // sqr을 활용했으니 제곱하는 걸 잊지 맙시다. WanderingState(); } void WanderingState() { if (agent.remainingDistance < 0.1f) { NewWanderingPoint(); } } private void NewWanderingPoint() { NavMesh.SamplePosition(transform.position + (Random.onUnitSphere * detectDistance), out NavMeshHit hit, detectDistance, NavMesh.AllAreas); agent.SetDestination(hit.position); }
- 위 코드는 목표에 도착하면 주기적으로 목적지를 계속 바꾸는 코드이다.
적용 결과
- 자신의 주위로 계속해서 배회한다. (detectDistance를 1로 설정해두었다.)
각종 코드 주의 사항
- SetDestination을 사용할 때 곧바로 Vector3를 넣으면 의도된대로 작동이 안될 수도 있다.
-> Navmesh를 벗어난 목적지로 설정해버릴 경우 그대로 자리에서 멈춰버린다.- SamplePosition은 랜덤으로 정하는 게 아니라 받은 sourceposition값에서 가장 가까운 NavMesh를 찾는 역할을 하는 것이다.
- SamplePosition은 위와 같은 과정으로 포지션 값을 뽑는 것이고, 만약에 적절한 NavMesh 값을 찾지 못하면 false를 반환한다.
유니티
NavMeshAgent
NavMeshAgent의 멤버
영상
[유니티] 클릭 이동 구현하기 | Navigation(NavMesh) - 오늘코딩