서의 공간

AIController에서 BehaviorTreeComponent 본문

Unreal Engine

AIController에서 BehaviorTreeComponent

홍서의 2021. 12. 12. 16:15

AI Blackboard 생성 관련 질문있어요 : 네이버 카페 (naver.com)

 

위 글을 먼저 참고하여 두 번째 경우에서 조금 다른 경우를 살펴보자.

BehaviorTree를 컨트롤러가 아닌 캐릭터에 설정하는 방식이다. 

Enemy 클래스(.h)에 다음과 같이 변수를 정의하고, 블루프린트에서 BehaviorTree 애셋을 설정할 것이다.

/** Behavior tree for the AI Character*/
UPROPERTY(EditAnywhere, Category = "Behavior Tree", meta = (AllowPrivateAccess = "true"))
class UBehaviorTree* BehaviorTree;

다음은 AEnemy 클래스에서 BeginPlay 함수 부분이다. 

void AEnemy::BeginPlay()
{
	...
	// Get the AI Controller
	EnemyController = Cast<AEnemyController>(GetController());

	...
	if (EnemyController)
	{
		...
		EnemyController->RunBehaviorTree(BehaviorTree);
		...
	}
}

다음은 이어지는 RunBehaviorTree 함수 코드이다.

bool AAIController::RunBehaviorTree(UBehaviorTree* BTAsset)
{
	...
	if (bSuccess)
	{
		// 이 부분을 주목한다.
		UBehaviorTreeComponent* BTComp = Cast<UBehaviorTreeComponent>(BrainComponent);
        // BTComp가 NULL이면 UBehaviorTreeComponent 인스턴스를 새롭게 생성한다.
		if (BTComp == NULL)
		{
			UE_VLOG(this, LogBehaviorTree, Log, TEXT("RunBehaviorTree: spawning BehaviorTreeComponent.."));

			BTComp = NewObject<UBehaviorTreeComponent>(this, TEXT("BTComponent"));
			BTComp->RegisterComponent();
		}
		
        // 앞서 BrainComponent는 NULL일 수도 있고, 아닐 수도 있다.
        // 새로 만든 BTComp는 기존 BrainComponent의 값과 같거나, 새롭게 할당한 값이다.
		// make sure BrainComponent points at the newly created BT component
		BrainComponent = BTComp;

		check(BTComp != NULL);
		BTComp->StartTree(*BTAsset, EBTExecutionMode::Looped);
	}

	return bSuccess;
}

호출 순서를 확인해본다. 컨트롤러와 캐릭터 사이에서 초기 함수 호출 순서는 다음과 같다.

EnemyController::OnPossess -> EnemyController::PostInitializeComponents -> EnemyController::BeginPlay -> Enemy::BeginPlay

 

다음 코드 OnPossess에서는 캐릭터에 설정된 BehaviorTree 애셋이 결정되지 않으므로, BehaviorTreeComponent의 애셋은 아직 없다. BlackboardComponent->InitializeBlackboard(..) 함수를 통해 BlackboardComponent는 초기화된다.

void AEnemyController::OnPossess(APawn* InPawn)
{
	Super::OnPossess(InPawn);
	if (InPawn == nullptr) return;
    
	AEnemy* Enemy = Cast<AEnemy>(InPawn);
	if (Enemy)
	{
		if (Enemy->GetBehaviorTree())
		{
			BlackboardComponent->InitializeBlackboard(*(Enemy->GetBehaviorTree()->BlackboardAsset));
		}
	}
}

그 다음 EnemyController::PostInitializeComponents 호출이 되는데, 다음은 부모 클래스의 구현부분이다. 주석 부분을 보자.

void AAIController::PostInitializeComponents()
{
	Super::PostInitializeComponents();
	...
	// 이 부분을 주목. BrainComponent가 nullptr이라면, FindComponentByClass를 통해
	// Component를 생성하고 초기화한다.
	if (BrainComponent == nullptr)
	{
		BrainComponent = FindComponentByClass<UBrainComponent>();
	}
	if (Blackboard == nullptr)
	{
		Blackboard = FindComponentByClass<UBlackboardComponent>();
	}
	...
}

이어서 FindComponentByClass 함수를 살펴보자.

// 다음은 AIController.cpp의 일부
/** Templatized version of FindComponentByClass that handles casting for you */
template<class T>
T* FindComponentByClass() const
{
	static_assert(TPointerIsConvertibleFromTo<T, const UActorComponent>::Value, "'T' template parameter to FindComponentByClass must be derived from UActorComponent");

	return (T*)FindComponentByClass(T::StaticClass());
}

// 다음은 Actor.cpp의 일부
UActorComponent* AActor::FindComponentByClass(const TSubclassOf<UActorComponent> ComponentClass) const
{
	UActorComponent* FoundComponent = nullptr;

	if (UClass* TargetClass = ComponentClass.Get())
	{
		// 현재 actor가 가지고 있는 모든 컴포넌트는 OwnedComponents에 저장되어있다.
		for (UActorComponent* Component : OwnedComponents)
		{
			if (Component && Component->IsA(TargetClass))
			{
				FoundComponent = Component;
				break;
			}
		}
	}

	return FoundComponent;
}

 

결론:

BrainComponent는 컨트롤러 클래스에 정의된 BehaviorTreeComponent와 같은 주소를 참조한다. 이 부분은 AAIController::PostInitializeComponent에서 확인할 수 있다. 만약 컨트롤러 클래스에 BehaviorTreeComponent가 없다면, 새로 컴포넌트를 생성한다. 이 과정은 RunBehaviorTree 함수에서 확인 가능하다.

최종적으로 BehaviorTreeComponent는 캐릭터에 설정된 BehaviorTree 애셋을 통해 StartTree를 실행한다.

 

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

컨트롤러 방향  (2) 2021.12.16
Set Timer 사용법  (0) 2021.12.12
속도, MakeFromX, MakeRotFromX  (0) 2021.11.09
Pawn  (0) 2021.11.09
[UMG] Drag & Drop  (0) 2021.10.29
Comments