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