How to cleanly remove InputAction callbacks?

Viewed 294

I have a class which is responsible for setting up and tearing down callbacks to InputAction events (from Unity's Input System package). The relevant code looks like this:

private void SetupCallbacks(InputActionMap map)
{
    InputAction action = map.FindAction("Action", true);
    action.performed += ActionPerformed;
    action.canceled += ActionCanceled;
}

private void TeardownCallbacks(InputActionMap map)
{
    InputAction action = map.FindAction("Action", true);
    action.performed -= ActionPerformed;
    action.canceled -= ActionCanceled;
}

Clearly, there is a lot of duplication here and the code very nearly does the same thing. This looks like a breeding ground for bugs, especially as the number of actions increases. I'm hoping someone on here knows a cleaner solution. Please share your thoughts!

1 Answers

Unity generates a public method in the auto-generated class file called SetCallbacks() which subscribes/unsubscribes (deallocates memory) all Actions and phases in the ActionMap provided via a public Interface. It's covered in this video. So doing something like (using my SlideController from a a cut scene):

public class SlideController : MonoBehaviour, InputControls.ISlidesActions
{
  InputControls inputControls;
  void Awake()
  {
    // new instance of input system controls
    inputControls = new InputControls();
    // *** subscribes ALL events ***
    inputControls.ISlidesActions.SetCallbacks(this);    
  }

  // enable / disable action maps for this class
  void OnEnable()
  {
    inputControls.ISlidesActions.Enable();
  }
  void OnDisable()
  {
    inputControls.ISlidesActions.Disable();
  }

  // callbacks => game logic
  public void OnNextSlide(InputAction.CallbackContext context)
  {
    DisplayNextSlide(); 
  }
  public void OnPreviousSlide(InputAction.CallbackContext context)
  {
    DisplayPreviousSlide();

    // you have access to the phase here
    if (context.started) Debug.Log("Event started");     
    else if (context.performed) Debug.Log("Event performed");
    else if (context.canceled) Debug.Log("Event canceled");
  }
  // -> ect.
}

In that video, he enables/disables the entire Input Asset, but I think its better to enable/disable only the map you need for a class.

Related