Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

New Input Multiple controllers not working...

Discussion in 'Input System' started by PaRsOnIsPhErE, Jan 10, 2020.

  1. PaRsOnIsPhErE

    PaRsOnIsPhErE

    Joined:
    Dec 19, 2018
    Posts:
    19
    Hi all,

    Pulling my hair out over this, I've read everything, or what feels like everything in the documentation on this... I'm developing a top down 2D game with the emphasis being on 4 players, although it can and will be played with less. I have 4 player objects / prefabs already in my scene, so I won't be instantiating anything. I have 2 Xbox 360 controllers plugged in which Unity is receiving data from as can be seen in Input Debugger.

    I have a player input component on 2 of the game objects, both using the same input actions map. But both controllers control all 4 objects in-game. Neither controller is being auto assigned to a player input, leaving 2 objects, uncontrollable. All I keep reading is PlayerInput will do this, and PlayerInput will assign that... what am I missing???

    I've read about performpairwithdevice etc but unsure how to go about using it... and am unsure where ever that will solve my issues. Input Debugger is showing 2 users (User#0, User#1), and both controllers.

    So if I understand the docs correctly, I need to somehow assign these controllers (devices), to each user, then each user to each PlayerInput (but doesn't playerInput, do this automatically). I've read about PlayerInput.user, but am not having any luck with that either to check if each player input has an assigned user.

    Below are screenshots of my inspector, Input Action and snippets of code.

    Thank you in advance for any help, advice and replies.

    upload_2020-1-10_20-41-43.png

    upload_2020-1-10_20-49-54.png

    Code (CSharp):
    1.    void Start()
    2.     {
    3.         //set variable rb to this ship's rigidbody component
    4.         rb = GetComponent<Rigidbody2D>();
    5.     }
    6.  
    7.     void Awake()
    8.     {
    9.  
    10.         controls = new PlayerControls();
    11.  
    12.         //sets the fire method to the Fire input action in actionmap
    13.         controls.PlayerShip.Fire.started += ctx => Fire();
    14.  
    15.         controls.PlayerShip.Reset.started += ctx => Reset();
    16.  
    17.         //sets move to the X and Y values coming from the input action
    18.         controls.PlayerShip.Move.performed += ctx => move = ctx.ReadValue<Vector2>();
    19.         controls.PlayerShip.Move.canceled += ctx => move = Vector2.zero;
     
  2. PaRsOnIsPhErE

    PaRsOnIsPhErE

    Joined:
    Dec 19, 2018
    Posts:
    19
    I've realised after reading on another post, that the code i'm using to move my players doesn't allow for local multiplayer, and I will have to use methods created by player input (OnMove(), OnFire() etc).

    So I have set all that up, but now player Input is now not assigning a device to the user.. input debugger shows a device active and with receiving input... I've removed the other player objects from my scene so this is currently the only object with a Player Input Component.

    I did quickly add another player object too see if the second Player Input component would create a second User and it did, but didn't assign my currently wired in Xbox360 controller to either... I thought the PlayerInput component was supposed to control all the auto assign side of things...

    Below is a screenshot of the game running in-editor. I've highlighted the area where device is showing as empty. I can't find reference to this anywhere, so unsure where ever a device would actually show up here or not.

    Any help, or advice in the right direction is greatly appreciated! @Kurt-Dekker you helped me with my last issue, do you have any ideas with this?? Thank you!

    upload_2020-1-11_12-58-59.png
     
    TP3 and Static4242 like this.
  3. Static4242

    Static4242

    Joined:
    Jan 27, 2020
    Posts:
    8
    Code it like this as opposed to using the lambda functions.

    Code (CSharp):
    1.    Vector3 move;
    2.     Vector2 moveDir;
    3.     float aim;
    4.     Vector2 aimDir;
    5.     void Start()
    6.     {
    7.         player = Instantiate(playerObj, new Vector3(0.0f, 1.0f, 0.0f), Quaternion.identity);
    8.         player.GetComponent<MCPlayerinit>().playNum = playNum;
    9.     }
    10.     void Update()
    11.     {
    12.         Move();
    13.         Aim();
    14.     }
    15.     void Move()
    16.     {
    17.         move = new Vector3(moveDir.x, 0.0f, moveDir.y) * moveSpeed * Time.deltaTime;
    18.         player.transform.Translate(move, Space.World);
    19.     }
    20.     void Aim()
    21.     {
    22.         Vector3 lookTowards = new Vector3(aimDir.x,0.0f,aimDir.y);
    23.         if (lookTowards != Vector3.zero)
    24.         {
    25.             player.transform.rotation = Quaternion.LookRotation(lookTowards);
    26.         }
    27.     }
    28.     void OnMove(InputValue value)
    29.     {
    30.         moveDir = value.Get<Vector2>();
    31.     }
    32.     void OnAim(InputValue value)
    33.     {
    34.         aimDir = value.Get<Vector2>();
    35.     }
    This coupled with a player input manager object (A gameobject with the Player Input Manger Component)
    should do the trick. A lot of tutorials are misleading when it comes to this.

    & Here, watch this tutorial.
    The brackeys one as well as some others don't really use the feature properly for local multiplayer.

     
    TP3 and RoyaltyMisha like this.
  4. arrste21

    arrste21

    Joined:
    May 5, 2020
    Posts:
    1
    What if we do not simply have prefabs for our players?
     
  5. FullMe7alJacke7

    FullMe7alJacke7

    Joined:
    Dec 17, 2013
    Posts:
    53
    Then make your players into prefabs? If you're not using prefabs now is a good time to start ;)
     
  6. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    5,450
    You either start using prefabs or you span your players and register the devices by hand.
     
  7. Max_Bol

    Max_Bol

    Joined:
    May 12, 2014
    Posts:
    124
    If you're using the Input System 1.0, there's a bit more documentation about how to manage multiple controllers and there's one super useful doc right HERE.

    You can set up a single variable for each controller (such as var gamepad_One; var gamepad_Two; etc.) and then setting up which is the latest gamepad to have been used. This method requires you to have all the controls set up in a single script which mean you got to have a "central" input manager of some sort.

    You can set up an array of gamepads ( var allGamepads = Gamepad.all; ) and then compare to find which, in the array, is being used by each player in row. It's kinda like the previous option, but easier to use as you can just, then, use integer and array to point out the source (like allGamepads[1] from the code example above if the player One uses the second registered gamepad.) This, again, requires you to create a sort of "central" input manager that manage all inputs done by the players in a single script.

    If you prefer an approach that has a bit more "adaptability", you could make it so that each player's prefab or character has their own Player Input component pre-attributed and directly target those Player Input instances from each individual player prefab instantiated. (Each players' instance has its own controls script and its own Player Input component. When instantiating the player's instance, you set up the variable in its control script so that it knows which gamepad should control its Player Input.

    This last approach is great, but involve a bit more work in managing the input as you need to make sure things are done in the proper order. For example, you could pre-register the actual Gamepad (like in the first example above) on a general script and then, when needed, attribute each gamepad to each player's instance as they are instantiated. It's a bit of a work-around, but it ensure that this remains under controls.

    The one down side of all of those approaches comes from the potential of a really simple, but bad situation.
    What happens if a player... unplug a controller mid-game?

    From that, it's possible check when a device is unplugged and when a device is plugged back in.
    If the same device is plugged back in, there's nothing you need to do as the registered Gamepad variable is actually link to the gamepad unique number and not just as a generic gamepad. (You might get some error though depending on how you read the unplugged gamepad while it's unplugged.)
    In the Devices doc of the Input System, here's the text that explains it:
    The Input System keeps track of disconnected Devices in InputSystem.disconnectedDevices. If one of these Devices reconnects later, the Input System can detect that the Device was connected before, and reuses its InputDevice instance. This allows the PlayerInputManager to reassign the Device to the same user again.

    The thing is more complex when it's a case where a player actually change his controller. This is a possible action if the player was using a certain controller that ran out of battery and don't have any spare batteries nor a way to charge/plug it. Maybe the player will, then, switch to a wired controller which, ultimately, is different.

    For this, you got to do some quick check with something like shown in the link above:
    Code (CSharp):
    1.  
    2. InputSystem.onDeviceChange +=
    3.         (device, change) =>
    4.         {
    5.             switch (change)
    6.             {
    7.                 case InputDeviceChange.Added:
    8.                     // New Device.
    9.                     break;
    10.                 case InputDeviceChange.Disconnected:
    11.                     // If this is happening, activate some boolean that will tell the game that a controller is now "missing".
    12.                     break;
    13.                 case InputDeviceChange.Connected:
    14.                     // Plugged back in.
    15.                     break;
    16.                 case InputDeviceChange.Removed:
    17.                     // Remove from Input System entirely; by default, Devices stay in the system once discovered.
    18.                     break;
    19.                 default:
    20.                     // Always includes a default case for when a unused case is being called. Leave it empty.
    21.                     break;
    22.             }
    23.         }
    24.  
    As you can see, you can get whenever a device got plugged back in, when a new device was plugged in and when one is disconnected. Now, how you set up to relink with a new device depends on how you set them up in the first place. You got to have some kind of menu/pause/warning that activates when the case InputDeviceChange.Disconnected; is being activate/called from which you can get the player with the missing controller to press a button on the new controller to set it up and replace the disconnected controller.
     
unityunity