I followed the Behavior Tree Quick Start Guide and got everything to work simply enough.
I'm now trying to convert the Follower_AI_CON
controller from a Blue Print to C++ but I can't get a reference to the Behaviour Tree (using only C++).
I'm able to get a reference by creating a Blue Print that has a parent class of AIController
and selecting my Behaviour Tree from within the editor (image below) but that seems wasteful considering I won't be using the Blue Print for anything other than that tiny dropdown menu.
I've spent a frustrating number of hours on what appears to be a simple task. I guess I'm not as smart as I lead people to believe! :D
My bare-bones .h / .cpp files look like this:
.h
UCLASS()
class THIRDPERSON_API AAIController : public AAIController
{
GENERATED_BODY()
ATPAIController(const class FObjectInitializer& ObjectInitializer);
public:
virtual void Possess(class APawn* InPawn) override;
// Reference to the AI's blackboard component.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
UBlackboardComponent* BlackboardComponent;
// The Behavior Tree Component used by this AI.
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
UBehaviorTreeComponent* BehaviorTreeComponent;
UPROPERTY(EditDefaultsOnly, Category = "AI")
class UBehaviorTree* BehaviorTree;
};
.cpp
AAIController::AAIController(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
BlackboardComponent = ObjectInitializer.CreateDefaultSubobject<UBlackboardComponent>(this, TEXT("EnemyAIBlackboard"));
BehaviorTreeComponent = ObjectInitializer.CreateDefaultSubobject<UBehaviorTreeComponent>(this, TEXT("EnemyAIBehaviorTree"));
}
void AAIController::Possess(APawn* InPawn)
{
Super::Possess(InPawn);
if (BehaviorTree)
{
BlackboardComponent->InitializeBlackboard(*BehaviorTree->BlackboardAsset);
BehaviorTreeComponent->StartTree(*BehaviorTree, EBTExecutionMode::Looped);
}
}
So you need to specify a behavior tree without making an AIController blueprint? You have two options:
Hardcode the path
You can hardcode the path to your tree in your code and then load it. But this approach is not very data-driven:
FString Path = "/Game/AIStuff/FollowerBT";
UBehaviorTree* Tree = Cast<UBehaviorTree>(StaticLoadObject(UBehaviorTree::StaticClass(), nullptr, *Path.ToString()));
Set somewhere else
Set the tree in some other global class that you have a blueprint for. I would put it in a custom GameMode Blueprint and then retrieve it:
UBehaviorTree* Tree = Cast<AMyGameMode>(GetWorld()->GetAuthGameMode())->MyBehaviorTree;