오늘은 언리얼 엔진에서 AI 이동과 경로탐색(Pathfinding)을 구현하는 방법을 자세히 살펴본다.
언리얼 엔진의 경로탐색(Pathfinding) 원리
언리얼 엔진에서의 경로탐색 알고리즘 응용 방법
MoveToActor와 MoveToLocation 명령 활용법
이 세 가지를 이해하면 AI의 움직임을 제어할 수 있다.
📒학습 내용
1. 언리얼 엔진의 경로탐색(Pathfinding) 원리 이해하기
언리얼 엔진 AI는 목적지까지의 경로를 탐색할 때 가장 효율적인 경로를 자동으로 선택한다. 이 때 주로 사용하는 알고리즘은 A(A-Star)*나 다익스트라(Dijkstra) 알고리즘이다.
💡 핵심 개념: AI는 항상 비용(거리 또는 이동 난이도)이 가장 적게 드는 경로를 선택한다.
예를 들어, 한국에서 미국으로 가는 항공편이 있을 때 직항은 비용이 5, 일본을 경유하는 항공편은 비용이 3이라면, 엔진의 AI는 항상 비용이 더 적게 드는 일본 경유 경로를 선택한다. 이처럼 AI가 경로를 선택할 때 가장 효율적이고 비용이 적은 경로를 선택하는 것이 핵심이다.
2. 경로탐색 알고리즘 응용 방법 - Nav Modifier Volume 활용
언리얼 엔진은 기본적으로 NavMesh(내비게이션 메시)를 통해 AI의 이동 경로를 관리한다. 그러나 NavMesh는 런타임 중 동적 재생성이 어렵다는 단점이 있다.
🛑 문제점과 해결 방법
문제점: 런타임 중 네비메시 동적 수정 불가 → 동적 상황에 대응하기 어려움
해결책: Nav Modifier Volume을 사용하여 지역별 이동 비용을 실시간으로 조정할 수 있다.
혹여 프로젝트를 새로 오픈했을 때 설정값이 다이나믹이 아닐 수가 있으니 확인해보자.
해당 볼륨을 움직일 때마다 해당 네비메시 부분이 사라진다. 영역 클래스(Area Class) 세팅이 Null로 되어 있기 때문이다.
🔧 프로토타입 설계 단계별 정리
아래 단계를 순서대로 진행하면, Nav Modifier Volume을 통해 AI 이동 경로를 실시간으로 조정할 수 있다.
타겟포인트 설정.
Nav Modifier Volume을 배치하고, Default-Area Class를 NavArea_Obstacle로 설정
Mobility를 Movable로 설정
이동 비용이 높은 구역(주황색 영역)을 생성
이를 통해 AI는 실시간으로 가장 효율적인 경로를 선택하게 된다.
🛠️ Nav Modifier Volume을 런타임에서 이동시키면 AI는 이를 즉시 반영해 새로운 경로를 계산한다. 이를 활용하면 플레이어를 추적하거나 전술적인 움직임을 구현할 때 매우 유용하다.
3. AI의 이동 명령: MoveToActor와 MoveToLocation 명령 이해하기
레벨 블루프린트 열고, NaviModifierVolume을 (드래그앤드랍)참조한다. 아래와 같이 블루프린트를 세팅하고 0번을 누르게 되면,
여기서 문제 발생! 디버깅을 위해 0번을 눌러도 아무런 동작을 이뤄지지 않는다. ➡️ 스태틱이 아닌 무버블로 Set을 해줘야 된다.
지정키를 누르게 되면 AI가 지정 구역을 피해서 왕복하는 것을 볼 수 있다. 그리고 코드를 보게 되면 `MoveToTarget()`안에 있는 내장 함수 `MoveToLocation()`가 핵심적인 메소드이다.
지금까지의 과정에서는 MoveToLocation 기능을 사용했다.
AI의 이동 명령은 크게 MoveToActor와 MoveToLocation으로 나뉜다. 두 기능은 AIController 안에 내장되어 있는 시스템이다. 두 함수의 주요 차이점과 활용법을 명확히 이해하자.
명령어
특징 및 활용법
MoveToLocation
정적인 특정 좌표로 이동할 때 사용
MoveToActor
동적인 타겟(Actor)을 따라 이동할 때 사용
MoveToLocation 함수
EPathFollowingRequestResult::Type MoveResult = AIController->MoveToLocation(
TargetLocation,
AcceptanceRadius,
true, // 목적지에 오버랩 되면 도착으로 판정할지 여부.
true, // 경로 찾기 사용
false, // 프로젝션 사용 안함
true // 네비게이션 데이터 사용
);