I am new to Unreal, coming from Unity.
I followed the Behavior Tree Quick Start Guide and wanted to try to make the same system in C++.
At step 7.5 in that guide a sequence is set up with a Blackboard Decorator to query HasLineOfSight.
Since I couldn’t find any guide in C++, I attempted my own solution. One of the problems I initially had was getting a reference to the Blackboard but found out you could add a Blackboard Component to my enemy character so I used that.
Problem: What I see when I run my Behavior Tree, is that it never executes the nodes under the Decorator, even though I set HasLineOfSight to true.
At first I thought maybe I misspelled HasLineOfSight like HasLineofSight (lowercase O for example) in either the Blackboard or C++ but I double checked, copied the key from the Blackboard into code to make sure.
Apart from if someone can spot what I am doing wrong, is there any way to see the actual Values in the Blackboard for the running Behavior Tree in some editor?
void AEnemy_AIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
auto EnemyCharacter = Cast<AEnemyCharacter>(InPawn);
if (EnemyCharacter == nullptr)
{
UE_LOG(LogTemp, Error, TEXT("Pawn does not inherit from AEnemyCharacter"));
return;
}
Blackboard = Cast<UBlackboardComponent>(EnemyCharacter->GetComponentByClass(UBlackboardComponent::StaticClass()));
if (Blackboard == nullptr)
{
UE_LOG(LogTemp, Error, TEXT("Pawn has no Blackboard Component"));
return;
}
// GetBehaviorTree is custom, just returns a UPROPERTY for a UBehaviorTree*
RunBehaviorTree(EnemyCharacter->GetBehaviorTree());
}
void AEnemy_AIController::OnActorSense(AActor* Actor, FAIStimulus Stimulus)
{
if (Stimulus.WasSuccessfullySensed() && Actor->ActorHasTag(FName("Player")))
{
UE_LOG(LogTemp, Display, TEXT("Detected Player"));
GetWorldTimerManager().ClearTimer(LineOfSightTimer);
if (Blackboard == nullptr)
{
UE_LOG(LogTemp, Error, TEXT("No Blackboard present in AEnemy_AIController"));
}
else
{
// This is logged appropriately when detecting player.
// But the Behavior Trees Decorator never passes flow to child nodes.
UE_LOG(LogTemp, Display, TEXT("HasLineOfSight = true"));
// This acts as if never being set
Blackboard->SetValueAsBool("HasLineOfSight", true);
Blackboard->SetValueAsObject("EnemyActor", Actor);
}
}
else
{
UE_LOG(LogTemp, Display, TEXT("Lost Player"));
GetWorldTimerManager().SetTimer(LineOfSightTimer, this, &AEnemy_AIController::ForgetPlayer, 4.0f, false);
}
}
void AEnemy_AIController::ForgetPlayer()
{
UE_LOG(LogTemp, Display, TEXT("Forgot Player"));
if (Blackboard == nullptr)
{
UE_LOG(LogTemp, Error, TEXT("No Blackboard present in AEnemy_AIController"));
}
else
{
// This is logged appropriately when 4 seconds have passed since losing track of Player
UE_LOG(LogTemp, Display, TEXT("HasLineOfSight = False"));
Blackboard->SetValueAsBool("HasLineOfSight", false);
Blackboard->SetValueAsObject("EnemyActor", nullptr);
}
}