using System; using System.ComponentModel; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.Utilities; #if UNITY_EDITOR using UnityEditor; using UnityEngine.InputSystem.Editor; using UnityEngine.UIElements; #endif namespace UnityEngine.InputSystem.Composites { /// /// A 3D vector formed from six floating-point inputs. /// /// /// Depending on the setting of , the vector is either in the [-1..1] /// range on each axis (normalized or not depending on ) or is in the /// full value range of the input controls. /// /// /// /// action.AddCompositeBinding("3DVector") /// .With("Forward", "<Keyboard>/w") /// .With("Backward", "<Keyboard>/s") /// .With("Left", "<Keyboard>/a") /// .With("Right", "<Keyboard>/d") /// .With("Up", "<Keyboard>/q") /// .With("Down", "<Keyboard>/e"); /// /// /// /// [DisplayStringFormat("{up}+{down}/{left}+{right}/{forward}+{backward}")] [DisplayName("Up/Down/Left/Right/Forward/Backward Composite")] public class Vector3Composite : InputBindingComposite { /// /// Binding for the button that represents the up (that is, (0,1,0)) direction of the vector. /// /// /// This property is automatically assigned by the input system. /// // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once FieldCanBeMadeReadOnly.Global [InputControl(layout = "Axis")] public int up; /// /// Binding for the button that represents the down (that is, (0,-1,0)) direction of the vector. /// /// /// This property is automatically assigned by the input system. /// // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once FieldCanBeMadeReadOnly.Global [InputControl(layout = "Axis")] public int down; /// /// Binding for the button that represents the left (that is, (-1,0,0)) direction of the vector. /// /// /// This property is automatically assigned by the input system. /// // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once FieldCanBeMadeReadOnly.Global [InputControl(layout = "Axis")] public int left; /// /// Binding for the button that represents the right (that is, (1,0,0)) direction of the vector. /// /// /// This property is automatically assigned by the input system. /// // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once FieldCanBeMadeReadOnly.Global [InputControl(layout = "Axis")] public int right; /// /// Binding for the button that represents the right (that is, (0,0,1)) direction of the vector. /// /// /// This property is automatically assigned by the input system. /// // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once FieldCanBeMadeReadOnly.Global [InputControl(layout = "Axis")] public int forward; /// /// Binding for the button that represents the right (that is, (0,0,-1)) direction of the vector. /// /// /// This property is automatically assigned by the input system. /// // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once FieldCanBeMadeReadOnly.Global [InputControl(layout = "Axis")] public int backward; /// /// How to synthesize a Vector3 from the values read from , , /// , , , and . /// /// Determines how X, Y, and Z of the resulting Vector3 are formed from input values. public Mode mode = Mode.Analog; /// public override Vector3 ReadValue(ref InputBindingCompositeContext context) { if (mode == Mode.Analog) { var upValue = context.ReadValue(up); var downValue = context.ReadValue(down); var leftValue = context.ReadValue(left); var rightValue = context.ReadValue(right); var forwardValue = context.ReadValue(forward); var backwardValue = context.ReadValue(backward); return new Vector3(rightValue - leftValue, upValue - downValue, forwardValue - backwardValue); } else { var upValue = context.ReadValueAsButton(up) ? 1f : 0f; var downValue = context.ReadValueAsButton(down) ? -1f : 0f; var leftValue = context.ReadValueAsButton(left) ? -1f : 0f; var rightValue = context.ReadValueAsButton(right) ? 1f : 0f; var forwardValue = context.ReadValueAsButton(forward) ? 1f : 0f; var backwardValue = context.ReadValueAsButton(backward) ? -1f : 0f; var vector = new Vector3(leftValue + rightValue, upValue + downValue, forwardValue + backwardValue); if (mode == Mode.DigitalNormalized) vector = vector.normalized; return vector; } } /// public override float EvaluateMagnitude(ref InputBindingCompositeContext context) { var value = ReadValue(ref context); return value.magnitude; } /// /// Determines how a Vector3 is synthesized from part controls. /// public enum Mode { /// /// 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). /// Analog, /// /// 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,0), a vector /// of roughly (-0.7,0.7,0) (that is, corresponding to new Vector3(-1,1,0).normalized) is returned instead. /// DigitalNormalized, /// /// Part controls are treated as buttons (on/off) and the resulting vector is not normalized. This means /// that if both left and up are pressed, for example, the resulting vector is (-1,1,0) and has a length /// greater than 1. /// Digital, } } #if UNITY_EDITOR internal class Vector3CompositeEditor : InputParameterEditor { private GUIContent m_ModeLabel = new GUIContent("Mode", "How to synthesize a Vector3 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() { #if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS if (!InputSystem.settings.IsFeatureEnabled(InputFeatureNames.kUseIMGUIEditorForAssets)) return; #endif target.mode = (Vector3Composite.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 = (Vector3Composite.Mode)evt.newValue; onChangedCallback(); }); root.Add(modeField); } #endif } #endif }