Spawn Actor and AIController problem

Hi guys, I’m literally losing my mind, hope someone can help me understand what I’m doing wrong.

So, in my level script I spawn an actor:

AEnemy Enemy = Cast<AEnemy>(GetWorld()->SpawnActor<AEnemy>(EnemyBlueprint, EnemyLocation, EnemyRotation));

Then, I set in the actor Blueprint “Auto Possess by AI when Spawned”.

Then In my AIController on BeginPlay()

AEnemy* PossessedEnemy = Cast<AEnemy>(GetPawn());

And it crashes.

Tried disabling the auto possess option and after the spwn calling

Enemy -> SpawnDefaultController();

And it changes nothing. Tried to call after the spawning:

AMyAIController EnemyController = Cast<AMyAIController>(Enemy -> GetController());
EnemyController -> Possess(Enemy);

And it chenges nothing.

I understand that BeginPlay of the controller is being called before the actual possession, but why?
I know I can resolve this thing in some way but I want to understand why, The cronological order in which Unreal call the functions is a big mystery for me.

Hi there! the thing is that order differs for spawned actors and for regular level actors

- Spawn:

LogBlueprintUserMessages: [BP_AI_C_2] Controller Begin Play

LogBlueprintUserMessages: [BP_Pawn_C_1] Pawn Possessed

LogBlueprintUserMessages: [BP_AI_C_2] Controller Possessed

LogBlueprintUserMessages: [BP_Pawn_C_1] Pawn Begin Play

- Level Actor:

LogBlueprintUserMessages: [BP_Pawn_2] Pawn Possessed

LogBlueprintUserMessages: [BP_AI_C_0] Controller Possessed

LogBlueprintUserMessages: [BP_AI_C_0] Controller Begin Play

LogBlueprintUserMessages: [BP_Pawn_2] Pawn Begin Play

3 Likes

Hi Kehel, thanks!
Now it’s all clear, what workaround do you suggest keeping the code in the controller? Maybe some other method I can use? I’m thinking to add custom event or call the code from the Pawn BeginPlay at this point.

Can you be more precise - what type of logic do you have and want to put in Controller class?

Oh nevermind, I have resolved this with a setter in the BeginPlay() of the pawn class, thanks a lot sir!

Resolved, thanks to @Kehel18 :slight_smile:

I was stuck on this for a few days! I had a NavMesh and verified active with “P”, my placed actor would move, and I was calling SpawnDefaultController() and my behavior tree was running but my spawned actor wouldn’t move. Noticed a warning I had in my logs about not having the pawn after BeginPlay was called.

This helped me understand why I had no pawn on my AI controller subclass in BeginPlay when I would spawn the actor. Didn’t realize the start sequence order would be different. I overrode OnPossess and only called my init function after both BeginPlay and OnPossess occurred to cover both the placed actor and spawned actor cases consistently.

Initially my code was designed to work on actors placed by the level designer and not by spawning.

This response made me aware that I should move my logic from void AShooterAIController::BeginPlay() to void AShooterAIController::OnPossess(APawn* InPawn)

3 Likes

OH MY GOD it took me FOREVER to find this answer and it fixed everything immediately.

1 Like

Wow, I can’t understand why there is such a huge inconsistency in the call-order. This is still an issue in Unreal Engine 5.0 btw

also calling

SpawnDefaultController();

is essential

can anyone help me i have solve possessing’s issue but have kind of prroblem my PlayerPawn is valid in beginplay it brokes in ticks that is my spawning ai doesnt have valid aicontoller when i set my ai to posses ai controller place or spawn in the wolrd here is the codes am i missin somethig please point out void AAIShooterController::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
APawn* PlayerPawn =Cast( UGameplayStatics::GetPlayerPawn(GetWorld(), 0));

  if (!PlayerPawn)
{
    UE_LOG(LogTemp, Warning, TEXT("PlayerPawn is valid."));
}
else
{
    UE_LOG(LogTemp, Warning, TEXT("PlayerPawn is NULL."));
    return; // Exit early to prevent further issues if PlayerPawn is NULL
}   here is my spawn actor  AAIShooterController* NewPoliceController = GetWorld()->SpawnActor<AAIShooterController>(AAIShooterController::StaticClass(), FTransform::Identity);
            if (NewPoliceController)
            {
                NewPoliceController->Possess(NewPolice);
                NewPoliceController->RunBehaviorTree(PoliceBehaviorTree);