본문 바로가기

게임프로그래밍/실습1

[언리얼 실습] 56. 에너미 패트롤 하기.


목차

  1. 에너미 패트롤 시키기

1. 에너미 패트롤 시키기

 

에너미가 일정 위치를 지속적으로 순찰하는 기능을 만들어 보려고 한다.

 

패트롤 타겟을 여러개 만들고 이 타켓들을 순찰하게 하고 싶은데 그러기 위해서 이 타켓들을 배열에 담아서 보관해야 한다.

 

C++에서 이 작업을 해보자. 에너미 클래스에 변수를 선언할 것이다.

 

// 현재 순찰중인 타켓
UPROPERTY(EditInstanceOnly, Category = "AI Navigation")
AActor* PatrolTarget;

// 타켓 배열
UPROPERTY(EditInstanceOnly, Category = "AI Navigation")
TArray<AActor*> PatrolTargets;

 

PatrolTarget은 현재 에너미가 향하고 있는 목표이다. CombatTarget이 nullptr이 되면 이 타겟을 따라 이동하게 할 것이다.

 

PatrolTargets 배열은 순찰할 목표들을 담을 배열이다.

 

이제 이 타겟 배열에서 타겟을 뽑고 그쪽으로 이동하게 하게 구현해보자.

 

가장 먼저 BeginPlay() 함수에서 첫 타겟을 쫒아가게 할 것이다. 에너미를 움직이기 위해서는 AIController를 가져올 필요가 있고 그러기 위해서는 추가적인 모듈이 필요하다.

 

빌드파일에 AIModule을 포함해주자. 그 다음 헤더파일에  AIController를 저장할 변수를 선언해주자. C++에서는 AIController 맨 앞에 A가 한번더 붙는다.

 

UPROPERTY()
class AAIController* EnemyController;

 

그리고 BeginPlay() 함수에서 이를 할당하고 MoveTo 함수를 통해 에너미가 이동하는 것을 구현해보자.

 

void AEnemy::BeginPlay()
{
	Super::BeginPlay();
	if (HealthBarWidget)
	{
		HealthBarWidget->SetVisibility(false);
	}

	EnemyController = Cast<AAIController>(GetController());
	if (EnemyController)
	{
		EnemyController->MoveTo()
	}
}

 

MoveTo() 함수의 매개변수로는 어떤 값을 넣어주어야 할까?

 

언리얼 문서에서 나와있는 매개변수는 다음과 같다.

virtual FPathFollowingRequestResult MoveTo  
(  
    const FAIMoveRequest & MoveRequest,  
    FNavPathSharedPtr * OutPath  
)

 

MoveRequest 는 FAIMoveRequest 는타겟 액터나 도착지의 위치, 도착 후 행동, 경로지정 여부등의 정보를 가지고 있는 구조체라고 한다. 더 자세한 정보는 언리얼 문서에서 확인할 수 있다.

 

OutPath 는 경로 정보를 반환받기 위한 FNavPathSharedPtr 타입의 포인터로 주로 디버깅을 하기 위해 사용한다.

 

FAIMoveRequest 구조체 먼저 정의해보자.

 

FAIMoveRequest MoveRequest;
MoveRequest.SetGoalActor(PatrolTarget);
MoveRequest.SetAcceptanceRadius(15.f);

 

SetGoalActor() 로 목표인 액터를 정해주었고,

SetAcceptanceRadius() 에서 목표에 얼마나 가까이 접근하는지를 지정해주었다.

 

이제 OutPath 변수를 만들어주자.

FNavPathSharedPtr NavPath;

 

FNavPathSharedPtr는 이미 타입자체가 포인터로 지정되어있기 때문에 따로 * 연산자를 쓰지 않아도 된다고 한다. 이제 MoveTo() 함수에 매개변수들을 넣어주면 된다.

 

EnemyController->MoveTo(MoveRequest, &NavPath);

 

NavPath는 경로정보를 저장한다고 하였다. 이 변수로부터 정보를 받아와보자.

 

NavPath->GetPathPoints();

 

그런데 이렇게 하면 에러가 나는 것을 볼 수 있다. FNavPathSharedPtr, 정확히는 FNavigationPath의 타입을 알지 못한다. 헤더파일을 가져올 필요가 있다.

 

 

#include "Navigation/PathFollowingComponent.h"

 

위의 헤더파일을 가져오면 된다. 해당 헤더파일을 가져오면 FNavigationPath  타입뿐 아니라 FAIMoveRequest 타입정의도 함께 들어있어 오류를 해결할 수 있다.

 

TArray<FNavPathPoint>& PathPoints = NavPath->GetPathPoints();

 

 

이제 다음과 같이 하여 FNavPathPoint 배열을 만들고 이 지점들을 그려보자

 

TArray<FNavPathPoint>& PathPoints = NavPath->GetPathPoints();
for (const FNavPathPoint& Point : PathPoints)
{
	const FVector& Location = Point.Location;
	DrawDebugSphere(GetWorld(), Location, 12.f, 12.f, FColor::Green, false, 20.f);
}

 

이렇게 하면 이제 AI 이동하는 경로를 시작적으로 볼 수 있게 된다.

 

이제 컴파일하고 잘 되는지 확인해보자. 물론 패트롤 타겟을 설정하는 것을 잊으면 안된다.

 

 

에너미가 타겟으로 이동하는 것은 물론 이동할때 목표로 지정하는 경로를 볼 수 있다.

 

이렇게 해서 에너미를 목표까지 이동하게 하였다. 하지만 현재는 순찰이 아닌 단순 이동일뿐이다. 다음에는 순찰 기능을 구현해보려고 한다.