Can i switch Active PlayerController?

Hello guys i have a problem and i feel stupid about it.

I’m working on a game where you can control 2 characters.

I want to be able to switch the current active Player Controller because i use a dynamic camera Systems with triggers,areas and others stuff so i must keep track camera infos of the other character.

So each playerController have a distinct PlayerCameraManager and a pawn.

So what’s the best solution to acheive that ?

Do you have any other solutions ?

Any ideas could be usefull cause i’m stuck right now

If you need more infos let me know :slight_smile:

Thanks.

gamer08

Thanks for the idea but as i said I must use my custom CameraManager class because i’ve build a dynamic system with multiples camera mode and blending. So i really need 2 paws with their respective controller and camera.

it’s like a local multiplayer game but where each player can be control by one user.

I will find a look around i’m pretty sure. For the moment it’s just a big headache

I think better solution for you would be repossession and switch between view targets and implement camera in characters with operating camera component, thats what view target system was made for.

But if you could try to swap UPlayer pointer in PlayerController with this function:

You can also access it from varable Player:

then try that Player pointer switch :stuck_out_tongue: get UPlayer from active controller and switch it between the two characters, you can also swap some AI controller for other character

Ok i will try it but it seems to me same thing as switch possess character and the CameraManager pointer is on the controller not on character so.

At least i will give a try and check if i can work around.

Hey folks i’m back !

To answer back my question Yes we can switch Active playerController there is a build-in function in the gameMode but i find it out after finished my own workaround :expressionless:

To summarize, i do almost almost the same things as the GameMode function with more stuff in there because each playable Character need is own camera and i can switch back and forward so i keep a cametra list on PlayerController and each camera have a character target. When i update PlayerCameraManager i update all camera even if the character is controll by AI because i can switch at any moment.

if you need more details i can post my code just tell me :slight_smile:

We can mark that post as solved but i still don’t know how to do it even if we can.

gamer08

Could you share your code to me?
mafiyd13@gmail.com

There’s a howto now too: Possessing Pawns in Blueprint

Hey! I`m trying to implement cameras switching within a my custom playercontroller. From 3rd person view to 1st person. When I add the second camera into my playercontroller the editor is crashes. I think this is because of a playercontroller can not handle multiple cameras. So i have found your question, and this is almost the same a want to make. So could you please share your solution, or you can say what I have to do.
What I have already done.

A custom playercontroller with a ucameracomponent and a custom uspringarmcomponent in it

A custom cameramanager

A character

All movement events like walk, run, jump, sprint I want to handle within my playercontroller, which I have done already. And switching between cameras is the next goal. But I can`t quite understand how to make it work in a proper way. I want to store my view cameras within my playercontroller and switch between them.

Hi Mikhail,

Well if I understand your problem correctly it’s easier than mine back then.

You want to be able to switch “camera Mode” within your playerController am I right ?

If so, you can do this. (I use that concept in my own games)

customPlayerCameraManager.h

#pragma once

#include "Camera/PlayerCameraManager.h"
//#include "BaseCameraMode.h"
#include "Object.h"
#include "ProtoPlayerCameraManager.generated.h"

class UBaseCameraMode;

UCLASS()
class PROTO_API AProtoPlayerCameraManager : public APlayerCameraManager
{
	GENERATED_BODY()

private:
	
	UPROPERTY()
	UBaseCameraMode* _currentCameraMode;

	UPROPERTY()
	TArray<UBaseCameraMode*> _cameraModes;

	bool _isCameraIsInterpoling;

	void UpdateViewTarget(FTViewTarget& outVT, float deltaTime) override; 
	void BeginPlay() override;
	void CreateCameraModesAndSetupInitial();
	UBaseCameraMode* CreateCameraMode(UClass* cameraModeClass);
		
public:
	AProtoPlayerCameraManager();
	
	void LimitCameraPitch(FRotator& rotation, float minPitch, float maxPitch);
	void UpdatePitch(float value);
	void UpdateYaw(float value);
	void ChangeCameraMode(int cameraMode);
};

