123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- using System;
- using System.ComponentModel;
- using UnityEngine.InputSystem.Controls;
- using UnityEngine.InputSystem.Layouts;
- using UnityEngine.InputSystem.Utilities;
-
- #if UNITY_EDITOR
- using UnityEditor;
- using UnityEngine.InputSystem.Editor;
- using UnityEngine.UIElements;
- #endif
-
- ////TODO: add support for ramp up/down
-
- namespace UnityEngine.InputSystem.Composites
- {
- /// <summary>
- /// A 2D planar motion vector computed from an up+down button pair and a left+right
- /// button pair.
- /// </summary>
- /// <remarks>
- /// This composite allows to grab arbitrary buttons from a device and arrange them in
- /// a D-Pad like configuration. Based on button presses, the composite will return a
- /// normalized direction vector (normalization can be turned off via <see cref="mode"/>).
- ///
- /// Opposing motions cancel each other out. This means that if, for example, both the left
- /// and right horizontal button are pressed, the resulting horizontal movement value will
- /// be zero.
- ///
- /// <example>
- /// <code>
- /// // Set up WASD style keyboard controls.
- /// action.AddCompositeBinding("2DVector")
- /// .With("Up", "<Keyboard>/w")
- /// .With("Left", "<Keyboard>/a")
- /// .With("Down", "<Keyboard>/s")
- /// .With("Right", "<Keyboard>/d");
- /// </code>
- /// </example>
- /// </remarks>
- /// <seealso cref="Vector3Composite"/>
- [DisplayStringFormat("{up}/{left}/{down}/{right}")] // This results in WASD.
- [DisplayName("Up/Down/Left/Right Composite")]
- public class Vector2Composite : InputBindingComposite<Vector2>
- {
- /// <summary>
- /// Binding for the button that represents the up (that is, <c>(0,1)</c>) direction of the vector.
- /// </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 up;
-
- /// <summary>
- /// Binding for the button represents the down (that is, <c>(0,-1)</c>) direction of the vector.
- /// </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 down;
-
- /// <summary>
- /// Binding for the button represents the left (that is, <c>(-1,0)</c>) direction of the vector.
- /// </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 left;
-
- /// <summary>
- /// Binding for the button that represents the right (that is, <c>(1,0)</c>) direction of the vector.
- /// </summary>
- /// <remarks>
- /// This property is automatically assigned by the input system.
- /// </remarks>
- [InputControl(layout = "Axis")] public int right;
-
- [Obsolete("Use Mode.DigitalNormalized with 'mode' instead")]
- public bool normalize = true;
-
- /// <summary>
- /// How to synthesize a <c>Vector2</c> from the values read from <see cref="up"/>, <see cref="down"/>,
- /// <see cref="left"/>, and <see cref="right"/>.
- /// </summary>
- /// <value>Determines how X and Y of the resulting <c>Vector2</c> are formed from input values.</value>
- /// <remarks>
- /// <example>
- /// <code>
- /// var action = new InputAction();
- ///
- /// // DigitalNormalized composite (the default). Turns gamepad left stick into
- /// // control equivalent to the D-Pad.
- /// action.AddCompositeBinding("2DVector(mode=0)")
- /// .With("up", "<Gamepad>/leftStick/up")
- /// .With("down", "<Gamepad>/leftStick/down")
- /// .With("left", "<Gamepad>/leftStick/left")
- /// .With("right", "<Gamepad>/leftStick/right");
- ///
- /// // Digital composite. Turns gamepad left stick into control equivalent
- /// // to the D-Pad except that diagonals will not be normalized.
- /// action.AddCompositeBinding("2DVector(mode=1)")
- /// .With("up", "<Gamepad>/leftStick/up")
- /// .With("down", "<Gamepad>/leftStick/down")
- /// .With("left", "<Gamepad>/leftStick/left")
- /// .With("right", "<Gamepad>/leftStick/right");
- ///
- /// // Analog composite. In this case results in setup that behaves exactly
- /// // the same as leftStick already does. But you could use it, for example,
- /// // to swap directions by binding "up" to leftStick/down and "down" to
- /// // leftStick/up.
- /// action.AddCompositeBinding("2DVector(mode=2)")
- /// .With("up", "<Gamepad>/leftStick/up")
- /// .With("down", "<Gamepad>/leftStick/down")
- /// .With("left", "<Gamepad>/leftStick/left")
- /// .With("right", "<Gamepad>/leftStick/right");
- /// </code>
- /// </example>
- /// </remarks>
- public Mode mode;
-
- /// <inheritdoc />
- public override Vector2 ReadValue(ref InputBindingCompositeContext context)
- {
- var mode = this.mode;
-
- if (mode == Mode.Analog)
- {
- var upValue = context.ReadValue<float>(up);
- var downValue = context.ReadValue<float>(down);
- var leftValue = context.ReadValue<float>(left);
- var rightValue = context.ReadValue<float>(right);
-
- return DpadControl.MakeDpadVector(upValue, downValue, leftValue, rightValue);
- }
-
- var upIsPressed = context.ReadValueAsButton(up);
- var downIsPressed = context.ReadValueAsButton(down);
- var leftIsPressed = context.ReadValueAsButton(left);
- var rightIsPressed = context.ReadValueAsButton(right);
-
- // Legacy. We need to reference the obsolete member here so temporarily
- // turn of the warning.
- #pragma warning disable CS0618
- if (!normalize) // Was on by default.
- mode = Mode.Digital;
- #pragma warning restore CS0618
-
- return DpadControl.MakeDpadVector(upIsPressed, downIsPressed, leftIsPressed, rightIsPressed, mode == Mode.DigitalNormalized);
- }
-
- /// <inheritdoc />
- public override float EvaluateMagnitude(ref InputBindingCompositeContext context)
- {
- var value = ReadValue(ref context);
- return value.magnitude;
- }
-
- /// <summary>
- /// Determines how a <c>Vector2</c> is synthesized from part controls.
- /// </summary>
- public enum Mode
- {
- /// <summary>
- /// Part controls are treated as analog meaning that the floating-point values read from controls
- /// will come through as is (minus the fact that the down and left direction values are negated).
- /// </summary>
- Analog = 2,
-
- /// <summary>
- /// Part controls are treated as buttons (on/off) and the resulting vector is normalized. This means
- /// that if, for example, both left and up are pressed, instead of returning a vector (-1,1), a vector
- /// of roughly (-0.7,0.7) (that is, corresponding to <c>new Vector2(-1,1).normalized</c>) is returned instead.
- /// The resulting 2D area is diamond-shaped.
- /// </summary>
- DigitalNormalized = 0,
-
- /// <summary>
- /// Part controls are treated as buttons (on/off) and the resulting vector is not normalized. This means
- /// that if, for example, both left and up are pressed, the resulting vector is (-1,1) and has a length
- /// greater than 1. The resulting 2D area is box-shaped.
- /// </summary>
- Digital = 1
- }
- }
-
- #if UNITY_EDITOR
- internal class Vector2CompositeEditor : InputParameterEditor<Vector2Composite>
- {
- private GUIContent m_ModeLabel = new GUIContent("Mode",
- "How to synthesize a Vector2 from the inputs. Digital "
- + "treats part bindings as buttons (on/off) whereas Analog preserves "
- + "floating-point magnitudes as read from controls.");
-
- public override void OnGUI()
- {
- target.mode = (Vector2Composite.Mode)EditorGUILayout.EnumPopup(m_ModeLabel, target.mode);
- }
-
- #if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
- public override void OnDrawVisualElements(VisualElement root, Action onChangedCallback)
- {
- var modeField = new EnumField(m_ModeLabel.text, target.mode)
- {
- tooltip = m_ModeLabel.tooltip
- };
-
- modeField.RegisterValueChangedCallback(evt =>
- {
- target.mode = (Vector2Composite.Mode)evt.newValue;
- onChangedCallback();
- });
-
- root.Add(modeField);
- }
-
- #endif
- }
- #endif
- }
|