Search Unity

Question How to create an Input Action per device in code?

Discussion in 'Input System' started by Sangemdoko, Mar 20, 2022.

  1. Sangemdoko

    Sangemdoko

    Joined:
    Dec 15, 2013
    Posts:
    222
    Hi,

    I am making a local multiplayer game. I am using my own custom code (Not PlayerInput or PlayerInputManager) for dealing with input.

    I'm currently looping over all my input actions, listening to all inputs and then I check the input device to see what player pressed that input:

    Code (CSharp):
    1.  for (int i = 0; i < m_InputActionAsset.actionMaps.Count; i++) {
    2.      var map = m_InputActionAsset.actionMaps[i];
    3.      Debug.Log($"map {map.name} is enabled "+map.enabled);
    4.      for (int j = 0; j < map.actions.Count; j++) {
    5.          var action = map.actions[j];
    6.          action.started += HandleAnyInput;
    7.          action.performed += HandleAnyInput;
    8.          action.canceled += HandleAnyInput;
    9.      }
    10. }
    Code (CSharp):
    1. private void HandleAnyInput(InputAction.CallbackContext ctx)
    2. {
    3.     if (m_LastInputDeviceUsed != ctx.control.device) {
    4.         HandleLastInputDeviceChange(ctx);
    5.     }
    6.     for (int i = 0; i < m_PlayerConfigs.Length; i++) {
    7.         var playerConfiguration = m_PlayerConfigs[i];
    8.         if (playerConfiguration.InputDevice != ctx.control.device) { continue; }
    9.         if (m_LastPlayerConfigDeviceUsed != playerConfiguration) {
    10.             HandleLastPlayerConfigDeviceChange(playerConfiguration, ctx);
    11.         }
    12.            
    13.         playerConfiguration.HandleActionTriggered(ctx);
    14.        
    15.         //TODO should I break here, since not two players can have the same device?
    16.     }
    17. }
    The problem I have is that all the input actions are shared by all inputs. So if the keyboard start pressing the gamepad input won't do anything until the keyboard unpresses the input because the action start is still ongoing.

    I alrady assign devices to players using my custom PlayerConfig class. All I need is to create actions specific to a device such that they can be pressed independetly.

    How can I create an Input Action in code from the default InputActionAsset actions that is device specific?
     
  2. Sangemdoko

    Sangemdoko

    Joined:
    Dec 15, 2013
    Posts:
    222
    Ok I figured it out. I should have checked to documentation in more detail.

    The device cannot be assigned to an action directly. But it can be set on the action map or the action asset.

    So here is the code to dupplicated the input action asset and assign the device to it if anyone is interested:
    Code (CSharp):
    1.  protected InputActionAsset m_PlayerInputActionAsset;
    2. protected InputDevice[] m_ActionAssetDevices;
    3.  
    4. public void SetPlayerDevice(InputDevice inputDevice)
    5. {
    6.      m_InputDevice = inputDevice;
    7.      m_IsPlaying = inputDevice != null;
    8.  
    9.      //Create a Input Action asset specific to the player device.
    10.      if (m_PlayerInputActionAsset == null) {
    11.          var sharedActionAsset = GameManager.InputActionAsset.ToJson();
    12.          m_PlayerInputActionAsset = InputActionAsset.FromJson(sharedActionAsset);
    13.          m_ActionAssetDevices = new[] { m_InputDevice };
    14.          for (int i = 0; i < m_PlayerInputActionAsset.actionMaps.Count; i++) {
    15.              var map = m_PlayerInputActionAsset.actionMaps[i];
    16.              for (int j = 0; j < map.actions.Count; j++) {
    17.                  var action = map.actions[j];
    18.                  action.started += HandleActionTriggered;
    19.                  action.performed += HandleActionTriggered;
    20.                  action.canceled += HandleActionTriggered;
    21.              }
    22.          }
    23.        
    24.          m_PlayerInputActionAsset.Enable();
    25.      }
    26.      m_ActionAssetDevices[0] = m_InputDevice;
    27.      m_PlayerInputActionAsset.devices = m_ActionAssetDevices;
    28. }
     
  3. Sauron1234

    Sauron1234

    Joined:
    Sep 22, 2014
    Posts:
    29
    hey Im interested in what you are doing. I dislike the input system but like the access to devices. Hows your code coming along?
    Id like to do something similar.
    Are you basically making a list of inputActions on runtime and setting binding keys to them? is that it??
     
  4. Sangemdoko

    Sangemdoko

    Joined:
    Dec 15, 2013
    Posts:
    222
    So I make the InputActionAsset once in the Editor.
    Then since I am making a local multiplayer game I dupplicate the InputActionAsset for each player and assign a device to each dupplicate.

    This allows me to have one InputActionAsset that detects the input of all the players and then 4 others that detect inputs individually.

    So in the main menu I can allow everyone to control the UI, and then in the character select screen or in gameplay I allow individual input.

    It's also a good things when somone pauses the game, they are the only one that can unpause it.

    I hope that helps