using System.ComponentModel;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.Processors;
using UnityEngine.InputSystem.Utilities;
namespace UnityEngine.InputSystem.Composites
{
///
/// A single axis value computed from one axis that pulls in the direction () and one
/// axis that pulls in the direction ().
///
///
/// The limits of the axis are determined by and .
/// By default, they are set to [-1..1]. The values can be set as parameters.
///
///
///
/// var action = new InputAction();
/// action.AddCompositeBinding("Axis(minValue=0,maxValue=2")
/// .With("Negative", "<Keyboard>/a")
/// .With("Positive", "<Keyboard>/d");
///
///
///
/// If both axes are actuated at the same time, the behavior depends on .
/// By default, neither side will win () and the result
/// will be 0 (or, more precisely, the midpoint between and ).
/// This can be customized to make the positive side win ()
/// or the negative one ().
///
/// This is useful, for example, in a driving game where break should cancel out accelerate.
/// By binding to the break control(s) and to the
/// acceleration control(s), and setting to ,
/// if the break button is pressed, it will always cause the acceleration button to be ignored.
///
/// The actual absolute values of and are used
/// to scale and respectively. So if, for example,
/// is bound to and the trigger is at a value of 0.5, then the resulting
/// value is maxValue * 0.5 (the actual formula is midPoint + (maxValue - midPoint) * positive).
///
[DisplayStringFormat("{negative}/{positive}")]
[DisplayName("Positive/Negative Binding")]
public class AxisComposite : InputBindingComposite
{
///
/// Binding for the axis input that controls the negative [..0] direction of the
/// combined axis.
///
///
/// This property is automatically assigned by the input system.
///
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
[InputControl(layout = "Axis")] public int negative = 0;
///
/// Binding for the axis input that controls the positive [0..] direction of the
/// combined axis.
///
///
/// This property is automatically assigned by the input system.
///
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
[InputControl(layout = "Axis")] public int positive = 0;
///
/// The lower bound that the axis is limited to. -1 by default.
///
///
/// This value corresponds to the full actuation of the control(s) bound to .
///
///
///
/// var action = new InputAction();
/// action.AddCompositeBinding("Axis(minValue=0,maxValue=2")
/// .With("Negative", "<Keyboard>/a")
/// .With("Positive", "<Keyboard>/d");
///
///
///
///
///
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
[Tooltip("Value to return when the negative side is fully actuated.")]
public float minValue = -1;
///
/// The upper bound that the axis is limited to. 1 by default.
///
///
/// This value corresponds to the full actuation of the control(s) bound to .
///
///
///
/// var action = new InputAction();
/// action.AddCompositeBinding("Axis(minValue=0,maxValue=2")
/// .With("Negative", "<Keyboard>/a")
/// .With("Positive", "<Keyboard>/d");
///
///
///
///
///
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
[Tooltip("Value to return when the positive side is fully actuated.")]
public float maxValue = 1;
///
/// If both the and button are actuated, this
/// determines which value is returned from the composite.
///
[Tooltip("If both the positive and negative side are actuated, decides what value to return. 'Neither' (default) means that " +
"the resulting value is the midpoint between min and max. 'Positive' means that max will be returned. 'Negative' means that " +
"min will be returned.")]
public WhichSideWins whichSideWins = WhichSideWins.Neither;
///
/// The value that is returned if the composite is in a neutral position, that is, if
/// neither nor are actuated or if
/// is set to and
/// both and are actuated.
///
public float midPoint => (maxValue + minValue) / 2;
////TODO: add parameters to control ramp up&down
///
public override float ReadValue(ref InputBindingCompositeContext context)
{
var negativeValue = Mathf.Abs(context.ReadValue(negative));
var positiveValue = Mathf.Abs(context.ReadValue(positive));
var negativeIsActuated = negativeValue > Mathf.Epsilon;
var positiveIsActuated = positiveValue > Mathf.Epsilon;
if (negativeIsActuated == positiveIsActuated)
{
switch (whichSideWins)
{
case WhichSideWins.Negative:
positiveIsActuated = false;
break;
case WhichSideWins.Positive:
negativeIsActuated = false;
break;
case WhichSideWins.Neither:
return midPoint;
}
}
var mid = midPoint;
if (negativeIsActuated)
return mid - (mid - minValue) * negativeValue;
return mid + (maxValue - mid) * positiveValue;
}
///
public override float EvaluateMagnitude(ref InputBindingCompositeContext context)
{
var value = ReadValue(ref context);
if (value < midPoint)
{
value = Mathf.Abs(value - midPoint);
return NormalizeProcessor.Normalize(value, 0, Mathf.Abs(minValue), 0);
}
value = Mathf.Abs(value - midPoint);
return NormalizeProcessor.Normalize(value, 0, Mathf.Abs(maxValue), 0);
}
///
/// What happens to the value of an if both
/// and are actuated at the same time.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1717:OnlyFlagsEnumsShouldHavePluralNames", Justification = "False positive: `Wins` is not a plural form.")]
public enum WhichSideWins
{
///
/// If both and are actuated, the sides cancel
/// each other out and the result is 0.
///
Neither = 0,
///
/// If both and are actuated, the value of
/// wins and is ignored.
///
Positive = 1,
///
/// If both and are actuated, the value of
/// wins and is ignored.
///
Negative = 2,
}
}
}