//Note. Include here because nested UCLASS and source declared UCLASS are not supported en date du 07/08/2015 sur 4.8.3 and I want to reduce includes and references 

/******* Camera Modes *******/

/******* Base Mode *******/
UCLASS(Abstract)
class PROTO_API UBaseCameraMode : public UObject
{
	GENERATED_BODY()
	
protected:

	float _minPitchAngle, _maxPitchAngle;

	UPROPERTY()
	FVector _relativePosition;

	UPROPERTY()
	FRotator _rotation;

	UPROPERTY()
	FRotator _defaultRotation;

	UPROPERTY()
	AProtoPlayerCameraManager* _camera;
	
public:	

	UBaseCameraMode();
	
	UFUNCTION()
	virtual void UpdateViewTarget(FTViewTarget& outVT, float deltaTime) PURE_VIRTUAL(UBaseCameraMode::UpdateViewTarget,);
	
	UFUNCTION()
	virtual void SetRotationAndRelatedStuff(FRotator oldDefaultRotation) PURE_VIRTUAL (UBaseCameraMode::SetRotationAndRelatedStuff,);

	UFUNCTION()
	virtual bool InterpolateIn(FTViewTarget& outVT, float deltaTime, float interpolationSpeed) PURE_VIRTUAL(UBaseCameraMode::InterpolateIn, return false;);
	
	virtual void UpdateYaw(float value);
	virtual void UpdatePitch(float value);
	void SetCamera(AProtoPlayerCameraManager* camera);

	FORCEINLINE FRotator GetDefaultRotation()const 
	{ 
		return _defaultRotation; 
	}
};

/******* Third person Mode *******/
UCLASS()
class PROTO_API UThirdPersonCameraMode : public UBaseCameraMode
{
	GENERATED_BODY()
	
public:
	UThirdPersonCameraMode();

	UFUNCTION()
	void UpdateViewTarget(FTViewTarget& outVT, float deltaTime);

	UFUNCTION()
	void SetRotationAndRelatedStuff(FRotator oldDefaultRotation);

	UFUNCTION()
	bool InterpolateIn(FTViewTarget& outVT, float deltaTime, float interpolationSpeed);
	
	void DoCollisionTest(FVector& desiredLocation);
};

/******* Shoulder Mode *******/
UCLASS()
class PROTO_API UShoulderCameraMode : public UBaseCameraMode
{
	GENERATED_BODY()

private:
	UPROPERTY()
	FRotator _rotationDelta;

public:
	UShoulderCameraMode();

	UFUNCTION()
	void UpdateViewTarget(FTViewTarget& outVT, float deltaTime);

	UFUNCTION()
	void SetRotationAndRelatedStuff(FRotator oldDefaultRotation);
	
	UFUNCTION()
	bool InterpolateIn(FTViewTarget& outVT, float deltaTime, float interpolationSpeed);
	
	void UpdateYaw(float value) override;
};

customPlayerCameraManager.cpp

#include "Proto.h"
#include "ProtoPlayerCameraManager.h"
//#include "BaseCameraMode.h"
//#include "ThirdPersonCameraMode.h"
//#include "ShoulderCameraMode.h"

AProtoPlayerCameraManager::AProtoPlayerCameraManager()
{
	_isCameraIsInterpoling = false;
}

void AProtoPlayerCameraManager::BeginPlay()
{
	Super::BeginPlay();

	CreateCameraModesAndSetupInitial();
}

void AProtoPlayerCameraManager::UpdateViewTarget(FTViewTarget& outVT, float deltaTime)
{
	if (_isCameraIsInterpoling)
		_isCameraIsInterpoling = _currentCameraMode->InterpolateIn(outVT, deltaTime, 20.0f);
	else
		_currentCameraMode->UpdateViewTarget(outVT, deltaTime);
}

void AProtoPlayerCameraManager::UpdatePitch(float value)
{
	_currentCameraMode->UpdatePitch(value);
}

void AProtoPlayerCameraManager::UpdateYaw(float value)
{	
	_currentCameraMode->UpdateYaw(value);
}

