Download

Setting up AIController on Player Character

I’m trying to setup an AIController on my Player Character to just send basic commands like MoveToLocation or Shoot through MyPlayerController and use BehaviorTree with the AIController.

I followed this answer here: https://answers.unrealengine.com/questions/374052/is-it-possible-to-use-both-ai-controller-and-playe.html

  1. Made sure that my GameMode DefaultPawnClass is set to “SpectatorPawn”
  2. Made sure the “Auto Possess Player” property of the character on the map is set to “Disabled” from “Player 0”.
  3. Made sure “Auto Possess AI” is set to “Placed in World or Spawned”
  4. Made sure the “AI Controller Class” is set to my custom AIController

Stuck at #5. I’m only planning to use one character so I’m thinking it shouldn’t be that complicated. Currently stuck at not being able to get a reference to my PlayerCharacter.

In BeginPlay() of my PlayerController:

    AMyPlayerCharacter* PlayerCharacter = Cast<AMyCharacter>(UGameplayStatics::GetPlayerCharacter(this,0));
    AMyPlayerCharacter* PlayerCharacter = Cast<AMyCharacter>(GetWorld()->GetFirstPlayerController()->GetPawn());

tried both, both of them returns null so I can’t get a reference to my PlayerAIController with this

    if (PlayerCharacter)
    	{
    		AMyPlayerAIController* PlayerAI = Cast<AMyPlayerAIController>(PlayerCharacter->GetController());
    	}

so then I might be able to modify the MoveToMouseCursor function like this maybe:

    FHitResult Hit;
    	GetHitResultUnderCursor(ECC_Visibility, false, Hit);
    	
    	if (Hit.bBlockingHit)
    	{
    		// SetNewMoveDestination(Hit.ImpactPoint);
    		if (PlayerAI)
    		{
    			PlayerAI->MoveToLocation(Hit.ImpactPoint);
    		}
    	}

Also I don’t know yet if I’ll still be able to use MyPlayerCharacter’s camera/follow the character with AIController is assigned on it.

So those functions trying to get the player character won’t work, because what you’re doing is getting the first player controller (which is the class you’re already in), and getting its character, which you don’t have, because the AIController owns it.

What you could do is set it so that the character is owned by the player controller again, and in your begin play you can get a reference to the character by GetControlledCharacter() (or something like that), then spawn the AIController you want, and call Unpossess() and then get the AIController to Possess the character.

If you have a blueprint AI Controller class you’ll probably want a reference to the class by using

UPROPERTY(EditDefaultsOnly)
TSubclassOf<AIController> MyAIControllerClass; 

UPROPERTY()
AIController* PlayerAI;

UPROPERTY()
AMyPlayerCharacter* PlayerChar;

in the .h for the player controller, then you can go

PlayerChar = Cast<AMyPlayerCharacter>(GetControlledPawn());
PlayerAI = SpawnActor<AIController>(MyAIControllerClass, Location, Rotation, Params);
Unpossess();
PlayerAI->Possess(PlayerChar);

You’ll need to make sure that you have a blueprint class of the player controller, then you can adjust the MyAIControllerClass in the blueprint to be the AIController class you want.

Forgive me if the code isn’t exactly correct, just typing it from memory

1 Like

I believe the Top Down template does what you want. You might take a look at that.

in header:

UPROPERTY(EditDefaultsOnly)
TSubclassOf<AAIController> PlayerAIControllerClassBP;

UPROPERTY()
AAIController* PlayerAI;

UPROPERTY()
AMyCharacter* PlayerCharacter;

in .cpp BeginPlay():

PlayerCharacter = Cast<AMyCharacter>(GetPawn());

FVector Location;
FRotator Rotation;
FActorSpawnParameters Params;
PlayerAI = GetWorld()->SpawnActor<AAIController>(PlayerAIControllerClassBP, Location, Rotation, Params);
UnPossess();

if (PlayerAI && PlayerCharacter)
{
	PlayerAI->Possess(PlayerCharacter);
	//SetViewTarget(PlayerCharacter);
}

then I selected my BP_PlayerAIController in my BP_PlayerController(any reason not to use the c++ version?), when I tried it the game created a camera at 0 location and I’m stuck in that view. I tried SetViewTarget like above and tried changing AutoPossessAI to “Placed in the world or Spawned”, no luck. I see both PlayerCharacter and PlayerController and 2 PlayerAIControllers spawned in world outliner.

Thanks for the help.

I started with Top Down template, it doesn’t have AIController on player character.

Yeah so SetViewTarget will just put a camera in that position (where the actor is). You could try SetViewTarget(PlayerChar->camera), that might work. If not read below. If it works you’ll still run into the problem where movement is not routed through the player controller onto the character

