Initialize/spawn class within ai controller

This is a really beginner question but for the life of me can’t figure it out for the life of me.

What I’m trying to do is retrieve the location of my AI within the world and compare that against the players position. I have this logic being done in my AIController which is of type ACharacter (for movement etc).

I have the following code which prints out and shows the difference in location between the AI and the player

	if (m_lineOfSight)
	{
		SetFocus(m_fpsCharacter);
		const FVector playerLoc = m_fpsCharacter->GetActorLocation();

        // Crashes here as m_observer is nullptr
		const FVector seekerPos = m_observer->GetActorLocation();  

		const FVector distanceBetween = m_observer->GetActorLocation() - m_fpsCharacter->GetActorLocation();
		
		UE_LOG(LogTemp, Display, TEXT("Player Position X:%f,Y:%f,Z:%f"), playerLoc.X, playerLoc.Y, playerLoc.Z)
		//UE_LOG(LogTemp, Display, TEXT("Seeker Position X:%f,Y:%f,Z:%f"), seekerPos.X, seekerPos.Y, seekerPos.Z)
		//UE_LOG(LogTemp, Display, TEXT("Distance Between X:%f,Y:%f,Z:%f"), distanceBetween.X, distanceBetween.Y, distanceBetween.Z)
	}

I know that m_observer needs to be initialized so that it doesn’t return a nullptr. But I’m struggling on how to initialize it (sounds daft, I know). In the SeekerAIController.h , the m_observer has been created like AObserver* m_observer = nullptr; . I know this is why it’s returning a nullptr, but obviously needs to have some ‘value’ as it’s a pointer. I have tried using UPROPERTY(EditAnywhere) to assign the Blueprint that way, but when I select BP_Observer, it doesn’t get set, field stays as None.
m_observer is declared in the header like so
AObserver* m_observer = nullptr;. However, when I change it to TSubclassOf<AObserver> m_observer', I am able to assign it to BP_Observer.

I have been looking at the idea of spawning the observer in the world which would be it’s initialization. At the moment, it’s just dragged into the world via Blueprint Class (created from the C++ class). Does the actor/pawn need to be in some sort of a ‘spawner’ class, and have that in the level? Then the code will spawn the actor at that point once the game starts? But can’t really figure that out either… I feel like I should know how to do this, but I’m drawing a blank. Any advice on what I could do to solve this?

P.S; Observer and Seeker are the same thing. Just haven’t made the name consistent yet.

If you’re trying to set it in the blueprint then that would be why. The blueprint isn’t something that exists in the level, you can’t refer to things in it. You can only set this on instances of the blueprint (so you should make it EditInstanceOnly).
You need to use the world to find it at BeginPlay. Or if it’s something that’s there in your scene and not spawned you can refer to it by name via FindObject

Yeah, I’ve done some research and most sources say use BeginPlay to spawn the AI in the SeekerAIController. But nothing seems to spawn when I start the game. I’m not too sure if I’ve set up my AI and AIController incorrectly or not.

Correct me if I’m wrong, I’m trying to use the AIController to spawn BP_Observer in the level (or anything that will spawn my AI class) when the game starts. This way, in the AIController, I can use m_observer to get a reference to the AI in the level, and use GetActorLocation() so I can get it’s location and compare that to the players. Is this the incorrect way of doing it?

Having a look at the FindObject, I assume I could put BP_Observer in my level, and use FindObject to get BP_Observer, or at least some reference to it?

How are you doing that? You can spawn the pawn and then call SpawnDefaultController on it which will use the default controller you set on the pawn class.

It’s not clear to me what Observer actually is or its purpose?

Yes you would use it like

FindObject<AObserver>(GetWorld()->GetCurrentLevel(), TEXT("BP_Observer_0"));

Where the second argument is the name of it if you hover over it. It’s the name + ID of it.

Unfortunately, I’m currently at work and don’t have access to my code. Once I get home, I’ll update this post with my code.

BP_Observer or m_observer is the AI that will be placed/spawned into the level. It’s just the AI that will look for the player. The C++ class is AObserver

That might be the answer. As long as I can do something like
m_observer = FindObject<AObserver>(GetWorld()->GetCurrentLevel(), TEXT("BP_Observer_0")); with in the SeekerAIController (or anything that’ll let me spawn it in), so I can then get the location of BP_Observer within the level, that will achieve what I’m after.

I meant like an actor or pawn. Presumably like a camera/third eye for the AI somewhere in the level to detect the player?

By spawn it in do you mean the observer? What’s wrong with spawning it in the AIController’s BeginPlay? Is it suppose to be shared across all AI or each have their own?

Oh right. My bad! It’s base class is ACharacter which I’m pretty sure is derived from APawn, if I’m not mistaken. Pretty much, yeah. Just an Character/Pawn that will spawn into the level and detect the player by Line of Sight.

Yes, exactly that. Currently, it will only be used on one observer. But I will be including other game modes with more observers. I have tried to use something like

FVector spawnLoc = GetActorLocation();
m_observer = GetWorld()->SpawnActor<AObserver>(spawnLoc);

but nothing seems to spawn. Unless the spawnLoc is getting the location of the Controller which isn’t in the world (just came to me whilst writing this)

Here’s the code on where I’m attempting to assign m_observer. In the header it’s defined as
AObserver* m_observer = nullptr;

void ASeekerAIController::BeginPlay()
{
	Super::BeginPlay();
	
	m_fpsCharacter = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
	m_observer = FindObject<AObserver>(GetWorld()->GetCurrentLevel(), TEXT("BP_Observer"));
	
	GetWorldTimerManager().SetTimer(m_timerHandle, this, &ASeekerAIController::CountdownTimer, 10.0f, true, 10.0f);
}

With the FindClass, I have used BP_Observer, BP_Observer0, and BP_Observer_0, and none of them seem to work. m_observer is still returning null. When I start the level, the observer BP in the Outliner has the name BP_Observer, I am clueless to what is going on…

I’ve managed to fix the problem.

In my ASeekerAIController::BeginPlay() function, I did the following
m_observer = Cast<AObserver>(GetPawn()); and m_observer is no longer returning null, so I am able to get the location of the observer within the world and compare is against the player.

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