Unreal Engine - AI (1)

2025. 4. 25. 16:01·Unreal Engine
목차
  1. 1. NavMeshBoundVolume
  2. 2. 장애물 설정하기 (Nav Modifier Volume)
  3. 3. RVO (Reciprocal Velocity Obstacles)
  4. 4. 캐릭터 추적
  5. 5. 자동 네비게이션 링크

1. NavMeshBoundVolume


1 - 1. Overview

NavMeshBoundVolume은 AI가 움직이는 영역을 정의할 수 있는 범위를 말한다.

  • 액터 배치 -> 볼륨 -> 내비메시 바운드 볼륨

 

해당 볼륨의 특징으로는 기본적인 세팅에서는 동적인 범위 생성이 불가능하다는 점이다.

  • 아래와 같이 레벨에 설치 후 단축키 P를 통해서 내비메시가 깔린 범위를 체크할 수 있다.

 

그러나 게임 플레이 도중, 장애물이나 여러 움직임에 따라 내비메시의 범위를 조절하고 싶다면, Dynamic 설정을 해주어야 한다.

  • 프로젝트 세팅 -> 엔진 -> 네비게이션 메시 -> 런타임 -> 런타임 생성
  • 디폴트 값으로는 static으로 되어있지만, 동적으로 생성하기 위해서는 dymamic을 선택해주면 된다.

 

1 - 2. Dynamic 종류

Dynamic

  • 동적으로 경로를 재구성하고, 경로를 빼기 및 더하기 작업을 동시에 수행한다.
  • 사진에서 파란색 액터 위에 영역 생성 (더하기 작업)

Dynamic Modifiers Only

  • 동적으로 경로를 재구성하지만, 경로를 빼기만 한다는 것이 차이점
  • 사진에서 위의 사진과 달리 영역이 생기지는 않고, 빼기 작업만 수행
  • 사용하기 위해서는 NavModifier 컴포넌트가 필요하다.

 

1 - 3. Navigation Invoker

언리얼 엔진의 네비메시는 브러시 방식을 사용하기 때문에, 런타임 중 동적 생성이 불가능하다는 단점이 존재한다.

그렇기 때문에, AI가 레벨 전체에서 돌아다니는 경우 레벨 전체에 네비매시를 깔아두어야하는 비효율적인 결과가 생긴다.

  • 이것을 해결하기 위해 존재하는 것이 "네비 인보커" 이다.
  • 네비 인보커는 Navigation Invoker 컴포넌트를 가진 액터의 주변 영역만 계산하여 리소스를 아끼는 시스템이다.

네비 인보커를 사용하기

  • 먼저 Build.cs에 아래 처럼 NavigationSystem 모듈 추가
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "NavigationSystem" });
  • NPC에 컴포넌트 추가
//헤더
#pragma region NavInvoker
	UPROPERTY(BlueprintReadWrite, Category = Navigation, meta = (AllowPrivateAccess = "true"))
	TObjectPtr<UNavigationInvokerComponent> NavInvoker;

	float NavGenerationRadius;

	float NavRemovalRadius;

	FORCEINLINE class UNavigationInvokerComponent* GetNavInvoker()const { return NavInvoker; }
#pragma endregion

//cpp
NavInvoker = CreateDefaultSubobject<UNavigationInvokerComponent>(TEXT("NavInvoker"));
NavInvoker->SetGenerationRadii(NavGenerationRadius, NavRemovalRadius);
  • 프로젝트 세팅
    • 내비게이션 매시의 런타임 생성은 Dynamic으로 설정 해준다.
    • 내비게이션 시스템 -> 내비게이션 실행 -> 내비게이션 인보커 주변에만 내비게이션 실행 -> true

 

실행 모습

  • 레벨 전체에 내비메시가 생기지 않고 NPC(AI) 주변에만 생기는 것을 확인할 수 있다.

 

 

2. 장애물 설정하기 (Nav Modifier Volume)


2 - 1. Overview

내비메시 내에 장애물을 두어, "런타임"에 AI가 장애물을 피해서 이동하는 것을 구현해보기

 

대체로 게임 내에서 경로찾기에 있어서는 A*나 다익스트라 방식을 사용한다.

  • 이 방식들은 경로의 가중치를 모두 체크해본 다음 가장 코스트가 적은 경로를 선택하는 방식이다.
  • 언리얼 내부적으로 어떤 방식을 쓰는지는 모르지만, 실습을 통해 동작하는 모습은 체크해 볼 수 있다.
  • 장애물을 런타임에 생성하기 위해 Nav Modifier를 사용한다.

