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

Question How do InputActionReferences work?

Discussion in 'Input System' started by PascalTheDog, Sep 14, 2021.

  1. PascalTheDog

    PascalTheDog

    Joined:
    Mar 16, 2015
    Posts:
    86
    Hey,

    So I'm trying to create a game dev architecture that's easy for non-programmers to use on their own. Right now, I'm working on inputs — with the new input system. The idea is that the designer should be able to choose what input is going to trigger a given interaction directly in the inspector. For instance, the Shooter class has two InputActionReference fields, one for the Shoot interaction and one for the Reload interaction; and just by clicking the field in the inspector, they can for instance set it to DefaultMap/MainAction and DefaultMap/SecondaryAction respectively.

    But I can't get it to work. No error or anything, the input simply does not register. What I used to do before was have an "InputManager" class with a static reference to the InputAction instance ("input"); then I would access that from other classes by writing say InputManager.input.DefaultMap.MainAction. It worked perfectly fine, but I don't like using manager-style classes because of coupling issues — plus, more importantly and as described above, I want something that doesn't rely on (re)writing code.

    Assistance would be greatly appreciated. Cheers!
     
  2. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    The pitfall here is actions getting duplicated and
    InputActionReference
    s then leading to
    InputAction
    s other than the ones you are actually interested in.

    The most common way to run into this is with the "Generate C# Class" option. One thing this particular path doesn't make clear is that it creates a completely self-contained class with no connection to the asset anymore. So if there's
    InputActionReference
    s, *they* will reference the actions in the .inputactions file whereas the C# class generated from it will have its own InputActions disconnected from those.

    This is a quirk with how the current code generation works and needs to get fixed properly. The same problem here is also apparent when using the rebinding UI from the sample together with "Generate C# Class". Overall, the current code generator has a number of shortcomings.

    Another case where this happens is with multiple
    PlayerInput
    s. Here, the first player will use the given actions as is but any additional player will duplicate them and have its own set. Again leading to
    InputActionReference
    s not going to those actions.

    ATM, in these cases where the set of actions used at runtime can differ from those on stored on disk, the actions need to be looked up manually. For example:

    Code (CSharp):
    1. public InputActionReference fire;
    2.  
    3. private InputAction fireAction;
    4.  
    5. void OnEnable()
    6. {
    7.     // Grab actions from player.
    8.     var player = GetComponent<PlayerInput>();
    9.     fireAction = player.actions[fire.action.id];
    10. }
    Not very elegant ATM.
     
    Oneiros90 likes this.
  3. PascalTheDog

    PascalTheDog

    Joined:
    Mar 16, 2015
    Posts:
    86
    Thank you for your detailed response! Though I'll be honest with you, there's all a lot in there I don't quite understand. What does the "PlayerInput" in the code refer to?

    Edit: I didn't realize PlayerInput was an actual component; that's just how I called my InputAction asset. That being said, the following code throws an error:

    GetComponent<PlayerInput>().actions[interact.action.id];

    Cannot convert type 'System.Guid' to 'int'
     
    Last edited: Sep 15, 2021
  4. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Ah, sorry, my bad.

    Code (CSharp):
    1. GetComponent<PlayerInput>().actions[interact.action.id.ToString()];
    2.  
    3. // Or simply.
    4. GetComponent<PlayerInput>().actions[interact.action.name];
     
  5. PascalTheDog

    PascalTheDog

    Joined:
    Mar 16, 2015
    Posts:
    86
    Thank you! That fixes the error. I'm afraid this doesn't help with the input not registering, however... No error, no warning, no nothing.

    Those are my two variables...
    [SerializeField] InputActionReference interact;
    private InputAction _interact;


    This is my OnEnable...
    _interact = GetComponent<PlayerInput>().actions[interact.action.name];


    And finally the actual call, in Start.
    _interact.performed += ctx => DoInteract();


    Am I missing something?