Using a PlayerCameraManager to keep a same camera while changing Pawns

Hello, I have made rolling balls pawns using the Rolling Ball default template, except the camera works slightly differently. It follows the movements of the mouse. I’d like to separate the camera from the pawns entirely using a player camera manager, In such a way that a camera is always following whichever pawn is presently controlled by the player controller. With my present system, when I switch pawns, the old pawn and its camera is destroyed, and the new pawn and its camera are then spawned, resetting the camera.

I have had trouble finding information and examples of how to use a player camera manager.

Here is the PlayerController code used to switch pawns. Also, the two pawns are different blueprints of a same class.

ReptilePlayerController.cpp

AReptilePlayerController::AReptilePlayerController(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
	static ConstructorHelpers::FObjectFinder<UBlueprint> Ball1(TEXT("Blueprint'/Game/RelevantContent/BP_RollingPawn.BP_RollingPawn'"));
	if (Ball1.Object) {
		BP_Ball1 = (UClass*)Ball1.Object->GeneratedClass;
	}
	static ConstructorHelpers::FObjectFinder<UBlueprint> Ball2(TEXT("Blueprint'/Game/RelevantContent/BP_RollingPawn2.BP_RollingPawn2'"));
	if (Ball2.Object) {
		BP_Ball2 = (UClass*)Ball2.Object->GeneratedClass;
	}
}

void AReptilePlayerController::SetupInputComponent()
{
	Super::SetupInputComponent();

	InputComponent->BindAction("Morph", IE_Pressed, this, &AReptilePlayerController::Morph);
}

void AReptilePlayerController::Morph()
{
	//References to our different morphs
	GEngine->AddOnScreenDebugMessage(2, 2, FColor::White, "Morph!");

	//We destroy our pawn and unpossess it
	FVector position = GetPawn()->GetActorLocation();
	FRotator orientation = GetPawn()->GetActorRotation();

	ARollingPawn *player = Cast<ARollingPawn>(UGameplayStatics::GetPlayerPawn((), 0));

	if (GetPawn()->GetClass() == BP_Ball1)
	{
		GetPawn()->Destroy();
		UnPossess();

		UWorld* const World = ();

		//Now we spawn the other one and possess it.
		ARollingPawn* Roller = World->SpawnActor<ARollingPawn>(BP_Ball2, position, orientation);
		Possess(Roller);
	}

	else if (GetPawn()->GetClass() == BP_Ball2)
	{
		GetPawn()->Destroy();
		UnPossess();

		UWorld* const World = ();

		//Now we spawn the other one and possess it.
		ARollingPawn* Roller = World->SpawnActor<ARollingPawn>(BP_Ball1, position, orientation);
		Possess(Roller);
	}
}

ReptilePlayerController.h

UCLASS()
class GETTINGSERIOUS_API AReptilePlayerController : public APlayerController
{
	GENERATED_BODY()
	
public:
		
	AReptilePlayerController(const FObjectInitializer& ObjectInitializer);

	virtual void SetupInputComponent() override;
	
	//Function to change shape
	void Morph();

	TSubclassOf<ARollingPawn> BP_Ball1;
	TSubclassOf<ARollingPawn> BP_Ball2;

};

Anyone knows how to work with Camera Managers? Thanks in advance! Please, don’t hesitate to ask me for more details if I forgot something important.

There no need call anything in PlayerCameraManager, you can just use PlayerController. First you need to set bAutoManageActiveCameraTarget to false in player controller, so possession wont automatically set view target, then you call SetViewTarget(Actor) and argument Actor becomes view target. Normally with variable i mentioned said to true, possessed Pawn becomes view target.

View target is a actor that is viewed in camera and each actor can have it’s own camera setup. When Actor is view target, PlayerCameraManager asks that actor for camera positioning on every frame, by calling CalcCamera which has struct as a argument in which set camera position in (you don’t return anything):

Default code in CalcCamera, picks first found camera component and apply position of that component as a camera. Also there no point of calling Super::CalcCamera here ofcorse

That’s very helpful, thank you!

I managed set boolean you mentioned to false, and used SetViewActor in my PlayerController, so that I had SetViewActor(GetPawn);. However, I’m not sure how I can change the camera setup of view target. Is it a blueprint, or settings that I modify in my cpp class?

What would a usage of CalcCamera look like?

void AReptilePlayerController::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	FMinimalViewInfo* CameraSetup;
		
	Cast<FMinimalViewInfo>(CameraSetup)->Location = FVector(0, 0, 0);
	Cast<FMinimalViewInfo>(CameraSetup)->Rotation = FRotator(0, 0, 0);

	CalcCamera(DeltaTime, CameraSetup);

}

Would it be something like that?

I said PlayerCameraMenager calls CameraCalc, so obviuesly you need to override CameraCalc. Here you have have default setup which fiunds camera component and set camera position in to it:

void AActor::CalcCamera(float DeltaTime, FMinimalViewInfo& OutResult)
{
	if (bFindCameraComponentWhenViewTarget)
	{
		// Look for the first active camera component and use that for the view
		TInlineComponentArray<UCameraComponent*> Cameras;
		GetComponents<UCameraComponent>(/*out*/ Cameras);

		for (UCameraComponent* CameraComponent : Cameras)
		{
			if (CameraComponent->bIsActive)
			{
				CameraComponent->GetCameraView(DeltaTime, OutResult);
				return;
			}
		}
	}

	GetActorEyesViewPoint(OutResult.Location, OutResult.Rotation);
}

Thanks for being patient with me :slight_smile:

I think I get a bit more how CalcCamera works now.

I now use camera linked to the controller instead of one linked to the pawns, which is great. However, I struggle with modifying the camera setup from outside of the CameraCalc function. Right, I’ve this :

ReptilePlayerController.cpp

void AReptilePlayerController::CalcCamera(float DeltaTime, struct FMinimalViewInfo& OutResult)
{
	FVector boom;

	FVector 

	boom = FVector(-200, 0, 20);

	OutResult.Location = GetPawn()->GetActorLocation() + boom;
	OutResult.Rotation = FRotator(0, 10, 0);
	
}

This places the camera behind my pawn, and when I switch pawns, it stays right there, while still following it when it moves around! Exactly what I want basically as far as this goes. But if say I want to pitch the camera from a separate function, how can I change the equivalent of OutResult (in CalcCamera) from there?