NavMesh와 AI MoveTo
14강. NavMesh와 AI MoveTo
1. 이번 강의에서 해결할 문제
목표 방향으로 AddMovementInput만 호출하니 적이 벽에 걸립니다. 레벨 충돌에서 생성된 NavMesh 그래프를 이용해 도달 가능한 경로를 요청합니다.
2. 학습 목표
3. 핵심 개념
Navigation System은 레벨 충돌로부터 이동 가능한 Mesh를 만들고 Polygon 비용을 바탕으로 경로를 찾습니다. 공식 Navigation System 문서는 Tile, Generation Mode, Area Cost와 회피 기능을 설명합니다.
방향 벡터는 목표가 어디 있는지 알려 주지만 벽을 우회할 경로는 알려 주지 않습니다. AIController가 MoveTo를 요청하고 Path Following과 CharacterMovement가 실제 이동을 처리합니다.
처음 등장하는 Navigation 용어
| 용어 | 역할 | 확인 위치 |
|---|---|---|
| NavMesh | 이동 가능한 표면을 Polygon 연결 관계로 표현한 길찾기 데이터 | Editor에서 P를 눌렀을 때 보이는 초록 영역 |
| NavMeshBoundsVolume | NavMesh를 생성할 공간 범위 | Place Actors와 레벨 Viewport |
| Navigation Agent | AI의 반지름·높이·이동 능력 규격 | Project Settings와 Character Capsule |
| 경로(Path) | 시작점부터 목적지까지 연결된 NavMesh 구간 | AI Debugger 또는 Path Following 로그 |
| Acceptance Radius | 목적지에 도착했다고 인정할 거리 | MoveToLocation 두 번째 인자 |
| AIController | 목표와 행동을 결정하고 이동을 요청하는 객체 | Pawn을 Possess한 Controller |
NavMesh가 초록색이라고 모든 AI가 반드시 지나갈 수 있는 것은 아닙니다. Agent 반지름보다 좁은 통로, NavMesh가 끊긴 높이 차, 잘못된 Capsule 설정은 경로 실패를 만듭니다. 먼저 공간 데이터를 확인한 뒤 C++ 이동 코드를 고쳐야 원인과 해결이 연결됩니다.
4. 단계별 실습
Unreal Editor에서 가장 작은 길찾기 환경 만들기
- 바닥에 Collision이 있는지 확인하고 Place Actors에서 NavMeshBoundsVolume을 배치해 바닥 전체를 감쌉니다.
- Viewport에서
P를 누르거나 콘솔에서show Navigation true를 실행해 초록색 이동 가능 영역을 확인합니다. - Collision이 있는 벽을 시작점과 TargetPoint 사이에 둡니다. 초록 영역이 벽을 통과하지 않고 주변으로 이어져야 합니다.
- Enemy Character의 Auto Possess AI 또는 Spawned 설정과 AI Controller Class를 확인합니다. Play 중 Controller가 AMathAIController여야 합니다.
- Capsule 크기와 Navigation Agent Radius가 통로 폭에 맞는지 확인합니다.
C++ · 파일 경로: Source/TopDownSurvival/AI/MathAIController.h · 이동 API
UFUNCTION(BlueprintCallable, Category = "AI|Movement")
bool MoveToReachableLocation(FVector Destination, float AcceptanceRadius);
C++ · 파일 경로: Source/TopDownSurvival/AI/MathAIController.cpp
#include "Navigation/PathFollowingComponent.h"
#include "NavigationSystem.h"
bool AMathAIController::MoveToReachableLocation(
FVector Destination, float AcceptanceRadius)
{
if (!GetPawn())
{
return false;
}
FNavLocation Projected;
UNavigationSystemV1* Navigation =
FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());
if (!Navigation ||
!Navigation->ProjectPointToNavigation(Destination, Projected))
{
UE_LOG(LogTemp, Warning, TEXT("Destination is outside NavMesh"));
return false;
}
const EPathFollowingRequestResult::Type Result = MoveToLocation(
Projected.Location,
FMath::Max(1.0f, AcceptanceRadius),
true,
true,
true,
false,
nullptr,
true);
return Result != EPathFollowingRequestResult::Failed;
}
코드와 반환값 이해하기
GetPawn()이 없으면 Controller가 움직일 대상이 없으므로 즉시 실패합니다.GetCurrent<UNavigationSystemV1>(GetWorld())는 현재 World의 Navigation System을 가져옵니다. Editor의 다른 World나 초기화 전에는 없을 수 있습니다.ProjectPointToNavigation은 임의의 Destination을 가까운 NavMesh 점으로 투영합니다. 함수가 실패하면 목표 주변에 사용 가능한 NavMesh가 없다는 뜻입니다.- Acceptance Radius는 최소 1로 제한해 음수나 0으로 생길 수 있는 불필요한 정밀 도착 요구를 피합니다.
- 이어지는 인자는 순서대로 Stop on Overlap, Pathfinding 사용, 목적지 투영, Strafe 허용, 기본 Query Filter, Partial Path 허용 정책입니다. bool 인자가 많으므로 호출 위에 정책 주석을 남기는 편이 안전합니다.
MoveToLocation은 이동이 끝날 때까지 기다리지 않습니다. 요청 직후Failed,AlreadyAtGoal,RequestSuccessful중 하나를 반환합니다.- 현재 wrapper는
Failed가 아니면true입니다. Partial Path를 허용했으므로 요청은 성공해도 목표 바로 앞까지 도달하지 못할 수 있습니다. 실제 도착·실패는OnMoveCompleted또는 Behavior Tree Task 결과에서 확인합니다.
Blueprint에서 요청하고 화면 결과 확인
BP_MathAIController 또는 테스트용 Actor에서 레벨의 TargetPoint 위치로 MoveToReachableLocation을 한 번 호출합니다. 반환값과 목적지를 Print String으로 남깁니다.
- TargetPoint가 같은 초록 영역 안에 있으면
true가 나오고 AI가 벽을 돌아 이동해야 합니다. - Pawn이 이미 Acceptance Radius 안이면
true지만 눈에 띄는 이동이 없을 수 있습니다. - NavMesh에서 멀리 떨어진 목표는 투영에 실패해 Warning 로그와
false가 나와야 합니다.
테스트용 BeginPlay 호출은 확인 후 제거합니다. Tick마다 재요청하면 경로를 불필요하게 다시 계산합니다.
5. 코드와 수학·AI가 동작하는 이유
ProjectPointToNavigation은 임의 목표를 가까운 NavMesh 위치로 투영합니다. MoveToLocation은 경로 요청 결과를 즉시 반환하며 실제 도착은 비동기입니다. 도착 후 행동은 Behavior Tree Task 완료나 MoveCompleted 이벤트로 연결해야 합니다.
6. 자주 하는 실수와 해결법
7. 직접 실습
실습 목표
NavMesh 안팎과 장애물 조건을 바꾸며 요청 승인과 실제 도착이 서로 다른 단계임을 확인합니다.
시작 전 상태
Enemy Character가 AMathAIController에 Possess되고, 바닥의 NavMesh가 초록색으로 보이며, 같은 영역에 TargetPoint가 하나 있어야 합니다.
1단계: 따라 하기
장애물이 없는 같은 NavMesh 안으로 요청합니다. 함수 반환 true, AI 이동 시작, Acceptance Radius 안에서 정지하는 세 결과를 순서대로 확인합니다.
2단계: 값 바꿔 보기
Acceptance Radius를 10과 200으로 바꿉니다. 200일 때는 목표에서 더 먼 곳에 멈춰도 도착으로 처리될 수 있습니다. “정확한 한 점”이 아니라 허용 반경 정책임을 화면 거리로 비교합니다.
3단계: 직접 적용
목표를 벽 뒤, NavMesh 밖, Agent보다 좁은 통로 뒤에 각각 둡니다. 다음 네 열로 표를 만드세요: P 시각화, 즉시 반환, 실제 이동, 완료 결과. 가능하면 OnMoveCompleted에서 Result Code를 로그로 남겨 요청 승인과 최종 결과를 분리합니다.
4단계: 스스로 확인
막혔을 때
| 증상 | 먼저 확인할 곳 | 해결 |
|---|---|---|
| 초록 영역이 전혀 없음 | Bounds Volume, 바닥 Collision, Navigation 생성 설정 | Volume이 바닥을 감싸는지와 바닥이 Navigation에 영향을 주는지 확인합니다. |
| 함수가 즉시 false | Pawn, Navigation System, 목적지 투영 | 어느 조건에서 반환했는지 Warning 로그를 나눠 추가합니다. |
| true지만 AI가 움직이지 않음 | 이미 도착 범위, Possess, Movement Component | Pawn-Controller 관계와 Acceptance Radius를 확인합니다. |
| 벽 앞에서 멈춤 | 경로가 끊기거나 Partial Path만 존재 | P 시각화, Agent Radius, 벽 주변 연결 영역을 확인합니다. |
8. 이해 점검 질문 3개
9. 핵심 요약
다음 강의 연결
다음 강의: Blackboard에서는 이동할 Target Actor와 Patrol Location을 AI별 판단 데이터로 저장해 Behavior Tree의 조건과 행동이 같은 목표를 읽게 합니다.
NavMesh와 AI MoveTo 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.