Search code examples
c++unreal-engine4behavior-tree

Retrieve Behavior Tree without using Blue Print


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.

Blue Print that only exists so that I can access my Behaviour Tree

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);
    }
}

Solution

  • 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;