Change PlayerController dynamically

I have a third-person character who I control with a gamepad. I have a couple of different UI menus that I pop up at various times, which require different kinds of input. I want to maintain the same camera that is showing the character, and just use a different PlayerController for deciding what to do with the input.

I do not want to put extra decisions into one PlayerController, like “if(menuShown)… else…”. Indirection between the button-press and the character action is lag, and I want to eliminate that as much as possible. Further, in the interests of good OO programming practices, I don’t want some catch-all PlayerController that is coupled with several other pieces of code.

I tried calling SwapPlayerControllers, but it seems to set the camera below the level, and doesn’t actually receive input. The documentation for SwapPlayerControllers says that it will discard the “old” PC, which I don’t want to do: I just want to temporarily handle input in a different PC, and then go back to the original one.

Is this possible with UE4? I’m surprised that I’m having such a struggle doing something that seems pretty common.

So I’ve spent a couple of hours digging through the engine code to see how this should work, and it really is not a trivial thing to accomplish. The game is making a lot of assumptions about input and controlling the player.

Fortunately for me I can mostly accomplish what I want by using APlayerController::SetInputMode, but I’m a bit dissatisfied with this approach. I’d really like to dynamically change the class that is responding to input.

never swap entire PlayerControllers, they are not meant to be swapped out. instead, swap out part of a player controller, as a separate actor that the player controller manages.

its like a brain transplant vs an eye transplant…

long story short, you should make your player controller spawn a menu manager actor, and enable input on that actor, allowing it to manage input for widgets it spawns.

coupling an object with several other pieces of code is not a bad thing to do in OOP, its only tight coupling that can be limiting, but even that has its uses. the player controller and pawn will probably be coupled with more systems than other parts of the code, because they are central parts to the simulation you are making. but if you want to avoid tight coupling as much as possible, then use interface functions to communicate anonymously between actors.

That’s odd… “they are not meant to be swapped out” seems to be directly contradicted by the function AGameModeBase::SwapPlayerControllers. I’m unclear about what you mean when you say “spawn a menu manager actor, and enable input on that actor” That’s exactly what I want to do; I want to pass action mapped inputs directly to different actors. But I don’t want to put a bunch of decisions directly into the APlayerController; that is bad practice. I’m also not too keen on setting up indirection with functors or delegates that let me re-assign where the input goes to (essentially giving the player controller a virtual table).

How exactly are you proposing I “enable input on that actor”?

“coupling an object with several other pieces of code is not a bad thing to do in OOP” I am relatively new to the Unreal engine, but I’ve been coding in C++ for a looong time, and I disagree with you on that statement.

without any coupling, your software would not be able to do anything. you need classes to at least loosely couple in most cases, but when you have something as central as the player controller, its fine to have a lot of other classes relying on the existence of a player controller in order to function. player controllers are not optional in UE4, they are a very important piece of the framework.

loosely coupling an object with several other pieces of code is not a problem, as long as editing one doesn’t make you also have to edit the other. you really shouldn’t follow one size fits all OOP rules for designing every class, that stuff is for beginners to learn the principles of oop, but in practice, some classes need far more coupling than others, and if designed properly, that should not be a problem.

do you truly believe that only 1 other object should have a reference to a player controller?

the player controller can enable input on an actor:

Obviously there’s going to be some coupling with anything that does inter-communication between objects. That doesn’t mean we should just default to building huge monolithic catch-all classes. The player controller being a central aspect of a game is exactly why any interaction with it should be designed correctly. Every indirection between a button press and the intended action is lag. As game developers we should strive to get as close to the metal as possible, and input is a prime example of where that is important.

Look I wasn’t trying to get into a debate about object-oriented design, I just wanted to know the best way to change how input is handled at run-time! I’m still unclear as to what you’re advocating in terms of doing this: Decisions in the input bindings that determine where the input is routed to? A virtual table of function pointers / functors / delegates that determine where input is routed to? Unbinding/rebinding the action mappings?

Ah, and DisableInput as well. Now that’s what I’m looking for, thanks!

EDIT: Upon further investigation that is not what I’m looking for. EnableInput and DisableInput just set a boolean flag, meaning they’ll make a decision about handling input. What I really want to do is APlayerController::PushInputComponent and PopInputComponent to make sure there is only one item in the stack receiving input. There’s still way more code in the way between the input and my receipt of it than is ideal, but I believe this is as good as it will get with this engine…

Hey Inconceivable, I’ve read this thread and am disappointed with the suggested solution - I have to agree that swapping controllers instead of having a monolith makes more sense. If you ended up doing something different, would you mind sharing?

AGameModeBase has a public function called SwapPlayerControllers(OldController, NewController). This is called on map or level swap but seems like the function you’d want to use when trying to force the player to use a new controller. Unfortunately it’s not exposed to Blueprint, so if you’re limited on coding this might not work for you.

AGameModeBase::SwapPlayerControllers | Unreal Engine Documentation