Best way to handle player input without a pawn

Enhanced input seems to be tied to pawns and player controllers which raises the question of how to handle player input when there are no actors?

When the game opens, the first level is the main menu level that displays several widgets which allow the user to pick a player profile and change settings. There is no pawn or character controlling going on.

How do you handle player input like the Esc key taking you back in a menu using C++?

It would be efficient to have just single copies of a pause menu, a settings menu and credits which exist in a UGameInstance through several levels until the game quits. These would be created on game startup and can be called up with certain keys. The input handling should then be done by the game instance. But how do you set up input mapping in UGameInstance if enhanced input seems to require a player controller? Surely we don’t need to create and possess a pawn just to navigate menus.

Code so far:

void UMainGameInstance::Init()
{
	Super::Init();

	if (PauseMenuClass != nullptr)
	{
		PauseMenu = CreateWidget<UUserWidget>(this, PauseMenuClass);
	}

	// !!! This does not work because there are no player controllers yet
	// !!! How could we do this properly?
	UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetPlayerController()->GetLocalPlayer());

	Subsystem->ClearAllMappings();
	Subsystem->AddMappingContext(InputMapping, 0);
	...

There is always a PlayerController.

Pawns are possessed/controlled by the PlayerController. There may be no pawn/character if you are dead or in a menu, but the controller remains always.

2 Likes

At what point is a player controller created? Is there an event that the game instance can say happens strictly after a player controller has been created? Do player controllers persist through worlds/levels being changed?

UGameplayStatics::GetPlayerController requires a World object.

Opted to go with a solution where a custom LocalPlayerSubsystem owns all menus. A custom PlayerController class handles enhanced input mapping and calls the appropriate subsystem functions.