DpadControl.cs 6.7 KB

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