using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.Processors;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.Scripting;
namespace UnityEngine.InputSystem.Composites
{
///
/// A single axis value computed from a "negative" and a "positive" button.
///
///
/// This composite allows to arrange any arbitrary two buttons from a device in an
/// axis configuration such that one button pushes in one direction and the other
/// pushes in the opposite 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 buttons are pressed 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 values returned are the actual actuation values of the buttons, unaltered for
/// and inverted for . This means that if the buttons are actual axes (e.g.
/// the triggers on gamepads), then the values correspond to how much the axis is actuated.
///
[Preserve]
[DisplayStringFormat("{negative}/{positive}")]
public class AxisComposite : InputBindingComposite
{
///
/// Binding for the button that controls the positive direction of the axis.
///
///
/// This property is automatically assigned by the input system.
///
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
[InputControl(layout = "Button")] public int negative = 0;
///
/// Binding for the button that controls the negative direction of the axis.
///
///
/// This property is automatically assigned by the input system.
///
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
[InputControl(layout = "Button")] 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, i.e. 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 = context.ReadValue(negative);
var positiveValue = context.ReadValue(positive);
////TODO: take partial actuation into account (e.g. amount of actuation of gamepad trigger should result in partial actuation of axis)
////REVIEW: should this respect press points?
var negativeIsPressed = negativeValue > 0;
var positiveIsPressed = positiveValue > 0;
if (negativeIsPressed == positiveIsPressed)
{
switch (whichSideWins)
{
case WhichSideWins.Negative:
return -negativeValue;
case WhichSideWins.Positive:
return positiveValue;
case WhichSideWins.Neither:
return midPoint;
}
}
if (negativeIsPressed)
return -negativeValue;
return 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,
}
}
}