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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Make a single-press-based axis

Discussion in 'Input System' started by PascalTheDog, Jan 30, 2021.

  1. PascalTheDog

    PascalTheDog

    Joined:
    Mar 16, 2015
    Posts:
    83
    Hey,

    Is there any way to make a single-press-based axis using the new input system? What I mean by that is an axis which only returns a value different from zero on the frame it is pressed, similarly to a GetButtonDown — unlike a typical axis which returns the value as long as it is held down, similarly to a GetButton.

    Using the old input system, I would typically achieve this through code — but I thought maybe the new input system is capable of handling this on its own. This would come in handy for stuff like menu navigation.

    Cheers.
     
  2. VideoVillain

    VideoVillain

    Joined:
    Oct 12, 2020
    Posts:
    6
    I don't know the new system all that well, but right-clicking on an action to add a binding gives you the option to choose 1D Axis Composite. Would that do what you are looking for?
     
  3. PascalTheDog

    PascalTheDog

    Joined:
    Mar 16, 2015
    Posts:
    83
    Thank you for your input. That's what I tried doing first, and that would have made sense — but it didn't work the way I intended. Messing around with Interactions didn't help. It would behave as a regular axis would, no matter what.

    What I do now is the following: first associate a method with the axis in Awake and only then read the value from the input in said method, kinda forcing it to be single-press-based. Something like:

    Code (CSharp):
    1. private void Awake() => playerIput.Controls.Whatever.performed += PerformRelevantAction();
    2.  
    3. private void PerformRelevantAction()
    4. {
    5.      playerInput.Controls.Whatever.performed += ctx => value = ctx.ReadValue<float>();
    6.  
    7.      index += value;
    8. }
    It kind of works, but with weird results. When I first press my axis, it doesn't seem to work at all — but then a second press and my index does change properly. Then, even weirder, there's the fact that if I press the other side of the axis, it continues to behave as if it were the previous side, but only on the first press. I'm a bit puzzled as to why that should be the case.
     
  4. VideoVillain

    VideoVillain

    Joined:
    Oct 12, 2020
    Posts:
    6
    I am really not the best at this stuff and have never used an axis, but I'm almost certain you wan to do something like:

    Code (CSharp):
    1. public void Awake() {
    2.     // get the reference
    3.     playerInput = new PlayerInput(); //or whatever you called your generated class
    4. }
    5.  
    6. private void OnEnable() {
    7.     playerInput.Enable();
    8. }
    9.  
    10. private void OnDisable() {
    11.     playerInput.Disable();
    12. }
    13.  
    14. private void Start() {
    15.     // subscribe to the control action and provide the context
    16.     playerInput.Controls.Whatever.performed += _context => PerformedRelevantAction(_context);
    17. }
    18.  
    19. private void PerformedRelevantAction(InputAction.CallbackContext _context) {
    20.     // do what you want performed here
    21.     index += _context.ReadValue<float>();
    22. }
    Because looking at how you have it, the first time PerformRelevantAction() is called, its inner code still hasn't subscribed to anything yet, so the first time you run it is when you finally subscribe while providing context and get the value, but it also re-subscribes each time, so the next time it is called, it finally grabs a value, but subscribes again.

    But not only that, you are double subscribed to playerInput.Controls.Whatever.performed... once to simply call a function, and again to subscribe yet again and this time provide a context and get a value.

    Your first event trigger will never give the right value, and all the other triggers, will resub and possibly try to increase the index a growing amount of times.
     
    PascalTheDog likes this.
  5. PascalTheDog

    PascalTheDog

    Joined:
    Mar 16, 2015
    Posts:
    83
    Oooh, I get it now. It works fine using your approach. Thanks!