I have made an AI Controller for my pawns which runs the behavior tree on BeginPlay(). The BehaviorTree seems to work but only one of my pawns move. I have checked to make sure ALL my pawns are utilising the AIController I have made and the UE_LOGs support that they are being invoked.
Why would only one pawn move? below is some attached code:
AIController:
AShipAiController::AShipAiController()
{
BTC = CreateDefaultSubobject <UBehaviorTreeComponent>(TEXT("BehaviorTreeComp"));
BBC = CreateDefaultSubobject<UBlackboardComponent>(TEXT("BlackboardComp"));
}
void AShipAiController::BeginPlay()
{
Super::BeginPlay();
//Start the behavior tree
if (IsValid(BehaviorTree.Get()))
{
RunBehaviorTree(BehaviorTree.Get());
//BTC->StartTree(*BehaviorTree.Get());
}
}
void AShipAiController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
//When AI takes control of our pawn, check for the blackboard and behavior tree
if (IsValid(Blackboard.Get()) && IsValid(BehaviorTree.Get()))
{
Blackboard->InitializeBlackboard(*BehaviorTree.Get()->BlackboardAsset.Get());
}
else { UE_LOG(LogTemp,Warning,TEXT("Failure to Get Blackboard or BehaviorTree (line39 ShipAiContoller.cpp)")); }
}
My Custom BTTask for the behavior tree code:
UBTTask_MoveShipToLocation::UBTTask_MoveShipToLocation()
{
NPC_Ship = nullptr;
ShipAiController = nullptr;
}
UBTTask_MoveShipToLocation::UBTTask_MoveShipToLocation(FObjectInitializer const& ObjectIntializer)
{
NodeName = "Navigate Random Location";
}
EBTNodeResult::Type UBTTask_MoveShipToLocation::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
//Get the AI controller
if (ShipAiController == nullptr)
{
ShipAiController = Cast<AShipAiController>(OwnerComp.GetAIOwner());
}
if (IsValid(ShipAiController))
{
//Get the pawn from the controller
if (!NPC_Ship)
{
NPC_Ship = Cast<ASpaceshipBase>(ShipAiController->GetPawn());
}
//check
if (IsValid(NPC_Ship))
{
//Random vector ukismetmathlib
LocationToNavigate = UKismetMathLibrary::RandomUnitVector();
//SpaceshipBase MoveTo
NPC_Ship->MoveTo(LocationToNavigate);
FinishLatentTask(OwnerComp, EBTNodeResult::InProgress);
}
else { return EBTNodeResult::Failed; }
}
else { return EBTNodeResult::Failed; }
UE_LOG(LogTemp, Warning, TEXT("EBTNodeResult = InProgress"));
return EBTNodeResult::InProgress;
}
//Task Tick
void UBTTask_MoveShipToLocation::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickTask(OwnerComp, NodeMemory, DeltaSeconds);
if (IsValid(NPC_Ship) && IsValid(ShipAiController))
{
if (NPC_Ship->GetActorLocation() == LocationToNavigate)
{
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
UE_LOG(LogTemp, Warning, TEXT("FinishLatentTask: Succeeded"));
}
}
}
FString UBTTask_MoveShipToLocation::GetStaticDescription() const
{
return FString::Printf(TEXT("New Random Location"));
}
[2025.01.11-19.40.02:962][506]LogTemp: Warning: BehaviourTree running for : BP_ShipAiController_C_0
[2025.01.11-19.40.02:962][506]LogTemp: Warning: BehaviourTree running for : BP_ShipAiController_C_1
[2025.01.11-19.40.02:962][506]LogTemp: Warning: BehaviourTree running for : BP_ShipAiController_C_2
[2025.01.11-19.40.02:962][506]LogTemp: Warning: Owner (BEGINPLAY): BP_MiningVesselOreAlpha_C_4
[2025.01.11-19.40.02:962][506]LogTemp: Warning: Owner (BEGINPLAY): BP_MiningVesselOreAlpha_C_5
[2025.01.11-19.40.02:962][506]LogTemp: Warning: Owner (BEGINPLAY): BP_MiningVesselOreAlpha_C_0
[2025.01.11-19.40.02:962][506]LogTemp: Warning: RTS Mapping Context Loaded
[2025.01.11-19.40.02:967][506]PIE: Server logged in
[2025.01.11-19.40.02:968][506]PIE: Play in editor total start time 0.118 seconds.
[2025.01.11-19.40.05:149][762]LogTemp: Warning: Owner has begun play: BP_MiningVesselOreAlpha_C_5
[2025.01.11-19.40.05:149][762]LogTemp: Warning: Spaceship Orders from AI Controller: MoveTo X=-0.696 Y=0.305 Z=0.650 for BP_ShipAiController_C_1
[2025.01.11-19.40.05:149][762]LogTemp: Warning: EBTNodeResult = InProgress
[2025.01.11-19.40.05:149][762]LogTemp: Warning: Owner has begun play: BP_MiningVesselOreAlpha_C_5
[2025.01.11-19.40.05:149][762]LogTemp: Warning: Spaceship Orders from AI Controller: MoveTo X=0.051 Y=-0.798 Z=-0.600 for BP_ShipAiController_C_1
[2025.01.11-19.40.05:149][762]LogTemp: Warning: EBTNodeResult = InProgress
[2025.01.11-19.40.05:149][762]LogTemp: Warning: Owner has begun play: BP_MiningVesselOreAlpha_C_5
[2025.01.11-19.40.05:149][762]LogTemp: Warning: Spaceship Orders from AI Controller: MoveTo X=-0.671 Y=-0.730 Z=0.130 for BP_ShipAiController_C_1
After more investigation I am now trying to track the bug down to the Blackboard_Task I have created. The behaviour tree runs as logged above for all 3 pawns. Also the Blackboard created 3 instances to show it is also working…
Only one pawn actually starts moving…
here is the BTTask code I made again:
UBTTask_MoveShipToLocation::UBTTask_MoveShipToLocation()
{
NPC_Ship = nullptr;
ShipAiController = nullptr;
}
UBTTask_MoveShipToLocation::UBTTask_MoveShipToLocation(FObjectInitializer const& ObjectIntializer)
{
NodeName = "Navigate Random Location";
}
EBTNodeResult::Type UBTTask_MoveShipToLocation::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
//Get the AI controller
if (ShipAiController == nullptr)
{
ShipAiController = Cast<AShipAiController>(OwnerComp.GetAIOwner());
}
if (IsValid(ShipAiController))
{
//Get the pawn from the controller
if (!NPC_Ship)
{
NPC_Ship = Cast<ASpaceshipBase>(ShipAiController->GetPawn());
}
//check
if (IsValid(NPC_Ship))
{
//Random vector ukismetmathlib
LocationToNavigate = UKismetMathLibrary::RandomUnitVector();
//SpaceshipBase MoveTo
NPC_Ship->MoveTo(LocationToNavigate);
FinishLatentTask(OwnerComp, EBTNodeResult::InProgress);
}
else { return EBTNodeResult::Failed; }
}
else { return EBTNodeResult::Failed; }
UE_LOG(LogTemp, Warning, TEXT("EBTNodeResult = InProgress"));
return EBTNodeResult::InProgress;
}
//Task Tick
void UBTTask_MoveShipToLocation::TickTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory, float DeltaSeconds)
{
Super::TickTask(OwnerComp, NodeMemory, DeltaSeconds);
if (IsValid(NPC_Ship) && IsValid(ShipAiController))
{
if (NPC_Ship->GetActorLocation() == LocationToNavigate)
{
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
UE_LOG(LogTemp, Warning, TEXT("FinishLatentTask: Succeeded"));
}
}
}
FString UBTTask_MoveShipToLocation::GetStaticDescription() const
{
return FString::Printf(TEXT("New Random Location"));
}
Any help in this matter would be greatly appreciated… I have spent 2 days on this now…
I have managed to isolate the problem down to UBTTask where I have forward declared my Pawn and also my AIController.
With the nature of the BahaviorTree and it’s ‘custom’ task’ the task was not instantiating correctly. By removing my APawn* Pawn and AIController* AiController out of my header file and instantiating them actually in the .cpp before using them made sure that each pawn was instantiated correctly and not overwriting the previous. Don’t ask me why it works like that? My knowledge of cpp is limited and my only clue given in the source code was in the UBTTaskNode.h where it states this jumble of nonsense to me…
If your node is not being instanced (default behavior), DO NOT change any properties of object within those functions! Template nodes are shared across all behavior tree components using the same tree asset and must store their runtime properties in provided NodeMemory block (allocation size determined by GetInstanceMemorySize() )
Hope this helps anyone else out there struggling with just one pawn out of many moving.
Due to the lack of documentation or understandable documentation for someone using CPP, I will be writing my own AI Behaviours rather than using BehaviorTrees.
My corrected code for others to view:
//Task to execute
EBTNodeResult::Type UBTTask_MoveShipToLocation::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory)
{
//Get the AI controller
AShipAiController* ShipAiController = Cast<AShipAiController>(OwnerComp.GetAIOwner());
if (IsValid(ShipAiController))
{
//Get the pawn from the controller
ASpaceshipBase* NPC_Ship = Cast<ASpaceshipBase>(ShipAiController->GetPawn());
//check
if (IsValid(NPC_Ship))
{
//Random vector ukismetmathlib
FVector LocationToNavigate;
LocationToNavigate = RandomLibrary->GetCompletelyRandomVector();
//SpaceshipBase MoveTo
if (NPC_Ship->GetActorLocation() == LocationToNavigate)
{
FinishLatentTask(OwnerComp, EBTNodeResult::Succeeded);
UE_LOG(LogTemp,Warning,TEXT("EBTNodeResult::Succeeded, Ship has arrived"));
}
else
{
NPC_Ship->MoveTo(LocationToNavigate);
FinishLatentTask(OwnerComp, EBTNodeResult::InProgress);
}
}
else { return EBTNodeResult::Failed; }
}
else { return EBTNodeResult::Failed; }
return EBTNodeResult::InProgess;
}