Hi. I’ve created a character class, a player controller and AI controller. I’ve followed some tutorials for the simple AI behavior but it seems that my custom ai controller is not controlling the character.
I’ve set AIControllerClass for the character, I’ve set behavior tree component…etc. It is not working. On behaviour tree I’ve created a playsound node and it worked but MoveTo is not working. The keys on the blackboard seems None. I’ve add AddOnScreenDebugMessage in AIController and it is not working. I guess AI Controller is not possesses the character.
So do I need to implement seperate characters for AI and player?
I figured out the problem, the AI controller returns null for the self pawn from GetPawn() which is called frombehavior tree service. So why?
No, you do not need separate character classes for AI and the player. What’s more, you shouldn’t do that since you’d block a way of AI controlling “player” pawn.
Regarding the specific issue you experience, how/where/when do you make your AI controller posses the pawn? How do you spawn the AI pawn?
and which UE4 version are you using?
I’ve created a blueprint from my custom character class. I assigned my behavior tree as behavior tree and set my ai controller as default ai controller for the character blueprint. I’ve just placed it on in design time. I’ve debugged the code and see GetPawn() for my AI controller returns null.
The latest version (4.5.1)
That’s strange. Hand-placed pawns spawn their own controller (of AIControllerClass type) and have it posses the pawn. Works like a charm every time, which means there are some details you have set up unconventionally.
Did you derive your AI character from character class you use for player? How do you posses the player pawn? Is it possible that your AI pawn gets possessed by AI controller as expected by then gets possessed and unpossessed by PlayerController? You could implement
Event Possessed and debug what’s actually is possessing your pawn.
Without getting my hands on your project I’m unable to help you more.
You can also try break-pointing in
APawn::SpawnDefaultController to see if it’s getting called, what’s the AIControllerClass value and if it works as expected.
I think my AI controller is spawning with character but not possessing it.
I’ve attached player controller in game mode class.
ARPGGameMode::ARPGGameMode(const class FPostConstructInitializeProperties& PCIP) : Super(PCIP)
// use our custom PlayerController class
PlayerControllerClass = ARPGPlayerController::StaticClass();
// set default pawn class to our Blueprinted character
static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/Characters/Player"));
if (PlayerPawnBPClass.Class != NULL)
DefaultPawnClass = PlayerPawnBPClass.Class;
The Player is a blueprint derived from ARPGCharacter which is derived from ACharacter. I’ve created a new blueprint called “Bot” which derived from ARPGCharacter. I’ve assigned it’s controller and behavior manualy. So I don’t think player controller possesses the AI.
I am going to try EventPossesed to debug. Thanks for help.
So I’ve tried this and seems my custom AI controller possesses correctly and the AI character not unpossessed later.
Here is my AI controller code for extra info:
void ARPGAIController::Possess(class APawn* InPawn)
ARPGCharacter *character = Cast<ARPGCharacter>(InPawn);
if (character && character->Behavior)
EnemyKeyId = BlackboardComponent->GetKeyID("Enemy");
// TODO: Create AI Sensing Code Here to search for other enemies for this AI.
APawn *self = GetPawn();
GEngine->AddOnScreenDebugMessage(1, 2, FColor::Red, FString("Could not found self pawn for the AI Controller!"));
const FVector selfLocation = self->GetActorLocation();
float bestDistanceSquared = FLT_MAX;
APawn *bestTarget = NULL;
for (FConstPawnIterator pawn = GetWorld()->GetPawnIterator(); pawn; pawn++)
APawn *possibleTarget = Cast<APawn>(*pawn);
const float distanceSquared = FVector::DistSquared(selfLocation, possibleTarget->GetActorLocation());
if (distanceSquared < bestDistanceSquared)
bestDistanceSquared = distanceSquared;
bestTarget = possibleTarget;
It seems you’re checking the wrong condition:
APawn *self = GetPawn();
I bet you meant
if (!self) there.
And that’s precisely why I’ve settled for using longer yet more readable conditions like
if (self == nullptr).