Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct here to familiarize yourself with the rules and how to post constructively.

  2. Unity 2022.1 is now available as the latest Tech release.
    Dismiss Notice
  3. Improve your project's performance with our new guide on profiling in Unity.
    Dismiss Notice

How would you handle a GetButtonDown Situaiton with the New Input System?

Discussion in 'Input System' started by WizByteGames, Feb 10, 2019.

  1. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    8,655
    Have you set the InputSystem's UpdateMode to Fixed Update as per the documentation?
    https://docs.unity3d.com/Packages/com.unity.inputsystem@1.1/manual/Settings.html#update-mode
     
  2. diliupg

    diliupg

    Joined:
    Jan 23, 2018
    Posts:
    43
    The code below worked for me to set up a crouch toggle using the new Input system. Works like a charm. Unity 2020.3.2f1 LTS
    Code (CSharp):
    1. private void HandleCrouchingInput()
    2.     {
    3.         if ( playerControls.PlayerActions.Crouch.triggered )
    4.         {
    5.             if(!isCrouched)
    6.             {            
    7.                 isCrouched = true;
    8.                 sign = 1;
    9.                 layerWeight = 0;
    10.             }
    11.             else
    12.             {              
    13.                 isCrouched = false;
    14.                 sign = -1;
    15.                 layerWeight = 1;
    16.             }
    17.  
    18.             StartCoroutine ( ToggleCrouch ( ) );
    19.         }
    20.     }
    21.  
    22.     IEnumerator ToggleCrouch ( )
    23.     {
    24.         if(isCrouched)
    25.         {
    26.             while(layerWeight <= 1 )
    27.             {
    28.                 layerWeight += Time.deltaTime * sign * 6;
    29.                 animator.SetLayerWeight ( 1, layerWeight );
    30.                 yield return null;
    31.             }
    32.         }
    33.         else
    34.         {
    35.             while(layerWeight >= 0)
    36.             {
    37.                 layerWeight += Time.deltaTime * sign * 6;
    38.                 animator.SetLayerWeight ( 1, layerWeight );
    39.                 yield return null;
    40.             }
    41.         }
    42.     }
     
    Last edited: Apr 2, 2021
  3. stevphie123

    stevphie123

    Joined:
    Mar 24, 2021
    Posts:
    23
    Shake my head, honestly..for something that used to be a simple task now looks like a hella bloats of a mess
     
  4. a-t-hellboy

    a-t-hellboy

    Joined:
    Dec 6, 2013
    Posts:
    170
    Hey Rene-Damm,

    I use C# Generated Class and inherits from the interface which inputs callbacks are there.
    For instance:
    Code (CSharp):
    1.  
    2. KeyboardInput: IPlayerControls
    3. {
    4.      public void OnJump(InputAction.CallbackContext context)
    5.      {
    6.         jump = context.ReadValueAsButton() && context.started;
    7.      }
    8. }
    As you can see I use context.started as a replacement for `GetButtonDown` but the problem is, it doesn't work. As I noticed it is because started and performed are done in a single frame so that jump variable is always false.
    Is it a bug or I miss something here ?
     
  5. parellquest

    parellquest

    Joined:
    Nov 18, 2020
    Posts:
    1
    Hey for anyone in 2021 trying to deal with UI and it flickers with clicking
    Dont do this. flickers hard

    controls.Gameplay.Jump.performed += i => playerMovement.isJumping = true;
    controls.Gameplay.Jump.canceled += i => playerMovement.isJumping = false;


    Just set this on a void easy and no more flickering UI

    if (controls.UI.Menu.WasPressedThisFrame() && !playerCanvas.isMenuPressed)
    {
    playerCanvas.isMenuPressed = true;
    }
    else
    {
    playerCanvas.isMenuPressed = false;
    }
     
  6. Rickmc3280

    Rickmc3280

    Joined:
    Jun 28, 2014
    Posts:
    170
    I have:

    InputActions:
    PrimaryPress,
    Primary Release,
    PrimaryHeld,
    PrimaryDoubleClick,
    PrimaryTripleClick.

    I have set all of their interactions as:
    Press:press,
    Press:Release,
    Hold,
    Tap2,
    Tap3.

    They work...

    However, it fires all of the events. Is there a way to prevent firing until it has determined if it is one of the 5 options? So that essentially, it only fires the relevant event? In my old system I handled this... but I dont want to attach events to events, seems counter productive.
     
  7. DavidSof

    DavidSof

    Joined:
    Sep 1, 2015
    Posts:
    6
    It's very sad for unity that something that can be one line of code in old system must now be a bunch of complicated code !! , the new generation as usual trying to take their place in system , by replace the oldest -"heavy duty code" , instead of repair it , this is the place for competitors.
     
  8. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,885
    For those who are still struggling with this, and since this is the first google search result I got when searching for this, here's how I solved it:

    Code (CSharp):
    1. public struct PlayerInput
    2. {
    3.     public float2 Move;
    4.     public float2 Look;
    5.     public float Scroll;
    6.     public bool JumpDown;
    7.     public bool JumpUp;
    8.     public bool AimDown;
    9.     public bool AimUp;
    10.     public bool ShootDown;
    11.     public bool ShootUp;
    12. }
    13.  
    14. public class GameInputManager : MonoBehaviour
    15. {
    16.     public PlayerInput PlayerInput;
    17.     public GameInputActions InputActions;
    18.  
    19.     protected void Start()
    20.     {
    21.         InputActions = new GameInputActions();
    22.         InputActions.Enable();
    23.         InputActions.DefaultMap.Enable();
    24.     }
    25.  
    26.     protected void Update()
    27.     {
    28.         DefaultMapActions inputMap = InputActions.DefaultMap;
    29.  
    30.         PlayerInput = new PlayerInput
    31.         {
    32.             Move = Vector2.ClampMagnitude(inputMap.Move.ReadValue<Vector2>(), 1f),
    33.             Look = inputMap.Look.ReadValue<Vector2>(),
    34.             Scroll = inputMap.Scroll.ReadValue<float>(),
    35.             JumpDown = ButtonDown(inputMap.Jump),
    36.             JumpUp = ButtonUp(inputMap.Jump),
    37.             AimDown = ButtonDown(inputMap.Aim),
    38.             AimUp = ButtonUp(inputMap.Aim),
    39.             ShootDown = ButtonDown(inputMap.Shoot),
    40.             ShootUp = ButtonUp(inputMap.Shoot),
    41.         };
    42.     }
    43.  
    44.     public static bool ButtonDown(InputAction action)
    45.     {
    46.         return action.ReadValue<float>() > 0.5f && action.triggered;
    47.     }
    48.  
    49.     public static bool ButtonUp(InputAction action)
    50.     {
    51.         return action.ReadValue<float>() < 0.5f && action.triggered;
    52.     }
    53.  
    54.     public static bool ButtonHeld(InputAction action)
    55.     {
    56.         return action.ReadValue<float>() > 0.5f;
    57.     }
    58. }

    See more specifically the ButtonDown, ButtonUp, ButtonHeld utilities at the end.

    However, there is one very important thing you must set up in the input actions window:


    You need the ActionType to be "Button", and you need a "Press" interaction with a TriggerBehaviour set to "Press and Release"
     
    Last edited: Jun 6, 2021
  9. bitinn

    bitinn

    Joined:
    Aug 20, 2016
    Posts:
    949
    It is maybe a little bit ridiculously that the new input system has 5 ways to do the same thing, but the documentation consistently failed at pointing out the easiest solution.

    I challenge Unity documentation team to find this info on these manual page:

    https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Interactions.html
    https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/HowDoI.html
    https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Migration.html
    https://docs.unity3d.com/Packages/c....InputSystem.InputAction.CallbackContext.html

    Seriously, Unity team, have page out to explain some basic usage example of CallbackContext, so that your users are NOT using random snippet from the forum that may or may not be the best practices.

    Hundreds of users posting on forum "I don't know if this is good but it works for me" snippets are not a good look.
     
    Last edited: Jul 18, 2021
  10. maxwad

    maxwad

    Joined:
    Apr 15, 2021
    Posts:
    1
    My solution of problem "GetButtonDown" was like that:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class Controls : MonoBehaviour
    7. {
    8.     private NewInputActions inputs;
    9.  
    10.     public static float horizontal       = 0;
    11.     public static float vertical            = 0;
    12.     public static bool jump                = false;
    13.     public static bool fire                   = false;
    14.  
    15.     private void Awake()
    16.     {
    17.         inputs = new NewInputActions();
    18.  
    19.         inputs.Player.Axises.performed += context => horizontal = inputs.Player.Axises.ReadValue<Vector2>().x ;
    20.         inputs.Player.Axises.canceled += context => horizontal = 0;
    21.  
    22.         inputs.Player.Axises.performed += context => vertical = inputs.Player.Axises.ReadValue<Vector2>().y;
    23.         inputs.Player.Axises.canceled += context => vertical = 0;
    24.  
    25.         inputs.Player.Fire.performed += context => fire = true;
    26.         inputs.Player.Fire.canceled += context => fire = false;
    27.  
    28.         //in this case we have problems with emulating GetButtonDown function
    29.         //therefore we need another solution, for example, like in Update method
    30.         //
    31.         //inputs.Player.Jump.started += context => jump = true;
    32.         //inputs.Player.Jump.canceled += context => jump = false;
    33.  
    34.     }
    35.  
    36.     private void Update()
    37.     {
    38.         jump = inputs.Player.Jump.triggered;
    39.         //debugging input
    40.         //Debug.Log("Jump" + inputs.Player.Jump.triggered);
    41.  
    42.     }
    43.  
    44.     private void OnEnable()
    45.     {
    46.         inputs.Enable();
    47.     }
    48.  
    49.     private void OnDisable()
    50.     {
    51.         inputs.Disable();
    52.     }
    53. }
    54.  
    Where the button should be held down ("Fire"), I used standard events. And where I need only one press ("Jump") is the trigger. I don't know if this is correct, but it works.
     
  11. jamie_xr

    jamie_xr

    Joined:
    Feb 28, 2020
    Posts:
    38
    I'm a little late to this party, but I just caught up.

    Quite frankly I'm baffled by the need for so much boiler plate for what was a simple. standard out of the box feature. Everyone in this thread has had to write something that converts the event based input into something you can poll for state. Each one is pretty similar, does this not tell us that this should be built-in to the library?

    Is this on the road map. If it's not then my feelings are that it definitely should be.
     
    florianBrn likes this.
  12. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,885
    I'm making assumptions here, but I think part of the reason why the new input system works this way is because it supports polling input at a different frequency than the Update() rate. (which was a highly requested feature back when we only had the old input system)

    Any built-in GetButtonDown()-style API would stop working as expected as soon as input is not set to be polled on Update(). It would be an API that only works "sometimes" when the right options are set, so it would arguably be bad API design. It could lead to lots headaches for both users & the inputsystem devs that need to provide support.

    The event-based input API guarantees that you won't need big refactors in your input code if you eventually decide to change the input polling rate, and it saves Unity from having to teach users about all the intricacies of an input system. Ideally when you design an API, you need to make sure there will be as few "things users just need to know" as possible. So the event-based input is a safer bet & a better practice to enforce for all parties involved

    The old input system didn't have this problem because it simply did not offer the possibility of supporting Update()-independant input polling. It's once again one of those situations where the Unity community is torn between "simple solution that has big limitations" and "complex solution that solves those limitations". Not saying it's impossible to do better, but I do understand why these decisions were made
     
    Last edited: Dec 1, 2021
  13. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    8,655
    There is API to poll built into the library.
     
  14. ILoveMyDada

    ILoveMyDada

    Joined:
    Apr 30, 2014
    Posts:
    5
    I haven’t implemented this yet but I’m pretty sure in order to emulate a GetKeyDown is to call every single callback. So if you were to check a jump bool for instance it would be like so:

    action.started += ctx => jump = true;
    action.performed += ctx => jump = false;
    action.canceled += ctx => jump = false;

    I think this should work because for a GetKeyDown for the new input system, performed is actually less similar to started and more similar to canceled in this particular case. Started initializes. Performed completes. Canceled cancels.
     
  15. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    8,655
    lightbug14 likes this.
unityunity