장애물 설정

  • Nav Modifier volume을 레벨에 설치하고,
  • 설정을 Movable과 Obstacle로 바꾸기

  • 추가적으로 장애물을 피해서 이동할 경로를 만들기 위해 액터 배치 -> 타깃 포인트 를 배치해준다.

내비 모디파이어를 Obstacle로 설정하면 아래와 같이 빨간색으로 표시가 되는데, 이것은 해당 지역이 주변 지역(초록색) 보다 계산 cost가 높다는 의미이다. (피해가야 한다는 의미가 된다.)

 

2 - 2. 실습

AI 캐릭터에 아래와 같이 컨트롤러 세팅을 해준 후

//헤더
UPROPERTY()
AAIController* AIController;

//cpp
void AUE5_AIStudyCharacter::BeginPlay()
{
	Super::BeginPlay();

	AIController = Cast<AAIController>(GetController());

	if (IsValid(AIController))
	{
		AIController->ReceiveMoveCompleted.RemoveDynamic(this, &ThisClass::OnMoveCompleted);
		AIController->ReceiveMoveCompleted.AddDynamic(this, &ThisClass::OnMoveCompleted);

		FindTargetPoints();
		StartMoving();
	}
}

void AUE5_AIStudyCharacter::NotifyControllerChanged()
{
	Super::NotifyControllerChanged();

	if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
		{
			Subsystem->AddMappingContext(DefaultMappingContext, 0);
		}
	}
	else //AI
	{
		AIController = Cast<AAIController>(Controller);
		if (IsValid(AIController))
		{
			AIController->ReceiveMoveCompleted.AddDynamic(this, &ThisClass::OnMoveCompleted);
		}
	}
}

 

움직임 함수와 바인딩을 하여, AI가 움직일 수 있도록  아래의 로직 순서로 세팅을 해준다.

  • 타겟 포인트를 찾는 함수(FindTargetPoints) 를 실행 후
  • 해당 타깃으로 이동하는 함수 실행 (MoveToTarget) 
  • 움직임이 완료되면, 바인딩된 OnMoveCompleted 함수를 통해 flag 값을 변경 후 타이머를 통해 다시 MoveToTarget 함수 실행

기억할 것 (AI를 움직이도록 하는 함수)

  • MoveToActor
EPathFollowingRequestResult::Type MoveResult = AIController->MoveToLocation(
TargetLocation,
AcceptanceRadius,
true,  // 목적지에 오버랩 되면 도착으로 판정할지 여부.
true,  // 경로 찾기 사용
false, // 프로젝션 사용 안함
true   // 네비게이션 데이터 사용
);
  • MoveToLocation
EPathFollowingRequestResult::Type MoveToLocation(
const FVector& Dest, //목적지 위치
float AcceptanceRadius = -1, //AI가 목적지에 도달했다고 판단하는 거리
bool bStopOnOverlap = true, //목적지와 캐릭터의 충돌 영역이 겹쳤을때 도착 여부 처리
bool bUsePathfinding = true, //경로 탐색 알고리즘 쓸지(false면 직선 이동)
bool bProjectDestinationToNavigation = true, //목적지를 네비메시에 투영할지
bool bCanStrafe = false, //AI가 측면이동을 할 수 있는지
TSubclassOf<UNavigationQueryFilter> FilterClass = nullptr, //필터 클래스
bool bAllowPartialPath = true //완전한 경로를 찾지 못하면 부분 경로를 가도록 허용할지
);

 

실행 결과 모습

 

 

3. RVO (Reciprocal Velocity Obstacles)


3 - 1. Overview

RVO란 움직이는 객체들이 서로의 속도와 방향을 고려하며 충돌을 피하는 방법을 말한다.

경로의 재계산 없이 속도와 방향을 조정하여 "실시간 회피"가 가능하기 때문에, 다수의 액터가 있을때 효율적인 움직임을 구현할 수 있다.

 

이미 언리얼에 구현되어 있기 때문에, 변수를 조절하여 움직임을 구현할 수 있다.

  • GetCharacterMovement()->bUseRVOAvoidance 
    • true로 설정하여 RVO를 켤 수 있다.
  • GetCharacterMovement()->AvoidanceConsiderationRadius
    • AI가 다른 오브젝트를 감지하고, 회피를 시작하는 반경을 뜻한다.
    • 대략적으로 200 ~ 500 사이의 값이 적당하다 (그러나 액터의 크기나 특징에 따라 다르게 설정할 수 있다)
  • GetCharacterMovement()->AvoidanceWeight
    • 회피 우선순위를 결정하는 변수
    • 클수록(1에 가까울수록) 다른 캐릭터들이 우선적으로 피하는 존재가 된다.

 

