Create a new local player/ new player controller on unassigned gamepad button press

Hi, I am trying to give a way for my players to join the lobby in a local multiplayer game (non splitscreen) with the press of a button. The end goal is to have a menu like smash bros (for example). However I cannot find a way to do that.

Should I create player controllers for each player, and then simply let them be spectators if they didn’t join ? If so what should I do ?

My initial goal was to only create ULocalPlayer for players who wanna join. I have a way of detecting button pressed for unassigned controllers (through the UEnhancedInputWorldSubsystem), but I cannot find the controller id that pressed the button.

If you have a solution I would appreciate it.
Thanks a lot

So I found a workaround that is kinda ugly and invasive (in my opinion) but it works :

You should create a custom engine subsystem, who’s single purpose is to send an event on key press (you can add this feature on any subsystem really, in my case I didn’t have one so I created it). This event is fired when an input preprocessor receives a key down.
Relevant engine files :
Engine\Source\Runtime\Engine\Classes\GameFramework\InputDeviceSubsystem.h
Engine\Source\Runtime\Engine\Private\GameFramework\InputDeviceSubsystem.cpp
Engine\Source\Runtime\Slate\Public\Framework\Application\IInputProcessor.h

Example :
YourSubsystem.h

#pragma once

#include "CoreMinimal.h"
#include "Subsystems/EngineSubsystem.h"
#include "YourSubsystem.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAnyKeyPressSignature, FKeyEvent, KeyEvent);

class FYourSubsystemInputProcessor;

/**
 * 
 */
UCLASS()
class UYourSubsystem : public UEngineSubsystem
{
	GENERATED_BODY()

public:
	static UYourSubsystem* Get();

	UFUNCTION(BlueprintCallable, BlueprintPure)
	static FInputDeviceId GetInputDeviceIdFromKeyEvent(FKeyEvent KeyEvent);
	
	virtual void Initialize(FSubsystemCollectionBase& Collection) override;
	virtual void Deinitialize() override;

	UPROPERTY(BlueprintAssignable)
	FOnAnyKeyPressSignature OnAnyKeyPressDelegate;

private:
	friend class FYourSubsystemInputProcessor;
	
	void PreprocessorReceivedInput(const FKeyEvent& KeyEvent);

	TSharedPtr<FYourSubsystemInputProcessor> InputProcessor;
};

YourSubsystem.cpp

#include "YourSubsystem.h"

#include "Framework/Application/IInputProcessor.h"

class FYourSubsystemInputProcessor : public IInputProcessor
{
	friend class FYourSubsystem;

public:

	virtual void Tick(const float DeltaTime, FSlateApplication& SlateApp, TSharedRef<ICursor> Cursor) override
	{
		
	}
	
	void NotifySubsystemOfKeyPress(const FKeyEvent& KeyEvent)
	{
		if (UYourSubsystem* Subsystem = UYourSubsystem::Get())
		{
			Subsystem->PreprocessorReceivedInput(KeyEvent);
		}
	}
	
	virtual bool HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& InEvent) override
	{
		NotifySubsystemOfKeyPress(InEvent);
		return false;
	}
};

UYourSubsystem* UYourSubsystem::Get()
{
	return GEngine ? GEngine->GetEngineSubsystem<UYourSubsystem>() : nullptr;
}

FInputDeviceId UXpinEngineSubsystem::GetInputDeviceIdFromKeyEvent(FKeyEvent KeyEvent)
{
	return KeyEvent.GetInputDeviceId();
}

void UYourSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);

	// We have to have a valid slate app to run this subsystem
	check(FSlateApplication::IsInitialized());
	
	InputProcessor = MakeShared<FYourSubsystemInputProcessor>();
	FSlateApplication::Get().RegisterInputPreProcessor(InputProcessor);
}

void UYourSubsystem::Deinitialize()
{
	Super::Deinitialize();
	
	if (FSlateApplication::IsInitialized())
	{
		FSlateApplication::Get().UnregisterInputPreProcessor(InputProcessor);
	}
	InputProcessor.Reset();
}

void UYourSubsystem::PreprocessorReceivedInput(const FKeyEvent& KeyEvent)
{
	OnAnyKeyPressDelegate.Broadcast(KeyEvent);
}

You can then use this event that is fired on EVERY KEY PRESS and check if the controller id stored in KeyEvent has a player. If not, create it.

I also added a little helper blueprint function that returns the Input device id since the function is not exposed in blueprints natively.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.