void AProtoPlayerCameraManager::LimitCameraPitch(FRotator& rotation, float minPitch, float maxPitch)
{
	LimitViewPitch(rotation, minPitch, maxPitch);
}

UBaseCameraMode* AProtoPlayerCameraManager::CreateCameraMode(UClass* cameraModeClass)
{
	UBaseCameraMode* cameraMode = NewObject<UBaseCameraMode>(GetTransientPackage(), cameraModeClass);
	cameraMode->SetCamera(this);
	return cameraMode;
}

void AProtoPlayerCameraManager::CreateCameraModesAndSetupInitial()
{
	_cameraModes.Add(CreateCameraMode(UThirdPersonCameraMode::StaticClass()));
	_cameraModes.Add(CreateCameraMode(UShoulderCameraMode::StaticClass()));

	_currentCameraMode = _cameraModes[0];
}

void AProtoPlayerCameraManager::ChangeCameraMode(int cameraMode)
{
	FRotator oldDefaultRotation = _currentCameraMode->GetDefaultRotation();
	
	_currentCameraMode = _cameraModes[cameraMode];
	_currentCameraMode->SetRotationAndRelatedStuff(oldDefaultRotation);
	_isCameraIsInterpoling = true;
}

/******* Camera Modes *******/

/******* Base Mode *********/
UBaseCameraMode::UBaseCameraMode()
{
}

void UBaseCameraMode::UpdatePitch(float value)
{
	_rotation.Pitch += value;
	_camera->LimitCameraPitch(_rotation, _minPitchAngle, _maxPitchAngle);
}

void UBaseCameraMode::UpdateYaw(float value)
{
	_rotation.Yaw += value;
}

void UBaseCameraMode::SetCamera(AProtoPlayerCameraManager* camera)
{
	_camera = camera;
}


/******* Third Person Mode *********/
UThirdPersonCameraMode::UThirdPersonCameraMode()
{
	_relativePosition = FVector(-200.0f, 0.0f, 0.0f);
	_rotation = FRotator(0.0f);
	_defaultRotation = _rotation;
	_maxPitchAngle = 25.0f;
	_minPitchAngle = -50.0f;
}

void UThirdPersonCameraMode::UpdateViewTarget(FTViewTarget& outVT, float deltaTime)
{
	FVector finalLocation, characterLocation;
	FRotator finalRotation;

	characterLocation = outVT.Target->GetActorLocation();

	FRotationMatrix cameraRotation(FRotator(_rotation.Pitch, _rotation.Yaw, 0.f));

	finalLocation = characterLocation + cameraRotation.TransformPosition(_relativePosition);

	DoCollisionTest(finalLocation);

	finalRotation = (characterLocation - finalLocation).Rotation();

	outVT.POV.Location = finalLocation;
	outVT.POV.Rotation = finalRotation;
}

void UThirdPersonCameraMode::SetRotationAndRelatedStuff(FRotator oldDefaultRotation)
{
	_rotation = _defaultRotation;
	_rotation.Yaw += _camera->GetCameraRotation().Yaw - oldDefaultRotation.Yaw;
}

bool UThirdPersonCameraMode::InterpolateIn(FTViewTarget& outVT, float deltaTime, float interpolationSpeed)
{
	FRotator actualRotation = outVT.POV.Rotation;
	FRotator outRotation = FMath::RInterpTo(actualRotation, _rotation, deltaTime, interpolationSpeed);

	if (outRotation.Equals(_rotation, 1))
		outRotation = _rotation;

	FVector actualPosition = outVT.POV.Location;

	FRotationMatrix cameraRotation(FRotator(_rotation.Pitch, _rotation.Yaw, 0.f));
	FVector desiredPosition =  outVT.Target->GetActorLocation() + cameraRotation.TransformPosition(_relativePosition);
	
	FVector outPosition = FMath::VInterpTo(actualPosition, desiredPosition, deltaTime, interpolationSpeed);

	if (outPosition.Equals(desiredPosition, 1))
		outPosition = desiredPosition;

	outVT.POV.Location = outPosition;
	outVT.POV.Rotation = outRotation;

	if ((outPosition == desiredPosition) && (outRotation == _rotation))
		return false;
		
	return true;
}

