Issue related to GetPawn()

I’ve just spent a couple of hours thinking that GetPawn() was always returning a nullptr and crashing. It’s now working but this has left me confused.

Initially I was having an issue mentioned in another thread here, that GetPawn() crashed the game if I used it as shown in the tutorial. Instead of that, I’m now doing this:

void AMyAIController::BeginPlay() 
{
    Super::BeginPlay();
    
    if (AIBehavior != nullptr)
    {
	    RunBehaviorTree(AIBehavior);

        PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);

        AIPawn = GetPawn();
        if (AIPawn != nullptr)
        {
            StartLocation = AIPawn->GetActorLocation();
            GetBlackboardComponent()->SetValueAsVector(TEXT("StartLocation"), StartLocation);
        }
        else
        {
            UE_LOG(LogTemp, Warning, TEXT("GetPawn failed."));
        }
    }    
}

What I was then seeing in the viewport was that the AI would run up to my player character but then stop and not run back to the start location. Also, I got my “GetPawn failed.” message coming up in the log. I thought that GetPawn() was always returning nothing.

Then I randomly realised that the AI was stopping where it was because my player character was getting in the way of it reaching its endpoint. If I move my player to a different location, the AI completes the first task and then moves onto the second, third, etc as expected. So it’s all working fine.

However, I’m still getting my “GetPawn failed.” message in the log, and I don’t understand why the “else” part is running, because quite clearly the first part of the “if” is ALSO running. Seems really weird and any help would be appreciated.

EDIT:

I don’t know if this is significant, but I have only one AI ShooterCharacter in the level when the game starts, plus the player’s ShooterCharacter that spawns on the PlayerStart. However, when the game starts, I have two BP_AIController assets in the level. I don’t understand why there’s two unless one is attached to the player.

To test this, I tried to change my log message to

            UE_LOG(LogTemp, Warning, TEXT("GetPawn failed on %s."), *AIPawn->GetName());

However, changing just this line crashes the game. So I changed the script to this:

if (AIBehavior != nullptr)
    {
	    RunBehaviorTree(AIBehavior);

        PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);

        AIPawn = GetPawn();
        if (AIPawn != nullptr)
        {
            StartLocation = AIPawn->GetActorLocation();
            GetBlackboardComponent()->SetValueAsVector(TEXT("StartLocation"), StartLocation);
                    UE_LOG(LogTemp, Warning, TEXT("GetPawn succeded on %s."), *AIPawn->GetName());

        }

        else
        {
            AIPawn = GetPawn();
            if (AIPawn != nullptr)
            {
                UE_LOG(LogTemp, Warning, TEXT("GetPawn failed on %s."), *AIPawn->GetName());
            }
        }
    }    

Now it doesn’t crash, and the log just prints the message “succeded on BP_ShooterCharacter_15”, not the failure message.

My theory is that the player is also creating an AIController asset that has trouble with GetPawn(), but I don’t know how to verify that.

Could you show your character blueprints? Showing the auto possess and controller properties?

Here’s a screenshot if this is what you mean?

Yes. Do you not have a player character blueprint as well?

No, I have a ShooterCharacter c++ class, and then I created BP_ShooterCharacter from that. I’m using it for both the AI and the player. Have I missed something important? I thought the general idea was that you could use the same character twice, just with one controller for the player and a different one for the AI.

No that should be fine. It’s just that Sam has two so if you followed exactly you would have two.

I think I might have to take a look at your project. Would you mind sending me your project using the following link?
https://gdev.tv/projectupload

Please use File > Package Project > Zip Up Project within Unreal as this will ensure only required files are zipped up and things like the Binaries are excluded.

Thanks, I sent the request form, the project was still 3gb.

Sam

Are you able to upload it to your own drive and link it?

Here’s a link, I thought this was included in the form:

https://drive.google.com/file/d/10Heh_o8dhlkPTZ-03vy2meOQFqwzbQNd/view?usp=sharing

This is your problem.
image

It had an AI Controller because you told it to spawn with one.

Thanks for your reply, I’ve changed these settings to the following:

Auto Possess Player: Disabled
Auto Possess AI: Placed in world
AI Controller Class: BP_AIController

The Player spawns in, and the AI is placed in the world so that seems like it’s how this is supposed to work.

I realised that I have another question related to this, particularly in the following:

void AShooterCharacter::BeginPlay()
{
	Super::BeginPlay();
	
	PlayerControllerRef = Cast<APlayerController>(GetWorld()->GetFirstPlayerController());
	
}

We seem to set PlayerControllerRef for both the AI ShooterCharacter and the player-controlled Shooter character (and we seem to SetupPlayerInputComponent for both as well). However, I can’t see where we use PlayerControllerRef.

Is there some other behavior somewhere that only assigns the first PlayerController to the player-controlled ShooterCharacter and stops it being assigned to the AI ShooterCharacter?

Similarly, I can’t see where SetupPlayerInputComponent gets its UInputComponent from. Does this happen somewhere else? And again, is there some behavior that stops this being set for the AI ShooterCharacter?

What lecture does that code exist? I can’t see it in the lecture tagged or in the end state.

It’s passed in by engine code within APawn::PawnClientRestart()

// Set up player input component, if there isn't one already.
if (InputComponent == nullptr)
{
	InputComponent = CreatePlayerInputComponent();
	if (InputComponent)
	{
		SetupPlayerInputComponent(InputComponent);
		InputComponent->RegisterComponent();
//...

Yes, the quoted code is within an if that checks if it’s a player controller.

APlayerController* PC = Cast<APlayerController>(Controller);
|if (PC && PC->IsLocalController())

What lecture does that code exist? I can’t see it in the lecture tagged or in the end state.

It’s possible I added this in myself for some reason, but in ShooterCharacter.h, I have

private:
	APlayerController* PlayerControllerRef;

And then in ShooterCharacter.cpp, I have

	PlayerControllerRef = Cast<APlayerController>(GetWorld()->GetFirstPlayerController());

I can’t see it in the GitHub version, so I guess I must have added it in for some reason??

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

Privacy & Terms