본문 바로가기
언리얼 C++ 게임 개발의 정석/11. AI 컨트롤러와 비헤어비어 트리

11.3 NCP의 추격 기능 구현

by ftftgop3 2024. 5. 2.

블랙 보드 변수 추가

NCP가 플레이어를 발견 시 정보를 블랙 보드에 저장

Object 타입 Target 변수 생성, 기반 클래스 ABcharacter 지정

 

NPC 행동 패턴

플레이어를 발견 했는지 안했는지 에 따라 추격 및 순찰로 구분

셀렉터 컴포짓을 사용 해 트리 확장

추격에 우선 적으로 동작 할 수 있게 확장

Move To 태스트에 BlackboardKey : Target 지정

 

서비스 노드 사용

독립적 으로 동작하지 않고 컴포짓 노드에 부착 되는 노드

해당 컴포짓 노드에 속한 태스트가 동작 할 때 같이 실행 

플레이어를 감지 하기에 적합 

 

서비스 노드 구현

BTservice 부모로 하는 BTservice_Detect 클래스 생성

서비스 노드 활성화 시 TickNode 함수를 Interval 주기에 따라 호출

 

TickNode 함수에는 NPC 위치 기준으로 6미터 내의 캐릭터 감지

여러 캐릭터가 존재 할 수 있어서 OverlapMultiByChannel 함수 사용

캐릭터 정보를 Tarray로 전달

 

UCLASS()
class ARENABATTLE_API UBTService_Detect : public UBTService
{
	GENERATED_BODY()
	
public:
	UBTService_Detect();

protected:
	virtual void TickNode(
    UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds) override;
};

#include "ABAIController.h"
#include "ABCharacter.h"
#include "BehaviorTree/BlackboardComponent.h"
#include "DrawDebugHelpers.h"

UBTService_Detect::UBTService_Detect()
{
	NodeName = TEXT("Detect");
	Interval = 1.0f;
}

void UBTService_Detect::TickNode(UBehaviorTreeComponent & OwnerComp, uint8 * NodeMemory, float DeltaSeconds)
{
	Super::TickNode(OwnerComp, NodeMemory, DeltaSeconds);
	//현재 컨트롤 중인 액터 참조
	APawn* ControllingPawn = OwnerComp.GetAIOwner()->GetPawn();
	if (nullptr == ControllingPawn) return;
	
	UWorld* World = ControllingPawn->GetWorld();
	//엑터 위치 값
	FVector Center = ControllingPawn->GetActorLocation();
	//충돌 범위
	float DetectRadius = 600.0f;

	if (nullptr == World) return;
	//충돌 시 리턴 되는 액터 정보
	TArray<FOverlapResult> OverlapResults;
	FCollisionQueryParams CollisionQueryParam(NAME_None, false, ControllingPawn);
	bool bResult = World->OverlapMultiByChannel(
		OverlapResults,
		Center,//액터 위치
		FQuat::Identity,
		ECollisionChannel::ECC_GameTraceChannel2, //Attack 트레이스 채널(공격과 같은 채널)
		FCollisionShape::MakeSphere(DetectRadius),//구 충돌체 사용
		CollisionQueryParam
	);
    //충돌 객체를 찾기 못하면 nullptr 입력
    OwnerComp.GetBlackboardComponent()->SetValueAsObject(AABAIController::TargetKey, nullptr);
	//디버그용 렌더링
	DrawDebugSphere(World, Center, DetectRadius, 16, FColor::Red, false, 0.2f);
}

서비스 노드를 배치 

BTservice_Detect 를 Selector 서비스 노드로 배치  

 

NPC 탐지 영역에서 플레이어 컨트롤러 찾기

플레이어 컨트롤러를 파악 할 수 있는 IsPlayerController 함수 사용

캐릭터 감지 시 블랙 보드의 Target 값에 플레이어 캐릭터 등록 실패 시 Nullptr

 

ABAIController 에 Targetkey 추가 

UCLASS()
class ARENABATTLE_API AABAIController : public AAIController
{
	GENERATED_BODY()
    static const FName TargetKey;
}
//Cpp
const FName AABAIController::TargetKey(TEXT("Target"));

BTservice_Detect 수정

충돌 된 액터에 플레이어 컨트롤러 확인 

디버그로 캐릭터 감지 시 녹색 구체, 캐릭터와 연결된 선을 렌더링

 

ABCharacter controlMode 추가

NCP 상태 추가, 방향에 따라 회전 할수 있게 캐릭터 무브먼터 설정

최대 이동 속도가 플레이어 보다 낮게 설정

부자연스럽게 움직이는 부분 보강

 

UCLASS()
class ARENABATTLE_API AABCharacter : public ACharacter
{
	GENERATED_BODY()
protected:
    enum class EControlMode
	{
		GTA,
		DIABLO,
		NPC
	};
    
    virtual void PossessedBy(AController* NewController) override;
}

void AABCharacter::SetControlMode(EControlMode NewControlMode)
{
	//...
	case EControlMode::NPC:
		//이동 방향에 따라 회전 설정
		bUseControllerRotationYaw = false;
		GetCharacterMovement()->bUseControllerDesiredRotation = false;
		GetCharacterMovement()->bOrientRotationToMovement = true;
		GetCharacterMovement()->RotationRate = FRotator(0.0f, 480.0f, 0.0f);
		break;
	}
}

void AABCharacter::PossessedBy(AController * NewController)
{
	Super::PossessedBy(NewController);
	//플레이어 컨트롤러 이면 
	if (IsPlayerControlled())
	{
		//디아블로 상태로 이동 속도 600
		SetControlMode(EControlMode::DIABLO);
		GetCharacterMovement()->MaxWalkSpeed = 600.0f;
	}
	else
	{
		//AIcontroller 이면 속도 300
		SetControlMode(EControlMode::NPC);
		GetCharacterMovement()->MaxWalkSpeed = 300.0f;
	}
}

 

 비헤어비어 트리 데코레이터 노드 사용

서비스 노드로 Target 키 값을 존재 여부 확인

블랙 보드의 값을 기반으로 특정 컴포짓의 실행 여부를 결정하는 데코레이터 노드 사용

 

추격 동작에 데코레이터 추가

키 값의 변경 감지 되면 현재 컴포짓 노드 실행 취소 할수 있게 변경

관찰자 중단 항목을 지정하지 않으면 태스가 모두 마무리 될때  까지 대기( 플레이어가 시야 밖인데 추적)

관찰자 중단에 Self로 지정

블랙 노드의 Target 키 설정

 

순찰 동작에 데코레이터 추가

반대 조건인 Is Not set 으로 지정, 동일하게 관찰자 중단 옵션 설정