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.

Resolved How to know if 1D axis binds are being pressed.

Discussion in 'Input System' started by Phoenix248, Nov 3, 2022.

  1. Phoenix248

    Phoenix248

    Joined:
    Sep 20, 2019
    Posts:
    48
    Hi everyone!

    I have a 1D axis type action, with positive and negative buttons, and I need to know if they are being pressed in the current frame. The problem is that when I press both sides at the same time, it returns 0. So pressing both and pressing none results in the same thing. How could I tell them apart?
     
  2. andrew_oc

    andrew_oc

    Unity Technologies

    Joined:
    Apr 16, 2021
    Posts:
    77
    This probably isn't as easy to do as it should be but one way would be to create a custom axis composite that contains extra information, namely whether any keys of the composite are currently actuated. Here's a working example:

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using UnityEngine.InputSystem;
    4. using UnityEngine.InputSystem.Composites;
    5. using UnityEngine.InputSystem.Layouts;
    6. using UnityEngine.InputSystem.Processors;
    7.  
    8. public struct CustomAxisValue
    9. {
    10.     public float absoluteValue;
    11.     public bool isAnyControlActuated;
    12. }
    13.  
    14. #if UNITY_EDITOR
    15. [InitializeOnLoad]
    16. #endif
    17. public class CustomAxisComposite : InputBindingComposite<CustomAxisValue>
    18. {
    19. #if UNITY_EDITOR
    20.     static CustomAxisComposite()
    21.     {
    22.         Initialize();
    23.     }
    24.  
    25. #endif
    26.  
    27.     [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    28.     private static void Initialize()
    29.     {
    30.         InputSystem.RegisterBindingComposite<CustomAxisComposite>();
    31.     }
    32.  
    33.     [InputControl(layout = "Axis")] public int negative = 0;
    34.     [InputControl(layout = "Axis")] public int positive = 0;
    35.  
    36.     public float minValue = -1;
    37.     public float maxValue = 1;
    38.  
    39.     public AxisComposite.WhichSideWins whichSideWins = AxisComposite.WhichSideWins.Neither;
    40.  
    41.     public float midPoint => (maxValue + minValue) / 2;
    42.  
    43.     public override CustomAxisValue ReadValue(ref InputBindingCompositeContext context)
    44.     {
    45.         var negativeValue = Mathf.Abs(context.ReadValue<float>(negative));
    46.         var positiveValue = Mathf.Abs(context.ReadValue<float>(positive));
    47.  
    48.         var negativeIsActuated = negativeValue > Mathf.Epsilon;
    49.         var positiveIsActuated = positiveValue > Mathf.Epsilon;
    50.  
    51.         if (negativeIsActuated == positiveIsActuated)
    52.         {
    53.             switch (whichSideWins)
    54.             {
    55.                 case AxisComposite.WhichSideWins.Negative:
    56.                     positiveIsActuated = false;
    57.                     break;
    58.  
    59.                 case AxisComposite.WhichSideWins.Positive:
    60.                     negativeIsActuated = false;
    61.                     break;
    62.  
    63.                 case AxisComposite.WhichSideWins.Neither:
    64.                     return new CustomAxisValue
    65.                     {
    66.                         absoluteValue = midPoint,
    67.                         isAnyControlActuated = negativeIsActuated
    68.                     };
    69.             }
    70.         }
    71.  
    72.         var mid = midPoint;
    73.  
    74.         if (negativeIsActuated)
    75.             return new CustomAxisValue
    76.             {
    77.                 absoluteValue = mid - (mid - minValue) * negativeValue,
    78.                 isAnyControlActuated = true
    79.             };
    80.  
    81.         return new CustomAxisValue
    82.         {
    83.             absoluteValue = mid + (maxValue - mid) * positiveValue,
    84.             isAnyControlActuated = true
    85.         };
    86.     }
    87.  
    88.     public override float EvaluateMagnitude(ref InputBindingCompositeContext context)
    89.     {
    90.         var customAxisValue = ReadValue(ref context);
    91.  
    92.         // if both axes are currently actuated, the absolute value will be zero, but if we return zero from EvaluateMagnitude
    93.         // the system will mark the action as not in progress and subsequent calls to InputAction.ReadValue<> won't return
    94.         // the value we want, so just return a tiny value here to fool the system.
    95.         if (customAxisValue.isAnyControlActuated && customAxisValue.absoluteValue == 0)
    96.             return float.Epsilon;
    97.  
    98.         var value = customAxisValue.absoluteValue;
    99.         if (value < midPoint)
    100.         {
    101.             value = Mathf.Abs(value - midPoint);
    102.             return NormalizeProcessor.Normalize(value, 0, Mathf.Abs(minValue), 0);
    103.         }
    104.  
    105.         value = Mathf.Abs(value - midPoint);
    106.         return NormalizeProcessor.Normalize(value, 0, Mathf.Abs(maxValue), 0);
    107.     }
    108. }
    Then when reading the value, you can check if the isAnyControlActuated property is true, like this:

    Code (CSharp):
    1. var value = m_Action.ReadValue<CustomAxisValue>();
    2.         Debug.Log("Is any control actuated = " + value.isAnyControlActuated + ", value = " + value.absoluteValue);
     
  3. Phoenix248

    Phoenix248

    Joined:
    Sep 20, 2019
    Posts:
    48
    Working perfectly, thanks! Would be nice to have this built in in the future.