[Solved] Two PlayerInputs

I have two quite independent game objects in one scene: Player and Manager. They work in parallel and read completely different inputs. I tried creating two InputActions assets and assigning them into two PlayerInput components (one for Player and Manager), but only single of those components work. So apparently multiple PlayerInputs is not an option.

One way of solving this problem I was thinking about is having ActionMap on a component where I will enable and disable it with the component and manually read values each update. But it is inconvenient to have a somewhat big group of actions being stored and edited inside the component, and not in a dedicated asset as it is with InputActions asset.

PlayerInput automatically takes care of duplicating actions. Assign the same action asset to one, then duplicate it and you have two players.

Note that by default each player receives a unique set of devices. So if player 1 grabs everything and there's nothing left for player 2, the latter one will not see any input coming through.

Use control schemes to separate different means of controlling your game and prevent PlayerInput from assigning more devices than necessary to a single player.

Use PlayerInput.Instantiate to explicitly pair devices to players.

USe PlayerInputManager to have a lobby where players join explicitly through devices.

1 Like

@Rene-Damm

I have assigned two InputAction assets to two PlayerInput components. Now I can see in the debug section that one component has Keyboard&Mouse devices and the other PlayerInput has nothing. So there is no way keyboard and mouse can be used by two PlayerInputs simultaneously?

Or is there another way how I can execute and read values from two different action maps stored as assets?

The same control scheme can be used by arbitrary many players but not the same devices, by default.

To have two players use the same device, you need to manually instantiate the players with those devices or pair the devices manually to the player's InputUsers.

// Create two players both using the same keyboard and mouse.
PlayerInput.Instantiate(playerPrefab, controlScheme: "Keyboard&Mouse", devices: new[] { Keyboard.current, Mouse.current });
PlayerInput.Instantiate(playerPrefab, controlScheme: "Keyboard&Mouse", devices: new[] { Keyboard.current, Mouse.current });
1 Like

Thank you very much, I have finally understood.

I have created extension class:

using UnityEngine;
using UnityEngine.InputSystem;

public static class InputInitializer
{
    public static PlayerInput Initialize(this PlayerInput input)
    {
        var instance = PlayerInput.Instantiate(input.gameObject, controlScheme: "Keyboard&Mouse", pairWithDevices: new InputDevice[] { Keyboard.current, Mouse.current });

        instance.transform.parent = input.transform.parent;
        instance.transform.position = input.transform.position;

        Object.Destroy(input.gameObject);
        return instance;
    }
}

Which I call like this:

private void Awake()
{
    input = GetComponentInChildren<PlayerInput>().Initialize();
}

With object hierarchy like this ("Input" object has PlayerInput component):
5081573--499997--upload_2019-10-18_15-7-48.png

@Rene-Damm Although it would be nice to have a built-in option to "force" players to pair with selected devices.

Sorry for up this topic (and for my bad english), but i don't understand all what you did @alkaitagi
In my case, i try to use left stick on my gamepad to moving my player, and the right stick to rotate the camera, which is in an other GO (and i can't just place my camera in the player). So here is my questions :
- Where did you write this lines, on which script ?
- what is your "input" variable in the awake function and how it is work exactly ?

Thanks for the time

@MamieDev I did exactly what Rene showed - instantiated & binded a player input runtime. I suppose you would need to instantiate 2 input components as well, for the Player and for the Camera. InputInitializer is a static class, you can take it as is and it might help you. The second code block, the awake() function, just called the static class to create an input instance, which I saved in a local variable in my Player script for subsequent use.

Hey! This should theoretically work, but it won't let me attach the extension class as a script ?

Okay so if I put it in the script where I'm initializing everything, what it's doing instead is initializing my object indefinitely, over and over again, even though it should only run once with awake. :| I've figured out that what's going on is essentially that it creates a new object, and then that object runs the script... indefinitely. It also only returns a clone object which is throwing all my other scripts off.

1 Like

I'm having the same issue with the second player having no input devices. I have the players instantiated through another script so I can't instantiate via the playerinput.instantiate. Is there another way for the second player to get all the devices?

So what the function PlayerInput.Instantiate do exactly? , it doesnt seem to instantiate the prefab
I am calling
PlayerInput.Instantiate(animalCompanion, 1, "Gamepad1", -1, new[ ] { Gamepad.all[1] });
Do I need the animalCompanion on the scene already with a player.input component on it?

Edit:Nevermind I had an error that was preventing the instantiation gamepad.all had only one value

How do I get the spawned player to be used by the second gamepad?

Ok I found the solution thank you for the original comment