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

Feedback C# ActionMap code gen should include accessible enum or ID

Discussion in 'Input System' started by Snowdrama, Jan 28, 2021.

  1. Snowdrama

    Snowdrama

    Joined:
    May 10, 2014
    Posts:
    28
    I am using the player input along with Invoke C Sharp events. My current solution uses string names to compare against the action name.
    Code (CSharp):
    1.  
    2.     [SerializeField] PlayerInput playerInput;
    3.     void Awake()
    4.     {
    5.         if(playerInput == null)
    6.         {
    7.             playerInput = this.GetComponent<PlayerInput>();
    8.         }
    9.     }
    10.  
    11.     private void OnEnable()
    12.     {
    13.         playerInput.onActionTriggered += HandleAction;
    14.     }
    15.  
    16.     private void OnDisable()
    17.     {
    18.         playerInput.onActionTriggered -= HandleAction;
    19.     }
    20.  
    21.     private void HandleAction(InputAction.CallbackContext ctx)
    22.     {
    23.         switch(ctx.action.name)
    24.         {
    25.             case "MousePosition":
    26.                 MousePosition(ctx);
    27.                 break;
    28.             case "TouchPosition":
    29.                 TouchPosition(ctx);
    30.                 break;
    31.             case "MouseClick":
    32.                 MouseClick(ctx);
    33.                 break;
    34.             case "TouchPress":
    35.                 TouchPress(ctx);
    36.                 break;
    37.         }
    38.     }
    39.  
    What I'd ideally like is to use say the actions ID or something to compare against an enum with the action name. In my case the action map is called "GameControls"
    Code (CSharp):
    1.     private void HandleAction(InputAction.CallbackContext ctx)
    2.     {
    3.         switch(ctx.action.id)
    4.         {
    5.             case GameControls.MousePosition:
    6.                 MousePosition(ctx);
    7.                 break;
    8.             case GameControls.TouchPosition:
    9.                 TouchPosition(ctx);
    10.                 break;
    11.             case GameControls.MouseClick:
    12.                 MouseClick(ctx);
    13.                 break;
    14.             case GameControls.TouchPress:
    15.                 TouchPress(ctx);
    16.                 break;
    17.         }
    18.     }
    This way if I change the name of something in my action map I get an actual compile time error saying that "TouchPress doesn't exist" and doesn't silently compile and run even though TouchPress had it's name changed.

    If there's something already in place for this, I'd love to know! Thanks in advance for listening!
     
  2. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    10,073
    You can have that if you click on the InputActioinAsset and in the inspector you set to generate C# class. But then you need to use the actions through that class. But you could register to the actions' performed event directly, so you could tie those together properly instead of in this switch structure.

    Check out this example: https://docs.unity3d.com/Packages/c....html#auto-generating-script-code-for-actions
     
    Snowdrama likes this.
  3. Snowdrama

    Snowdrama

    Joined:
    May 10, 2014
    Posts:
    28
    This is how I have done it in the past, I am trying to avoid having to not use the PlayerInput component so I can continue to use PlayerInput for things like the link to the Input System UI Input Module so I can do UI Blocking. As well as being able to use PlayerInputManager. I guess then my request would change so that there would be a way to use SetCallbacks within the context of the PlayerInput component. Ideally I'd like to do something like:
    Code (CSharp):
    1.  
    2. //This doesn't work, this is hypothetical
    3. if (playerInput.actions is Controls)
    4. {
    5.     //somehow cast the playerInput.actions (A InputActionAsset type)
    6.     //into a Controls InputActionAsset
    7.     Controls controls = (Controls)playerInput.actions;
    8.     //so I can set the callbacks
    9.     controls.Mining.SetCallbacks(this);
    10. }
    Here's an example of some updated code that does the UI blocking using PlayerInput and Input System UI Input Module
    Code (CSharp):
    1.  
    2. private void HandleAction(InputAction.CallbackContext ctx)
    3. {
    4.     switch (ctx.action.name)
    5.     {
    6.         case "MousePosition":
    7.             //Update the position regardless of UI so cursors hover over UI stuff
    8.             MousePosition(ctx);
    9.             break;
    10.         case "TouchPosition":
    11.             //Update the position regardless of UI so cursors hover over UI stuff
    12.             TouchPosition(ctx);
    13.             break;
    14.         case "MouseClick":
    15.             //Check if the cursor is over a UI element
    16.             if (!playerInput.uiInputModule.IsPointerOverGameObject(0))
    17.             {
    18.                 //Click if there's no UI in the way
    19.                 MouseClick(ctx);
    20.             }
    21.             break;
    22.         case "TouchPress":
    23.             //Check if the cursor is over a UI element
    24.             if (!playerInput.uiInputModule.IsPointerOverGameObject(0))
    25.             {
    26.                 //Click if there's no UI in the way
    27.                 TouchPress(ctx);
    28.             }
    29.             break;
    30.     }
    31. }
    32.  
     
  4. Snowdrama

    Snowdrama

    Joined:
    May 10, 2014
    Posts:
    28
    I guess as a workaround since I can't cast the actions back into a controls asset, the workaround would be to create the asset myself, and then assign it.
    Code (CSharp):
    1.  
    2. void Awake()
    3. {
    4.     playerInput = this.GetComponent<PlayerInput>();
    5.     Controls controls = new Controls();
    6.     controls.Mining.SetCallbacks(this);
    7.     playerInput.actions = controls.asset;
    8. }
    Edit: this does work. Though I do still think I should be able to somehow cast the action map back into it's base type OR like I was saying earlier to be able to compare an action against an enum or something so we aren't doing string compares.
     
    Last edited: Jan 29, 2021