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}