File size: 9,311 Bytes
18a519f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | using System.ComponentModel;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.Processors;
using UnityEngine.InputSystem.Utilities;
namespace UnityEngine.InputSystem.Composites
{
/// <summary>
/// A single axis value computed from one axis that pulls in the <see cref="negative"/> direction (<see cref="minValue"/>) and one
/// axis that pulls in the <see cref="positive"/> direction (<see cref="maxValue"/>).
/// </summary>
/// <remarks>
/// The limits of the axis are determined by <see cref="minValue"/> and <see cref="maxValue"/>.
/// By default, they are set to <c>[-1..1]</c>. The values can be set as parameters.
///
/// <example>
/// <code>
/// var action = new InputAction();
/// action.AddCompositeBinding("Axis(minValue=0,maxValue=2")
/// .With("Negative", "<Keyboard>/a")
/// .With("Positive", "<Keyboard>/d");
/// </code>
/// </example>
///
/// If both axes are actuated at the same time, the behavior depends on <see cref="whichSideWins"/>.
/// By default, neither side will win (<see cref="WhichSideWins.Neither"/>) and the result
/// will be 0 (or, more precisely, the midpoint between <see cref="minValue"/> and <see cref="maxValue"/>).
/// This can be customized to make the positive side win (<see cref="WhichSideWins.Positive"/>)
/// or the negative one (<see cref="WhichSideWins.Negative"/>).
///
/// This is useful, for example, in a driving game where break should cancel out accelerate.
/// By binding <see cref="negative"/> to the break control(s) and <see cref="positive"/> to the
/// acceleration control(s), and setting <see cref="whichSideWins"/> to <see cref="WhichSideWins.Negative"/>,
/// if the break button is pressed, it will always cause the acceleration button to be ignored.
///
/// The actual <em>absolute</em> values of <see cref="negative"/> and <see cref="positive"/> are used
/// to scale <see cref="minValue"/> and <see cref="maxValue"/> respectively. So if, for example, <see cref="positive"/>
/// is bound to <see cref="Gamepad.rightTrigger"/> and the trigger is at a value of 0.5, then the resulting
/// value is <c>maxValue * 0.5</c> (the actual formula is <c>midPoint + (maxValue - midPoint) * positive</c>).
/// </remarks>
[DisplayStringFormat("{negative}/{positive}")]
[DisplayName("Positive/Negative Binding")]
public class AxisComposite : InputBindingComposite<float>
{
/// <summary>
/// Binding for the axis input that controls the negative [<see cref="minValue"/>..0] direction of the
/// combined axis.
/// </summary>
/// <remarks>
/// This property is automatically assigned by the input system.
/// </remarks>
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
[InputControl(layout = "Axis")] public int negative = 0;
/// <summary>
/// Binding for the axis input that controls the positive [0..<see cref="maxValue"/>] direction of the
/// combined axis.
/// </summary>
/// <remarks>
/// This property is automatically assigned by the input system.
/// </remarks>
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once FieldCanBeMadeReadOnly.Global
[InputControl(layout = "Axis")] public int positive = 0;
/// <summary>
/// The lower bound that the axis is limited to. -1 by default.
/// </summary>
/// <remarks>
/// This value corresponds to the full actuation of the control(s) bound to <see cref="negative"/>.
///
/// <example>
/// <code>
/// var action = new InputAction();
/// action.AddCompositeBinding("Axis(minValue=0,maxValue=2")
/// .With("Negative", "<Keyboard>/a")
/// .With("Positive", "<Keyboard>/d");
/// </code>
/// </example>
/// </remarks>
/// <seealso cref="maxValue"/>
/// <seealso cref="negative"/>
// 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;
/// <summary>
/// The upper bound that the axis is limited to. 1 by default.
/// </summary>
/// <remarks>
/// This value corresponds to the full actuation of the control(s) bound to <see cref="positive"/>.
///
/// <example>
/// <code>
/// var action = new InputAction();
/// action.AddCompositeBinding("Axis(minValue=0,maxValue=2")
/// .With("Negative", "<Keyboard>/a")
/// .With("Positive", "<Keyboard>/d");
/// </code>
/// </example>
/// </remarks>
/// <seealso cref="minValue"/>
/// <seealso cref="positive"/>
// 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;
/// <summary>
/// If both the <see cref="positive"/> and <see cref="negative"/> button are actuated, this
/// determines which value is returned from the composite.
/// </summary>
[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;
/// <summary>
/// The value that is returned if the composite is in a neutral position, that is, if
/// neither <see cref="positive"/> nor <see cref="negative"/> are actuated or if
/// <see cref="whichSideWins"/> is set to <see cref="WhichSideWins.Neither"/> and
/// both <see cref="positive"/> and <see cref="negative"/> are actuated.
/// </summary>
public float midPoint => (maxValue + minValue) / 2;
////TODO: add parameters to control ramp up&down
/// <inheritdoc />
public override float ReadValue(ref InputBindingCompositeContext context)
{
var negativeValue = Mathf.Abs(context.ReadValue<float>(negative));
var positiveValue = Mathf.Abs(context.ReadValue<float>(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;
}
/// <inheritdoc />
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);
}
/// <summary>
/// What happens to the value of an <see cref="AxisComposite"/> if both <see cref="positive"/>
/// and <see cref="negative"/> are actuated at the same time.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1717:OnlyFlagsEnumsShouldHavePluralNames", Justification = "False positive: `Wins` is not a plural form.")]
public enum WhichSideWins
{
/// <summary>
/// If both <see cref="positive"/> and <see cref="negative"/> are actuated, the sides cancel
/// each other out and the result is 0.
/// </summary>
Neither = 0,
/// <summary>
/// If both <see cref="positive"/> and <see cref="negative"/> are actuated, the value of
/// <see cref="positive"/> wins and <see cref="negative"/> is ignored.
/// </summary>
Positive = 1,
/// <summary>
/// If both <see cref="positive"/> and <see cref="negative"/> are actuated, the value of
/// <see cref="negative"/> wins and <see cref="positive"/> is ignored.
/// </summary>
Negative = 2,
}
}
}
|