Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Input Action Callbacks

Discussion in 'Input System' started by orionburcham, Feb 4, 2017.

  1. orionburcham

    orionburcham

    Joined:
    Jan 31, 2010
    Posts:
    488
    Hi guys!

    I was wondering if the input team is still considering adding callbacks, or an event system, for input Actions. I like to work in an event-driven manner, and would prefer to avoid using update loops to check for action changes in my code.

    So for example, instead of doing this in a MonoBehaviour:

    Code (CSharp):
    1. void Update()
    2. {
    3.     if(m_MapInput.fire.isHeld)
    4.     {
    5.         // do fire logic
    6.     }
    7. }
    I would like to be able to do this, from anywhere:

    Code (CSharp):
    1. m_MapInput.fire.onDown += OnFireDown;
    2.  
    3. void OnFireDown(ButtonInputControl control)
    4. {
    5.     // do fire logic
    6. }
    This came up a loong time ago, and at the time you said it was on your radar, but it was too early to know anything. Any updates to know on this front? :)

    Thanks!
     
    Last edited: Feb 5, 2017
  2. orionburcham

    orionburcham

    Joined:
    Jan 31, 2010
    Posts:
    488
    Bumpity. Just wondering about this, as I plan some input code for my future work. Would appreciate any thoughts you guys could give. :)
     
  3. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Yes, we would like to add this.
    Now that the new system supports working with input in both Update and FixedUpdate, I think we would have to add separate callbacks for those. E.g. something like:

    .onWasJustPressedFixed
    .onWasJustPressedDynamic

    And you could subscribe to one or the other depending on whether you need input for things in Update (rendering) or for things in FixedUpdate (physics).
     
    orionburcham likes this.
  4. orionburcham

    orionburcham

    Joined:
    Jan 31, 2010
    Posts:
    488
    Thanks runevision, that's great to hear.

    Short followup question: What arguments would you imagine being passed into those listener callbacks? In my example, I used the control itself, thinking devs could check other details about the state of the action.

    GL working towards this summer. :)
     
    Last edited: Feb 9, 2017
  5. fabianzz

    fabianzz

    Joined:
    Nov 24, 2012
    Posts:
    39
    This feels messy. Couldn't you just make the delegate accept a bool parameter: "isFixed"?
    OR: Make it an enumerated switch where the action itself is configured, whether to call the events in the fixedupdate or update cycle.
     
  6. kru

    kru

    Joined:
    Jan 19, 2013
    Posts:
    452
    I'd prefer they remain separate events. I don't want to have my event handlers called unnecessarily only to be discarded half of the time at the outset.
     
  7. fabianzz

    fabianzz

    Joined:
    Nov 24, 2012
    Posts:
    39
    I get you, but there's more than one way to skin a cat. I was thinking something along these lines (this way, the switch or thrown away invokes you wanted to avoid is performed at compile time):
    Code (csharp):
    1.  
    2. public class InputEvent {
    3.     public delegate void DynamicCallback();
    4.     public delegate void FixedCallback(bool isFixed);
    5.     private DynamicCallback dynamicCallbacks;
    6.     private FixedCallback fixedCallbacks;
    7.     public static InputEvent operator +(InputEvent a, DynamicCallback d) {
    8.         a.dynamicCallbacks += d;
    9.         return a;
    10.     }
    11.     public static InputEvent operator +(InputEvent a, FixedCallback f) {
    12.         a.fixedCallbacks += f;
    13.         return a;
    14.     }
    15.     public static InputEvent operator -(InputEvent a, DynamicCallback d) {
    16.         a.dynamicCallbacks -= d;
    17.         return a;
    18.     }
    19.     public static InputEvent operator -(InputEvent a, FixedCallback f) {
    20.         a.fixedCallbacks -= f;
    21.         return a;
    22.     }
    23.     public void InvokeDynamic () {
    24.         dynamicCallbacks.Invoke ();
    25.     }
    26.  
    27.     public void InvokeFixed() {
    28.         fixedCallbacks.Invoke (true);
    29.     }
    30. }
    31.  
    I don't like the idea of having an unnecessary parameter being passed, but I'm just thinking from a readability standpoint the structure of on[event name][fixed / dynamic] is really unclear. It should end at [event name]. This way, the not-easy-on-the-eye part is completely abstracted from the user and also from the rest of the InputSystem code, the overhead is minimal since it's a wrapper class which in memory equates to basically nothing and only adds 1 invoke virtual call.

    If you wanted to remove the unnecessary parameter and change in delegate signature, you could just use the *= and /= operators (maybe one of the bitwise ones would be more appropriate) to signify that it's to be performed in FixedUpdate. These aren't used in multicast delegates usually so it could be an easier distinction with even less stack overhead. PoC:
    Code (csharp):
    1.  
    2. public class InputEvent {
    3.     public delegate void InputCallback();
    4.     private InputCallback dynamicCallbacks;
    5.     private InputCallback fixedCallbacks;
    6.     public static InputEvent operator +(InputEvent a, InputCallback d) {
    7.         a.dynamicCallbacks += d;
    8.         return a;
    9.     }
    10.     public static InputEvent operator *(InputEvent a, InputCallback f) {
    11.         a.fixedCallbacks += f;
    12.         return a;
    13.     }
    14.     public static InputEvent operator -(InputEvent a, InputCallback d) {
    15.         a.dynamicCallbacks -= d;
    16.         return a;
    17.     }
    18.     public static InputEvent operator /(InputEvent a, InputCallback f) {
    19.         a.fixedCallbacks -= f;
    20.         return a;
    21.     }
    22.     public void InvokeDynamic () {
    23.         dynamicCallbacks.Invoke ();
    24.     }
    25.  
    26.     public void InvokeFixed() {
    27.         fixedCallbacks.Invoke ();
    28.     }
    29. }
    30.  
    31.  
     
    Last edited: Mar 1, 2017
  8. RGV

    RGV

    Joined:
    Jan 25, 2016
    Posts:
    48
    Please consider this as soon as possible. =(