A game about forced loneliness, made by TACStudios
1using System;
2using UnityEngine.InputSystem.Layouts;
3using UnityEngine.InputSystem.LowLevel;
4
5namespace UnityEngine.InputSystem.Controls
6{
7 /// <summary>
8 /// A control made up of four discrete, directional buttons. Forms a vector
9 /// but can also be addressed as individual buttons.
10 /// </summary>
11 /// <remarks>
12 /// Is stored as four bits by default.
13 ///
14 /// The vector that is aggregated from the button states is normalized. I.e.
15 /// even if pressing diagonally, the vector will have a length of 1 (instead
16 /// of reading something like <c>(1,1)</c> for example).
17 /// </remarks>
18 public class DpadControl : Vector2Control
19 {
20 [InputControlLayout(hideInUI = true)]
21 public class DpadAxisControl : AxisControl
22 {
23 public int component { get; set; }
24
25 protected override void FinishSetup()
26 {
27 base.FinishSetup();
28 component = name == "x" ? 0 : 1;
29
30 // Set the state block to be the parent's state block. We don't use that to read
31 // the axis directly (we call the parent control to do that), but we need to set
32 // it up the actions know to monitor this memory for changes to the control.
33 m_StateBlock = m_Parent.m_StateBlock;
34 }
35
36 public override unsafe float ReadUnprocessedValueFromState(void* statePtr)
37 {
38 var value = ((DpadControl)m_Parent).ReadUnprocessedValueFromState(statePtr);
39 return value[component];
40 }
41 }
42
43 // The DpadAxisControl has it's own logic to read state from the parent dpad.
44 // The useStateFrom argument here is not actually used by that. The only reason
45 // it is set up here is to avoid any state bytes being reserved for the DpadAxisControl.
46 [InputControl(name = "x", layout = "DpadAxis", useStateFrom = "right", synthetic = true)]
47 [InputControl(name = "y", layout = "DpadAxis", useStateFrom = "up", synthetic = true)]
48
49 /// <summary>
50 /// The button representing the vertical upwards state of the D-Pad.
51 /// </summary>
52 [InputControl(bit = (int)ButtonBits.Up, displayName = "Up")]
53 public ButtonControl up { get; set; }
54
55 /// <summary>
56 /// The button representing the vertical downwards state of the D-Pad.
57 /// </summary>
58 [InputControl(bit = (int)ButtonBits.Down, displayName = "Down")]
59 public ButtonControl down { get; set; }
60
61 /// <summary>
62 /// The button representing the horizontal left state of the D-Pad.
63 /// </summary>
64 [InputControl(bit = (int)ButtonBits.Left, displayName = "Left")]
65 public ButtonControl left { get; set; }
66
67 /// <summary>
68 /// The button representing the horizontal right state of the D-Pad.
69 /// </summary>
70 [InputControl(bit = (int)ButtonBits.Right, displayName = "Right")]
71 public ButtonControl right { get; set; }
72
73 ////TODO: should have X and Y child controls as well
74
75 public DpadControl()
76 {
77 m_StateBlock.sizeInBits = 4;
78 m_StateBlock.format = InputStateBlock.FormatBit;
79 }
80
81 protected override void FinishSetup()
82 {
83 up = GetChildControl<ButtonControl>("up");
84 down = GetChildControl<ButtonControl>("down");
85 left = GetChildControl<ButtonControl>("left");
86 right = GetChildControl<ButtonControl>("right");
87 base.FinishSetup();
88 }
89
90 public override unsafe Vector2 ReadUnprocessedValueFromState(void* statePtr)
91 {
92 var upIsPressed = up.ReadValueFromStateWithCaching(statePtr) >= up.pressPointOrDefault;
93 var downIsPressed = down.ReadValueFromStateWithCaching(statePtr) >= down.pressPointOrDefault;
94 var leftIsPressed = left.ReadValueFromStateWithCaching(statePtr) >= left.pressPointOrDefault;
95 var rightIsPressed = right.ReadValueFromStateWithCaching(statePtr) >= right.pressPointOrDefault;
96
97 return MakeDpadVector(upIsPressed, downIsPressed, leftIsPressed, rightIsPressed);
98 }
99
100 public override unsafe void WriteValueIntoState(Vector2 value, void* statePtr)
101 {
102 var upIsPressed = up.IsValueConsideredPressed(value.y);
103 var downIsPressed = down.IsValueConsideredPressed(value.y * -1f);
104 var leftIsPressed = left.IsValueConsideredPressed(value.x * -1f);
105 var rightIsPressed = right.IsValueConsideredPressed(value.x);
106
107 up.WriteValueIntoState(upIsPressed && !downIsPressed ? value.y : 0f, statePtr);
108 down.WriteValueIntoState(downIsPressed && !upIsPressed ? value.y * -1f : 0f, statePtr);
109 left.WriteValueIntoState(leftIsPressed && !rightIsPressed ? value.x * -1f : 0f, statePtr);
110 right.WriteValueIntoState(rightIsPressed && !leftIsPressed ? value.x : 0f, statePtr);
111 }
112
113 /// <summary>
114 /// Create a direction vector from the given four button states.
115 /// </summary>
116 /// <param name="up">Whether button representing the up direction is pressed.</param>
117 /// <param name="down">Whether button representing the down direction is pressed.</param>
118 /// <param name="left">Whether button representing the left direction is pressed.</param>
119 /// <param name="right">Whether button representing the right direction is pressed.</param>
120 /// <param name="normalize">Whether to normalize the resulting vector. If this is false, vectors in the diagonal
121 /// directions will have a magnitude of greater than 1. For example, up-left will be (-1,1).</param>
122 /// <returns>A 2D direction vector.</returns>
123 public static Vector2 MakeDpadVector(bool up, bool down, bool left, bool right, bool normalize = true)
124 {
125 var upValue = up ? 1.0f : 0.0f;
126 var downValue = down ? -1.0f : 0.0f;
127 var leftValue = left ? -1.0f : 0.0f;
128 var rightValue = right ? 1.0f : 0.0f;
129
130 var result = new Vector2(leftValue + rightValue, upValue + downValue);
131
132 if (normalize)
133 {
134 // If press is diagonal, adjust coordinates to produce vector of length 1.
135 // pow(0.707107) is roughly 0.5 so sqrt(pow(0.707107)+pow(0.707107)) is ~1.
136 const float diagonal = 0.707107f;
137 if (result.x != 0 && result.y != 0)
138 result = new Vector2(result.x * diagonal, result.y * diagonal);
139 }
140
141 return result;
142 }
143
144 /// <summary>
145 /// Create a direction vector from the given axis states.
146 /// </summary>
147 /// <param name="up">Axis value representing the up direction.</param>
148 /// <param name="down">Axis value representing the down direction.</param>
149 /// <param name="left">Axis value representing the left direction.</param>
150 /// <param name="right">Axis value representing the right direction.</param>
151 /// <returns>A 2D direction vector.</returns>
152 public static Vector2 MakeDpadVector(float up, float down, float left, float right)
153 {
154 return new Vector2(-left + right, up - down);
155 }
156
157 internal enum ButtonBits
158 {
159 Up,
160 Down,
161 Left,
162 Right,
163 }
164 }
165}