Behavior Tree and my Custom AI controller only moving one pawn and no others

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

and this are my pawns in unreal editor:

https://imgur.com/a/W44xA1A

Any help or guidance would be appreciated…

[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…

Okay, not that I received any help…

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

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.