void UThirdPersonCameraMode::DoCollisionTest(FVector& desiredLocation)
{
	FCollisionQueryParams traceParams = FCollisionQueryParams(FName(TEXT("Trace")), true, _camera->GetViewTargetPawn());
	
	traceParams.bTraceComplex = true;
	traceParams.bTraceAsyncScene = true;
	traceParams.bReturnPhysicalMaterial = true;
	
	FHitResult hit(ForceInit);

	UWorld* world = _camera->();

	FVector characterLocation = _camera->GetViewTargetPawn()->GetActorLocation();

	world->SweepSingleByChannel(hit, characterLocation, desiredLocation, FQuat::Identity, ECC_Camera, FCollisionShape::MakeSphere(12.0f), traceParams);
	
	if (hit.bBlockingHit)
		desiredLocation = hit.Location;
}


/******* Shoulder Mode *********/
UShoulderCameraMode::UShoulderCameraMode()
{
	_relativePosition = FVector(-93.0f, 65.0f, 78.0f);
	_rotation = FRotator(0.0f, 10.0f, 0.0f);
	_defaultRotation = _rotation;
	_rotationDelta = FRotator(0.0f);
	_maxPitchAngle = 10.0f;
	_minPitchAngle = -20.0f;
}

void UShoulderCameraMode::UpdateViewTarget(FTViewTarget& outVT, float deltaTime)
{
	FRotationMatrix cameraRotation(FRotator(0.f, _rotationDelta.Yaw, 0.f));
	//outVT.POV.Location = outVT.Target->GetActorLocation() + cameraRotation.TransformPosition(_relativePosition);
	outVT.POV.Location = outVT.Target->GetActorLocation() + _relativePosition;
	outVT.POV.Rotation = _rotation;
}

void UShoulderCameraMode::SetRotationAndRelatedStuff(FRotator oldDefaultRotation)
{	
	_rotation = _defaultRotation;
	_rotation.Yaw += _camera->GetCameraRotation().Yaw;

	_rotationDelta.Yaw = _camera->GetCameraRotation().Yaw;
	_rotationDelta.Pitch = _rotation.Roll = 0.0f;
}

bool UShoulderCameraMode::InterpolateIn(FTViewTarget& outVT, float deltaTime, float interpolationSpeed)
{
	FRotator actualRotation = outVT.POV.Rotation;

	FRotator outRotation = FMath::RInterpTo(actualRotation, _rotation, deltaTime, interpolationSpeed);

	if (outRotation.Equals(_rotation, 1))
	{
		outRotation = _rotation;
		_rotationDelta = actualRotation;
	}

	FVector actualPosition = outVT.POV.Location;

	FRotationMatrix cameraRotation(FRotator(0.f, _rotationDelta.Yaw, 0.f));
	FVector desiredPosition =  outVT.Target->GetActorLocation() + cameraRotation.TransformPosition(_relativePosition);

	FVector outPosition = FMath::VInterpTo(actualPosition, desiredPosition, deltaTime, interpolationSpeed);

	if (outPosition.Equals(desiredPosition, 1))
		outPosition = desiredPosition;

	outVT.POV.Location = outPosition;
	outVT.POV.Rotation = outRotation;

	if ((outPosition == desiredPosition) && (outRotation == _rotation))
		return false;
		
	return true;
}

void UShoulderCameraMode::UpdateYaw(float value)
{
	Super::UpdateYaw(value);
	_rotationDelta.Yaw += value;
}

playerController.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "Proto.h"
#include "ProtoPlayerController.h"
#include "InputChord.h"
#include "Engine.h"
#include "ProtoPlayerCameraManager.h"

AProtoPlayerController::AProtoPlayerController()
{
	PlayerCameraManagerClass = AProtoPlayerCameraManager::StaticClass();
	_cameraMoveSpeed = 100.0f;
}