3 - 2. 실습

  • 새로운 캐릭터 클래스를 하나 만든 후, RVO 세팅을 해준다.
  • 이후 BeginPlay에서 MoveToActor를 사용하여 target을 향해 움직이도록 구현
ARVO_NPC::ARVO_NPC()
{
	PrimaryActorTick.bCanEverTick = false;

	// RVO 회피 시스템 활성화
	UCharacterMovementComponent* MovementComponent = GetCharacterMovement();
	if (MovementComponent)
	{
		MovementComponent->bUseRVOAvoidance = true;
		MovementComponent->AvoidanceConsiderationRadius = AvoidanceRadius;
		MovementComponent->AvoidanceWeight = 0.5f;
	}
}

void ARVO_NPC::BeginPlay()
{
	Super::BeginPlay();
	
	AIController = Cast<AAIController>(GetController());

	if (!AIController)
	{
    		return;
	}
	else if (TargetActor)
	{
		MoveToTarget();
	}
}

 

위처럼 구현하면 아래와 같이 좁은 구간에 있어서 AI들이 피해가며 원하는 목적지까지 움직인다.

  • 장애물은 Nav Modifier를 null로 설정

 

만약 RVO를 끈 경우 아래와 같이 좁은 길목에서 지나가지 못하는 상황이 생긴다.

 

 

4. 캐릭터 추적


 

 

5. 자동 네비게이션 링크


내비게이션 메시의 끊어진 부분을 자동으로 연결하여 AI 캐릭터의 경로 탐색을 향상시키는 기능

 

구현 방법

  • 레벨에 존재하는 RecastNavMesh에 Generate Nav Links 를 true로 체크

  • 추가적으로 GeneratedNavLinksProxy를 통해 기능을 추가해 줄 수 있다.
    • link를 만난 경우 Z 축으로 점프를 하는 기능을 구현했다.

  • Proxy 등록을 위해서는 아래의 화면에서 등록을 할 수 있다.
    • 추가적으로 Link의 값들을 조정하기 위해서 아래 값들을 수정할 수 있다.

 

 

'Unreal Engine' 카테고리의 다른 글

Unreal Engine - 데디케이티드 서버 8 (게임 흐름)  (0) 2025.05.02
Unreal Engine - AI (2)  (0) 2025.04.29
Unreal Engine - 멀티플레이 네트워크 최적화 2  (0) 2025.04.23
Unreal Engine - 멀티플레이 네트워크 최적화 1  (0) 2025.04.22
UE5 Issues - 리슨 서버 게임 이슈들  (0) 2025.04.18
  1. 1. NavMeshBoundVolume
  2. 2. 장애물 설정하기 (Nav Modifier Volume)
  3. 3. RVO (Reciprocal Velocity Obstacles)
  4. 4. 캐릭터 추적
  5. 5. 자동 네비게이션 링크
'Unreal Engine' 카테고리의 다른 글
  • Unreal Engine - 데디케이티드 서버 8 (게임 흐름)
  • Unreal Engine - AI (2)
  • Unreal Engine - 멀티플레이 네트워크 최적화 2
  • Unreal Engine - 멀티플레이 네트워크 최적화 1
gbleem
gbleem
gbleem 님의 블로그 입니다.
gbleem 님의 블로그gbleem 님의 블로그 입니다.
  • gbleem
    gbleem 님의 블로그
    gbleem
  • 전체
    오늘
    어제
    • 분류 전체보기 (184)
      • Unreal Engine (73)
      • C++ (19)
      • 알고리즘(코딩테스트) (27)
      • TIL (60)
      • CS (4)
      • 툴 (1)
  • 블로그 메뉴

    • 홈
    • 카테고리
  • 링크

    • 과제용 깃허브
    • 깃허브
    • velog
  • 공지사항

  • 인기 글

  • 태그

    const
    DP
    addonscreendebugmessage
    enhanced input system
    actor 클래스
    map을 vector로 복사
    싱글턴
    gamestate
    C++
    blend pose
    상속
    매크로 지정자
    템플릿
    BFS
    motion matching
    cin함수
    character animation
    Vector
    additive animation
    applydamage
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
gbleem
Unreal Engine - AI (1)

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.