Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Mapping different functions for two controllers - local multiplayer

Discussion in 'Multiplayer' started by kadeo13, Feb 18, 2020.

  1. kadeo13

    kadeo13

    Joined:
    Jul 8, 2019
    Posts:
    1
    My team and I are developing a local multiplayer game in Unity where one person drives a spaceship and the other person aims the reticle and shoots. I am using Unity's new Input System and have everything set up correctly such that the game responds to the controllers, however, it responds to input from both when it should only respond to input from one. We are using two Xbox One wireless controllers.

    For example: Player 1 should be the only one to move the ship with the left stick, Player 2's left stick should move the reticle around on the screen. However the ship moves if either of them use the left stick.

    I noticed that in the input action map tab there is an option to select a specific controller upload_2020-2-18_16-58-6.png
    Seeing as I have only two controllers currently connected I believe the machine is recognizing them, but doesn't seem to be able to tell them apart. If I map functionality to a specific player gamepad, the game stops functioning completely, but if I don't, both controllers can control the functions.

    Can anyone help me find a workaround? I've found multiple solutions for when more than one controllers are connected but they have the same button mappings. I haven't found anything about more than one controller functioning with different button mappings.

    Here's the code I'm working with in C#:
    Controller.cs - handles inputs

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.Events;
    5. using UnityEngine.InputSystem;
    6.  
    7. public class Controller : MonoBehaviour
    8. {
    9.     public delegate void InputEventHandler(InputValue inputValue);
    10.  
    11.     public event InputEventHandler _OnMovement;
    12.     public event InputEventHandler _OnShoot;
    13.     public event InputEventHandler _OnTest;
    14.  
    15.     private void OnMovement(InputValue inputValue)
    16.     {
    17.         Debug.Log("moving");
    18.         Debug.Log(inputValue.Get());
    19.         _OnMovement?.Invoke(inputValue);
    20.     }
    21.  
    22.     private void OnShoot(InputValue inputValue)
    23.     {
    24.         Debug.Log("shoot");
    25.         Debug.Log(inputValue.Get());
    26.         _OnShoot?.Invoke(inputValue);
    27.     }
    28. }
    29.  
    Controllers.cs - gets gamepad objects for each controller

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5.  
    6. public class Controllers : MonoBehaviour
    7. {
    8.     public GameObject controllerPrefab;
    9.     private List<Controller> controllers;
    10.  
    11.     public Controller GetController(int index)
    12.     {
    13.         if (controllers == null || index < 0 || index >= controllers.Count)
    14.         {
    15.             return null;
    16.         }
    17.         return controllers[index];
    18.     }
    19.  
    20.     private void Awake()
    21.     {
    22.         CreateControllers();
    23.         GetChildren();
    24.     }
    25.  
    26.     private void CreateControllers()
    27.     {
    28.         int playerIndex = 0;
    29.         foreach (Gamepad gamepad in Gamepad.all)
    30.         {
    31.             InputDevice inputDevice = gamepad.device;
    32.             Debug.LogFormat("Controllers - Device #{0} {1}", playerIndex, inputDevice);
    33.             PlayerInput playerInput = PlayerInput.Instantiate(controllerPrefab,
    34.                                                               playerIndex: playerIndex,
    35.                                                               pairWithDevice: inputDevice
    36.                                                              );
    37.             playerInput.transform.SetParent(this.gameObject.transform);
    38.             playerInput.transform.name = string.Format("Controller #{0}", playerIndex);
    39.             playerIndex++;
    40.         }
    41.     }
    42.  
    43.     private void GetChildren()
    44.     {
    45.         controllers = new List<Controller>();
    46.  
    47.         foreach (Transform child in transform)
    48.         {
    49.             Controller cef = child.GetComponent<Controller>();
    50.             controllers.Add(cef);
    51.         }
    52.     }
    53.  
    54.     public int Count(){
    55.         return controllers.Count;
    56.     }
    57. }
    58.  
    InputMaster.cs - code generated from actionmap

    Code (CSharp):
    1. // GENERATED AUTOMATICALLY FROM 'Assets/Scripts/Aliens/InputMaster.inputactions'
    2.  
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using UnityEngine.InputSystem;
    7. using UnityEngine.InputSystem.Utilities;
    8.  
    9. public class @InputMaster : IInputActionCollection, IDisposable
    10. {
    11.     public InputActionAsset asset { get; }
    12.     public @InputMaster()
    13.     {
    14.         asset = InputActionAsset.FromJson(@"{
    15.    ""name"": ""InputMaster"",
    16.    ""maps"": [
    17.        {
    18.            ""name"": ""Player"",
    19.            ""id"": ""aff4a64e-364f-45fd-824b-f7e41c89d50d"",
    20.            ""actions"": [
    21.                {
    22.                    ""name"": ""Shoot"",
    23.                    ""type"": ""Button"",
    24.                    ""id"": ""33aef77b-7bcc-45a8-8da8-4797e4b4535c"",
    25.                    ""expectedControlType"": ""Button"",
    26.                    ""processors"": """",
    27.                    ""interactions"": ""Tap""
    28.                },
    29.                {
    30.                    ""name"": ""Movement"",
    31.                    ""type"": ""Value"",
    32.                    ""id"": ""2b7a1c7a-697e-4e95-a6c6-dfc4e3ec3999"",
    33.                    ""expectedControlType"": ""Vector2"",
    34.                    ""processors"": """",
    35.                    ""interactions"": """"
    36.                }
    37.            ],
    38.            ""bindings"": [
    39.                {
    40.                    ""name"": """",
    41.                    ""id"": ""58a323d8-6e5b-4b34-a431-6f77732a64ac"",
    42.                    ""path"": ""<XInputController>/buttonSouth"",
    43.                    ""interactions"": """",
    44.                    ""processors"": """",
    45.                    ""groups"": ""Gamepad"",
    46.                    ""action"": ""Shoot"",
    47.                    ""isComposite"": false,
    48.                    ""isPartOfComposite"": false
    49.                },
    50.                {
    51.                    ""name"": """",
    52.                    ""id"": ""007726e1-57ab-4121-bd33-53a19efc065d"",
    53.                    ""path"": ""<XInputController>/leftStick"",
    54.                    ""interactions"": """",
    55.                    ""processors"": """",
    56.                    ""groups"": ""Gamepad"",
    57.                    ""action"": ""Movement"",
    58.                    ""isComposite"": false,
    59.                    ""isPartOfComposite"": false
    60.                }
    61.            ]
    62.        }
    63.    ],
    64.    ""controlSchemes"": [
    65.        {
    66.            ""name"": ""Gamepad"",
    67.            ""bindingGroup"": ""Gamepad"",
    68.            ""devices"": []
    69.        }
    70.    ]
    71. }");
    72.         // Player
    73.         m_Player = asset.FindActionMap("Player", throwIfNotFound: true);
    74.         m_Player_Shoot = m_Player.FindAction("Shoot", throwIfNotFound: true);
    75.         m_Player_Movement = m_Player.FindAction("Movement", throwIfNotFound: true);
    76.     }
    77.  
    78.     public void Dispose()
    79.     {
    80.         UnityEngine.Object.Destroy(asset);
    81.     }
    82.  
    83.     public InputBinding? bindingMask
    84.     {
    85.         get => asset.bindingMask;
    86.         set => asset.bindingMask = value;
    87.     }
    88.  
    89.     public ReadOnlyArray<InputDevice>? devices
    90.     {
    91.         get => asset.devices;
    92.         set => asset.devices = value;
    93.     }
    94.  
    95.     public ReadOnlyArray<InputControlScheme> controlSchemes => asset.controlSchemes;
    96.  
    97.     public bool Contains(InputAction action)
    98.     {
    99.         return asset.Contains(action);
    100.     }
    101.  
    102.     public IEnumerator<InputAction> GetEnumerator()
    103.     {
    104.         return asset.GetEnumerator();
    105.     }
    106.  
    107.     IEnumerator IEnumerable.GetEnumerator()
    108.     {
    109.         return GetEnumerator();
    110.     }
    111.  
    112.     public void Enable()
    113.     {
    114.         asset.Enable();
    115.     }
    116.  
    117.     public void Disable()
    118.     {
    119.         asset.Disable();
    120.     }
    121.  
    122.     // Player
    123.     private readonly InputActionMap m_Player;
    124.     private IPlayerActions m_PlayerActionsCallbackInterface;
    125.     private readonly InputAction m_Player_Shoot;
    126.     private readonly InputAction m_Player_Movement;
    127.     public struct PlayerActions
    128.     {
    129.         private @InputMaster m_Wrapper;
    130.         public PlayerActions(@InputMaster wrapper) { m_Wrapper = wrapper; }
    131.         public InputAction @Shoot => m_Wrapper.m_Player_Shoot;
    132.         public InputAction @Movement => m_Wrapper.m_Player_Movement;
    133.         public InputActionMap Get() { return m_Wrapper.m_Player; }
    134.         public void Enable() { Get().Enable(); }
    135.         public void Disable() { Get().Disable(); }
    136.         public bool enabled => Get().enabled;
    137.         public static implicit operator InputActionMap(PlayerActions set) { return set.Get(); }
    138.         public void SetCallbacks(IPlayerActions instance)
    139.         {
    140.             if (m_Wrapper.m_PlayerActionsCallbackInterface != null)
    141.             {
    142.                 @Shoot.started -= m_Wrapper.m_PlayerActionsCallbackInterface.OnShoot;
    143.                 @Shoot.performed -= m_Wrapper.m_PlayerActionsCallbackInterface.OnShoot;
    144.                 @Shoot.canceled -= m_Wrapper.m_PlayerActionsCallbackInterface.OnShoot;
    145.                 @Movement.started -= m_Wrapper.m_PlayerActionsCallbackInterface.OnMovement;
    146.                 @Movement.performed -= m_Wrapper.m_PlayerActionsCallbackInterface.OnMovement;
    147.                 @Movement.canceled -= m_Wrapper.m_PlayerActionsCallbackInterface.OnMovement;
    148.             }
    149.             m_Wrapper.m_PlayerActionsCallbackInterface = instance;
    150.             if (instance != null)
    151.             {
    152.                 @Shoot.started += instance.OnShoot;
    153.                 @Shoot.performed += instance.OnShoot;
    154.                 @Shoot.canceled += instance.OnShoot;
    155.                 @Movement.started += instance.OnMovement;
    156.                 @Movement.performed += instance.OnMovement;
    157.                 @Movement.canceled += instance.OnMovement;
    158.             }
    159.         }
    160.     }
    161.     public PlayerActions @Player => new PlayerActions(this);
    162.     private int m_GamepadSchemeIndex = -1;
    163.     public InputControlScheme GamepadScheme
    164.     {
    165.         get
    166.         {
    167.             if (m_GamepadSchemeIndex == -1) m_GamepadSchemeIndex = asset.FindControlSchemeIndex("Gamepad");
    168.             return asset.controlSchemes[m_GamepadSchemeIndex];
    169.         }
    170.     }
    171.     public interface IPlayerActions
    172.     {
    173.         void OnShoot(InputAction.CallbackContext context);
    174.         void OnMovement(InputAction.CallbackContext context);
    175.     }
    176. }
    177.  
    GameController.cs - helps generate controllers ingame

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class GameControllers : MonoBehaviour
    6. {
    7.     public static GameControllers Instance { get; private set; }
    8.  
    9.     public Controllers controllers { get; private set; }
    10.     // Start is called before the first frame update
    11.  
    12.     private void CreateSingleton()
    13.     {
    14.         if (Instance == null)
    15.         {
    16.             Instance = this;
    17.             DontDestroyOnLoad(gameObject);
    18.         }
    19.         else
    20.         {
    21.             Destroy(gameObject);
    22.         }
    23.     }
    24.  
    25.     private void Awake()
    26.     {
    27.         CreateSingleton();
    28.         controllers = transform.Find("Controllers").GetComponent<Controllers>();
    29.     }
    30. }
    31.  
    Please help I've been trying to find a work around for weeks now. If I'm missing anything please let me know. Thanks!