void AProtoPlayerController::Possess(APawn* pawn)
{
	_pawn = CastChecked<AProtoCharacter>(pawn);
	Super::Possess(pawn);
}

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

	InputComponent->BindAxis("MoveForward", this, &AProtoPlayerController::MoveForward);
	InputComponent->BindAxis("MoveSide", this, &AProtoPlayerController::MoveSide);

	InputComponent->BindAxis("Turn", this, &AProtoPlayerController::Turn);
	InputComponent->BindAxis("LookUp", this, &AProtoPlayerController::LookUp);

	InputComponent->BindAction("ChangeMode", IE_Pressed, this, &AProtoPlayerController::ChangeMode<1>);
	InputComponent->BindAction("ChangeMode", IE_Released, this, &AProtoPlayerController::ChangeMode<0>);

	InputComponent->BindKey(EKeys::T, IE_Pressed, this, &AProtoPlayerController::CenterCharacter);
}

void AProtoPlayerController::MoveForward(float value)
{
	if (value != 0.0)
		_pawn->MoveForward(value);
}

void AProtoPlayerController::MoveSide(float value)
{
	if (value != 0.0)
		_pawn->MoveSide(value);
}

void AProtoPlayerController::Turn(float value)
{
	Cast<AProtoPlayerCameraManager>(PlayerCameraManager)->UpdateYaw(value * ()->GetDeltaSeconds() * _cameraMoveSpeed);
	_pawn->Turn(value * ()->GetDeltaSeconds() * _cameraMoveSpeed);
}

void AProtoPlayerController::LookUp(float value)
{
	Cast<AProtoPlayerCameraManager>(PlayerCameraManager)->UpdatePitch(value * ()->GetDeltaSeconds() * _cameraMoveSpeed);
}

void AProtoPlayerController::CenterCharacter()
{
	_pawn->_needToRotate = true;
}

void AProtoPlayerController::ChangeMode(int newmode)
{
	_pawn->_needToRotate = true;
	_pawn->_onShoulderMode = !_pawn->_onShoulderMode;
	_pawn->GetCharacterMovement()->bOrientRotationToMovement = !_pawn->GetCharacterMovement()->bOrientRotationToMovement;
	
	Cast<AProtoPlayerCameraManager>(PlayerCameraManager)->ChangeCameraMode(newmode);
	if (GEngine)
		GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, FString::Printf(TEXT("Camera Yaw: %f"), Cast<AProtoPlayerCameraManager>(PlayerCameraManager)->GetCameraRotation().Yaw));
}

If you want to actually “switch active player controller” I can provide you the code from another project.

If you have any questions, let me know. I’ll help you.

Help that help you.

Have a good day.

gamer08

Awesome!!! Man you are my savior huge thank you! I have been trying to make it work two weeks.
One thing that I did not understand was InputComponent->BindAction("ChangeMode", IE_Released, this, &AProtoPlayerController::ChangeMode<0>); What is ChangeMode<0> especially <0> I have seen it for the first time. I assumed that it was a template but no. So I had to make two boolean variables and change them within the void ChangeMode() like that. NewMode = NewMode == 1 ? 0 : 1;

Thank you gamer08, It helped me a lot!

Yeah you’re right it’s a template method and yeah I forgot to send you the playerController.h to help you.

There it is. If you have any questions, I’m here.

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/PlayerController.h"
#include "ProtoCharacter.h"
#include "ProtoPlayerController.generated.h"


/**
 * 
 */
UCLASS()
class PROTO_API AProtoPlayerController : public APlayerController
{
	GENERATED_BODY()

private:
	UPROPERTY()
	AProtoCharacter* _pawn;

	UPROPERTY()
	float _cameraMoveSpeed;

	
	void MoveForward(float value);
	void MoveSide(float value);
	void Turn(float value);
	void LookUp(float value);
	void CenterCharacter();
	
	template<int mode>
	void ChangeMode()
	{ 
		ChangeMode(mode); 
	}
	
	void ChangeMode(int newMode);

	virtual void SetupInputComponent() override;
	virtual void Possess(APawn* aPawn) override;

public:
	AProtoPlayerController();

	FORCEINLINE FRotator GetCameraRotation() const 
	{ 
		return PlayerCameraManager->GetCameraRotation(); 
	}
};

Have a good day.

gamer08