What you might want is to create a pawn like ACameraPawn that has just has a camera component on it. This will be your view.

You can place that in the world at a good angle you want (you could make it move around with WASD, or set it up to follow the player from a certain distance using Tick, etc)

So what will happen from here is that your PlayerController will have the ACameraPawn setup as the pawn it wants to spawn.

Inside the begin play of the player controller, you can have the same stuff, except you’ll also spawn the player character into the world using SpawnActor. Get a reference like

PlayerCharacter = Spawn<AMyCharacter>(whateverbp, Location, Rotation, Params);

You won’t call Unpossess anymore, as you’re never going to be possessing the player character. You’ll have to route commands through your PlayerController and explicity call Shoot etc on the player character if you want.

Now this has drawbacks because you won’t actually be possessing the player character so you can’t move around or rotate without properly setting that up, probably in code.

SetViewTarget(PlayerCharacter->GetTopDownCameraComponent());

this doesn’t work, SetViewTarget only accepts actors it seems.

Anyway I have only mouse click move & placeholder shoot as character movement/control goes, then I have several İnputComponents for switching weapons and zooming & rotating camera all in PlayerController, none of these will work if I don’t possess the pawn with PlayerController?

If SetViewTarget doesn’t work, you might have to go with having a pawn with a camera attached and then having the player character be something spawned in and that you reference.

Those functions can still work, as long as they call into the player character, like if you had mouse right click you would then call PlayerCharacter->Shoot()

why not create a player controller that sends instructions to an aicontroller and you save those seven steps?
It’s like sending instructions to a companion.
You just have to spawn the ai in the player controller get a reference and start sending it instructions

Wow, this thread is really full of information. Thank you for sharing this.

I’m a beginner but I believe @Cd1232 's instructions was about doing that, no? Spawned the AI controller, gave it possession of the character to be able to use AIController’s functions but then I couldn’t use the player character’s camera anymore.

you dont need posse the AI, keep the possession in your pawn, having the reference you can send it instructions

Removed possession code then swapped SimpleMoveToLocation function with AIController’s MoveToLocation, it didn’t work. Don’t AIController has to control/know the character it’s sending commands to?

anyway currently looking into this video for making CameraPawn: UE4 Custom Camera Pawn and Movement Controller in C++ - YouTube

well what they actually spawn is a character and the Aicontroler it will use is configured here.
so you keep the player pawn for the camera

I use it like this for a companion and I send him instructions to move or attack enemy and he uses his own BT.

Guess I might have to do that then once I setup the camera pawn I’ll keep player controller on it and keep the AIController on player character.

I’ve created the custom camera pawn as in the video I linked above but I can’t attach it to or set it to follow my PlayerCharacter.

First of all I’m having a hard time referencing the character in PlayerController since its no longer the default pawn. I tried UGameplayStatics::GetAllActorsOfClass and adding the probably only 1 character to an array then assigning to PlayerCharacterRef through casting. I tried making a TSubclassOf PlayerCharacter and assigning the BP version in the editor but in either case I couldn’t attach CameraPawn to PlayerCharacter through CameraPawnRef->AttachToActor(). Any more help? :smiley:

UGameplayStatics::GetAllActorsOfClass(GetWorld(), APlayerCharacter::StaticClass(), FoundActors);

	PlayerCharacter = Cast<APlayerCharacter>(FoundActors[0]);

	if (PlayerCharacter)
	{
		SetViewTarget(PlayerCharacter);
	}
	
	CameraPawnRef = Cast<ACameraPawn>(GetPawn());
	if (CameraPawnRef != nullptr)
	{
		CameraMovementRef = CameraPawnRef->PawnMovementComponent;
	}

	SetViewTarget(CameraPawnRef);

Managed to use GetAllActorsOfClass() correctly. Now when I set the view target to player it uses players original camera with all the associated zoom/rotate controls I did for it before. When I set the view target back to CameraPawn its still stuck on player and can’t move but now it uses its own zoom/rotate controls. I want to toggle between following the player and free moving camera preferably only using the CameraPawn but if I can properly switch between the 2 cameras I guess that’d be ok too even tho there’d be 2 set of codes for camera controls.

Solved it with just setting the location of the camera on the character in PlayerTick with a bool that’s set in camera movement inputs and reversed with a new “focus camera on player” input.

if (CameraMovementRef != nullptr && CameraMovementRef->IsCameraDisabled() && CameraPawnRef && PlayerCharacter)
	{
		CameraPawnRef->SetActorLocation(PlayerCharacter->GetActorLocation(), false);
	}