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

[Solved]Creating a similar input to Input.GetKeyDown

Discussion in 'Input System' started by AnimatorOfTheYear, Apr 8, 2020.

  1. AnimatorOfTheYear

    AnimatorOfTheYear

    Joined:
    May 24, 2015
    Posts:
    8
    Hello, i am relatively new to Unity's new Input System as it is my 3rd time using this system. I have been trying to rack my head around getting a specific type of input down for a game that i am working on but i cant get it to work.

    The input i desire is similar to Input.GetKeyDown, where the input only sets itself true upon pressing a button once. I have searched around the internet for some reference with no luck.

    I have tried using the context.started boolean but that does nothing.
    I have also tried using the Interactions menu in the InputMenu which also does nothing.

    Does anyone have any good implementations or ideas as to how to get about creating this behaivour?
     
  2. Fenrisul

    Fenrisul

    Joined:
    Jan 2, 2010
    Posts:
    618
    You have some choices!

    If you truly just want Keys, rather than actions:

    Keyboard.current[KeyCode.Space].wasPressedThisFrame

    Is one :)
     
    hms0589, john79, normed and 5 others like this.
  3. AnimatorOfTheYear

    AnimatorOfTheYear

    Joined:
    May 24, 2015
    Posts:
    8
    Oh, didn't know it was an option. Maybe i will use this in the future.
    However, I am using a Input Actions asset for most of my inputs since it helps my colleagues with setting inputs without any hassle.
     
  4. AnimatorOfTheYear

    AnimatorOfTheYear

    Joined:
    May 24, 2015
    Posts:
    8
    I have read through that documentation actually. I have tried most of the methods and variables that lie with the examples and explanations. The primary ones that i have tried is assigning a method specifically to a desired state (such as having input that happen at the start of the frame being called at Action.started), as well as manually checking the state of the current input using the CallbackContext.phase to see in which exact phase the current input is in. Neither of these methods work at all (Action.started gets called constantly and the CallbackContext.phase sometimes never reaches certain states such as Started or Cancelled).

    I may have implemented both methods wrong though (and i sure hope that it is indeed the case) but as of this moment, i cant think of anything that can work.

    Below is the current implementation of what i have written. It is a seperate class that handles and extends from the PlayerControls InputActions class. For the sake of testing our game, i decided to include Unity's old input and swap between the two inputs using a boolean.

    The GameHandler.CoreManager contains eventListeners that allows this class to use Unity's Update, OnEnable and OnDisable methods. They have worked so far with no problems.

    Code (CSharp):
    1. public class InputManager
    2.     {
    3.         PlayerControls controls;
    4.  
    5.         //Singleton pattern.
    6.         static InputManager ins;
    7.         public static InputManager Player
    8.         {
    9.             get
    10.             {
    11.                 if (ins == null)
    12.                 {
    13.                     ins = new InputManager();
    14.                     GameHandler.CoreManager.OnEnableListener += ins.OnEnable;
    15.                     GameHandler.CoreManager.OnDisableListener += ins.OnDisable;
    16.                     GameHandler.CoreManager.OnUpdateListener += ins.Update;
    17.  
    18.                 }
    19.                 return ins;
    20.             }
    21.         }
    22.  
    23.         //Input setup.
    24.         public InputManager()
    25.         {
    26.             useOldInput = true;
    27.             controls = new PlayerControls();
    28.             AddListenersToInput();
    29.             controls.Player.Enable();
    30.         }
    31.  
    32.         private void AddListenersToInput()
    33.         {
    34.             controls.Player.Interact.started += ctx => { Interact = ctx.ReadValue<float>() == 1 && !pauseInput; };
    35.             controls.Player.Interact.canceled += ctx => { Interact = ctx.ReadValue<float>() == 1 && !pauseInput; };
    36.             controls.Player.Movement.canceled += ctx => { Movement = (!pauseInput) ? ctx.ReadValue<Vector2>() : Vector2.zero; };
    37.             controls.Player.Movement.performed += ctx => { Movement = (!pauseInput) ? ctx.ReadValue<Vector2>() : Vector2.zero; };
    38.             controls.Player.Jump.performed += ctx => { Jump = ctx.ReadValue<float>() == 1 && !pauseInput; };
    39.             controls.Player.Attack.started += ctx => { Attack = ctx.ReadValue<float>() == 1 && !pauseInput; };
    40.             controls.Player.Ingame.started += ctx => { IngameMenu = ctx.ReadValue<float>() == 1 && !pauseInput; };
    41.         }
    42.  
    43.         private void RemoveListenersFromInput()
    44.         {
    45.             controls.Player.Interact.started -= ctx => { Interact = ctx.ReadValue<float>() == 1 && !pauseInput; };
    46.             controls.Player.Interact.canceled -= ctx => { Interact = ctx.ReadValue<float>() == 1 && !pauseInput; };
    47.             controls.Player.Movement.canceled -= ctx => { Movement = (!pauseInput) ? ctx.ReadValue<Vector2>() : Vector2.zero; };
    48.             controls.Player.Movement.performed -= ctx => { Movement = (!pauseInput) ? ctx.ReadValue<Vector2>() : Vector2.zero; };
    49.             controls.Player.Jump.performed -= ctx => { Jump = ctx.ReadValue<float>() == 1 && !pauseInput; };
    50.             controls.Player.Attack.started -= ctx => { Attack = ctx.ReadValue<float>() == 1 && !pauseInput; };
    51.             controls.Player.Ingame.started -= ctx => { IngameMenu = ctx.ReadValue<float>() == 1 && !pauseInput; };
    52.         }
    53.  
    54.         private void Update()
    55.         {
    56.             if (useOldInput && !pauseInput)
    57.             {
    58.  
    59.                 Interact = Input.GetKeyDown(KeyCode.E) && !Attack;
    60.                 Movement = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
    61.                 Jump = Input.GetKeyDown(KeyCode.Space);
    62.                 Attack = Input.GetKey(KeyCode.Mouse1) && !Interact;
    63.                 IngameMenu = Input.GetKeyDown(KeyCode.Escape);
    64.  
    65.  
    66.             }
    67.  
    68.  
    69.         }
    70.  
    71.         private void OnDisable()
    72.         {
    73.             RemoveListenersFromInput();
    74.             controls.Player.Disable();
    75.         }
    76.  
    77.         private void OnEnable()
    78.         {
    79.             AddListenersToInput();
    80.             controls.Player.Enable();
    81.         }
    82.  
    83.  
    84.  
    85.         public bool useOldInput;
    86.  
    87.  
    88.         public bool pauseInput = false;
    89.  
    90.  
    91.  
    92.  
    93.  
    94.  
    95.  
    96.         InputAction.CallbackContext interactContext;
    97.  
    98.         #region Properties
    99.         public bool Attack { private set; get; }
    100.         public bool Interact { private set; get; }
    101.  
    102.         //public InteractStruct Interact;
    103.         public bool Jump { private set; get; }
    104.  
    105.  
    106.         public Vector2 Movement { get; private set; }
    107.         public bool IngameMenu { get; private set; }
    108.         #endregion
    109.  
    110.  
    111.  
    112.  
    113.     }
    Here is how the PlayerControls InputActions asset looks like:


     
  5. You said you need an input where the action happens once on a keypress. Like jumping when you hit the spacebar or something. You need the performed action for that.

    Also read up and make sure you set up the Interactions properly in case you need something different (press the "E" button for 2 seconds for interact-style controls)
     
  6. AnimatorOfTheYear

    AnimatorOfTheYear

    Joined:
    May 24, 2015
    Posts:
    8
    I have tried a performed action for that and it still kept being called every frame instead of just being called upon using the input. Taking Interact by example:
    controls.Player.Interact.started+= ctx => { Interact = ctx.ReadValue<float>() == 1 && !pauseInput; };

    controls.Player.Interact.performed+= ctx => { Interact = ctx.ReadValue<float>() == 1 && !pauseInput; 

    both of these lines behaive the same.

    Furthermore, if i use the CallbackContext states like this:
    controls.Player.Interact.performed+= ctx => { Interact = ctx.started && !pauseInput; };

    the same behaivour still presists, where the input keeps getting called at all times instead of just once at the start.

    I have read about the Interactions property and i still find it very confusing in terms of setting up the settings to get a desired result. Maybe you or other people know a specific setting(s) that allow one to make an input trigger once instead of every frame.
     
  7. I'm not sure about your setup, I found your class a bit confusing at first sight, but maybe because it's just strange for me doing things like this. :)
    But I guess, you only(!) need this for the interaction:
    Code (CSharp):
    1. controls.Player.Interact.performed+= ctx => { Interact = !pauseInput; };
    And then wherever you're actually perform the interaction you can set the Interact bool to false. You have made an assumption which is not true, naming that you assumed that the performed action is called every frame, but this is not the case. The performed is called ONCE per action (hit the spacebar, one performed call in the very next frame). Your problem is that your Interact boolean stays true after that. I think.
     
    heerok7 likes this.
  8. AnimatorOfTheYear

    AnimatorOfTheYear

    Joined:
    May 24, 2015
    Posts:
    8
    Yea, now that i look at it, it might have been the case. I will give it a try and come back to you to see if anything changed.
     
  9. AnimatorOfTheYear

    AnimatorOfTheYear

    Joined:
    May 24, 2015
    Posts:
    8
    Just tested a very crude implementation of your suggestion, i can say with confidence that it works.

    Here is how i did it:

    I set my Interact input to set my Interact to true (or !pauseInput, thanks for that catch) like so:
    Code (CSharp):
    1.  controls.Player.Interact.performed += ctx => { Interact = !pauseInput; };
    ¨

    Then in the Update Method, rigth after the check to use the oldInput, i set the Interact input to false, like so:
    Code (CSharp):
    1. private void Update()
    2.         {
    3.             if (useOldInput && !pauseInput)
    4.             {
    5.  
    6.                 Interact = Input.GetKeyDown(KeyCode.E) && !Attack;
    7.                 Movement = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
    8.                 Jump = Input.GetKeyDown(KeyCode.Space);
    9.                 Attack = Input.GetKey(KeyCode.Mouse1) && !Interact;
    10.                 IngameMenu = Input.GetKeyDown(KeyCode.Escape);
    11.  
    12.  
    13.             }
    14.  
    15.             Interact = false;
    16.         }
     
  10. heerok7

    heerok7

    Joined:
    May 26, 2015
    Posts:
    15
    Sorry to re-surface this after sometime. I came to this conclusion a while ago, is there a better way to this than to set the bool to false?
     
  11. phillipesq

    phillipesq

    Joined:
    Sep 5, 2022
    Posts:
    2
    Very sad, they made a new inputsystem that doesn't have anything similar to Keydown.
    Aren't updates supposed to make programmers' lives better?
     
    jacob77898 and KeParsons12 like this.
  12. phillipesq

    phillipesq

    Joined:
    Sep 5, 2022
    Posts:
    2
    My Sugestion:


    Code (CSharp):
    1.     public void InputSystemActionESC(InputAction.CallbackContext btn)
    2.     {
    3.         if (btn.started)    //detect started action, like old keydown.
    4.         {
    5.             ActionESC = !ActionESC; //trigger my bool when keydown
    6.         }
    7.     }