Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Question Input System v1.0 - PlayerInput.Instantiate seems to clone InputActionAsset, causing rebinding issue

Discussion in 'Input System' started by SmolPadok, Oct 11, 2020.

  1. SmolPadok

    SmolPadok

    Joined:
    Nov 25, 2016
    Posts:
    2
    Greetings. I have been busy implementing the new Input System in my game.

    Here is what I have so far:
    • An InputActionAsset for player controls. There are 2 bindings in each action for Player1 and Player2 control schemes. Each player uses the same InputActionAsset but with different control schemes for each of them. All of the players use the same input device simultaneously, in this case using Keyboard.current.

    • A game manager that instantiates a number of gameobjects from a prefab using PlayerInput.Instantiate. The manager loops through an array of booleans that checks if this player is active, then instantiates into the scene. Control schemes of associated number is assigned to each player.
    Code (CSharp):
    1. for (int i = 0; i < active.Length; i++)
    2.         {
    3.             if(active[i]){
    4.                 string name = "Player" + (i+1);
    5.  
    6.                 PlayerInput player = PlayerInput.Instantiate(playerPrefab, -1, name, -1, Keyboard.current);
    7.                 InputUser.PerformPairingWithDevice(Keyboard.current, player.user, InputUserPairingOptions.None);
    8.                 player.defaultControlScheme = name;
    9.             }
    10.         }
    • A rebinding UI menu that allows user to override the default controls for each player. This is taken from the Rebinding UI sample. The menu is prompted using backspace key. When the menu is active, all PlayerInput components are set to disabled, because I encountered an error when I tried to rebind the controls when the PlayerInput is enabled. The PlayerInputs are reenabled when closing.


    The issue:


    On Play mode, two players are instantiated. I notice that the InputActionAsset for both players are different, with Player2 having a cloned version of PlayerInputAction.

    Player1


    Player2


    Both player controls work normally at first. However, when I tried to rebind the controls, Player1 resumes accordingly with the new key binding, but Player2 remained with its default binding unchanged, although the rebinding UI shows the new key binding.

    From the issue, I came to a conclusion that I am overriding the key binding for the original PlayerInputAction, which does not seem to reflect the cloned version in Player2.

    Player2 begins to follow the new binding when I manually drag the original PlayerInputAction from the Project directory into the PlayerInput.actions and restore the component (disabling and enabling back). I would want this process to be procedural in code.

    I have tried using GameObject version of Instantiate, but the problem still persists.

    Perhaps there is a solution or an issue to be resolved? Any help is appreciated.
     
  2. wechat_os_Qy02K9MOEtMfDUI6jgdW0MAoY

    wechat_os_Qy02K9MOEtMfDUI6jgdW0MAoY

    Joined:
    Oct 8, 2022
    Posts:
    1
    I get the same problem today, did you find any solution to the problems?
     
    brunoliveiraaraujo likes this.
  3. brunoliveiraaraujo

    brunoliveiraaraujo

    Joined:
    Dec 10, 2019
    Posts:
    3
    I also stumbled upon a similar issue today, and eventually I've came up with a solution!

    Basically you have an InputActionAsset that gets rebinded, but when you create new PlayerInputs it doesn't use the rebinded keys. So you need to copy the overriden bindings from the original InputActionAsset into the PlayerInput's. Below is a way to do it:

    Code (CSharp):
    1.  
    2. private void CopyOverridenBindings(InputActionMap copyActionMap, InputActionMap originalActionMap)
    3.     {
    4.         for (int i = 0; i < copyActionMap.actions.Count; i++)
    5.         {
    6.             var copyAction = copyActionMap.actions[i];
    7.             var originalAction = originalActionMap.actions[i];
    8.             for (int j = 0; j < copyAction.bindings.Count; j++)
    9.             {
    10.                 var originalBinding = originalAction.bindings[j];
    11.                 if (originalBinding.overridePath != null
    12.                     && originalBinding.overridePath != string.Empty)
    13.                 {
    14.                     copyAction.ChangeBinding(j).WithPath(originalBinding.overridePath);
    15.                 }
    16.             }
    17.         }
    18.     }
    You just have to feed the action maps from PlayerInput and the original InputActionAsset. In my case those are named "Gameplay".

    Code (CSharp):
    1.  
    2. CopyOverridenBindings(
    3.             playerInput.actions.FindActionMap("Gameplay"),
    4.             InputActions.asset.FindActionMap("Gameplay")
    5.         );