summaryrefslogtreecommitdiff
path: root/src/Noddybox.Emulation.Xna.Input/Joystick
diff options
context:
space:
mode:
Diffstat (limited to 'src/Noddybox.Emulation.Xna.Input/Joystick')
-rw-r--r--src/Noddybox.Emulation.Xna.Input/Joystick/JoystickDriver.cs283
-rw-r--r--src/Noddybox.Emulation.Xna.Input/Joystick/JoystickState.cs14
2 files changed, 275 insertions, 22 deletions
diff --git a/src/Noddybox.Emulation.Xna.Input/Joystick/JoystickDriver.cs b/src/Noddybox.Emulation.Xna.Input/Joystick/JoystickDriver.cs
index dc83831..450113b 100644
--- a/src/Noddybox.Emulation.Xna.Input/Joystick/JoystickDriver.cs
+++ b/src/Noddybox.Emulation.Xna.Input/Joystick/JoystickDriver.cs
@@ -45,7 +45,7 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
public bool[] Buttons {get; private set;}
- private DigitalJoystickEventArgs(DigitalJoystickState state, bool[] buttons)
+ public DigitalJoystickEventArgs(DigitalJoystickState state, bool[] buttons)
{
State = state;
Buttons = buttons;
@@ -64,7 +64,7 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
public bool[] Buttons {get; private set;}
- private AnalogueJoystickEventArgs(Vector2 state, bool[] buttons)
+ public AnalogueJoystickEventArgs(Vector2 state, bool[] buttons)
{
State = state;
Buttons = buttons;
@@ -77,6 +77,7 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
private InputManager manager;
private bool subscribed;
+ private JoystickType joystickType;
private Texture2D backgroundImage;
private Texture2D joystickImage;
@@ -84,12 +85,16 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
private DigitalJoystickState digital;
private Vector2 analogue;
+ private Vector2 contact;
+ private int stickId;
private bool[] button;
+ private int[] buttonId;
private Vector2 backgroundPosition;
private Vector2 joystickPosition;
private Vector2[] buttonPositions;
private float deadzone;
+ private bool deadzoneBreached;
private float stickSize;
private int numButtons;
@@ -100,37 +105,197 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
private JoystickLock joylock;
+ private Vector2[] digitalPositions;
+ private DigitalJoystickState[] digitalAngles;
+
#endregion
#region Private members
/// <summary>
+ /// Update the analogue position with the passed state. This also applies the joylock clamp.
+ /// </summary>
+ /// <param name="v">The touch screen location.</param>
+ /// <returns>True if the state was changed.</returns>
+ private bool UpdatePosition(Vector2 v)
+ {
+ v -= contact;
+
+ switch(joylock)
+ {
+ case JoystickLock.TwoWayVertical:
+ v.X = 0;
+ break;
+
+ case JoystickLock.TwoWayHorizontal:
+ v.Y = 0;
+ break;
+
+ case JoystickLock.FourWay:
+ if (Math.Abs(v.Y) > Math.Abs(v.X))
+ {
+ v.X = 0;
+ }
+ else
+ {
+ v.Y = 0;
+ }
+ break;
+
+ case JoystickLock.EightWay:
+ break;
+ }
+
+ if (v.Length() > stickSize)
+ {
+ v.Normalize();
+ v *= stickSize;
+ }
+
+ if (v != analogue)
+ {
+ analogue = v;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Update the digital position with the new analogue state.
+ /// </summary>
+ /// <param name="v"></param>
+ /// <returns>True if the state was changed.</returns>
+ private bool UpdatePosition()
+ {
+ DigitalJoystickState newState = DigitalJoystickState.Centre;
+
+ if (analogue.Length() > deadzone)
+ {
+ float angle = MathHelper.ToDegrees((float)Math.Atan2(analogue.Y, analogue.X)) + 22.5f;
+
+ while (angle < 0)
+ {
+ angle += 360;
+ }
+
+ System.Diagnostics.Debug.WriteLine("original angle = {0}", angle);
+
+ angle = Math.Min(angle / 45, 7);
+
+ newState = digitalAngles[(int)angle];
+ System.Diagnostics.Debug.WriteLine("calced angle = {0} / {1}", angle, newState);
+ }
+
+ if (newState != digital)
+ {
+ digital = newState;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
/// Updates the joystick.
/// </summary>
- public void TouchScreenHandler(object sender, InputManager.TouchLocationEventArgs e)
+ private void TouchScreenHandler(object sender, InputManager.TouchLocationEventArgs e)
{
- if (e.Location.State == TouchLocationState.Pressed)
+ bool stateChanged = false;
+
+ // Handle release of stick or buttons
+ //
+ if (e.Location.State == TouchLocationState.Released)
+ {
+ if (stickId == e.Location.Id)
+ {
+ stickId = 0;
+ digital = DigitalJoystickState.Centre;
+ analogue = Vector2.Zero;
+ stateChanged = true;
+ e.Handled = true;
+ }
+ else
+ {
+ for(int f = 0; !e.Handled && f < numButtons; f++)
+ {
+ if (buttonId[f] == e.Location.Id)
+ {
+ buttonId[f] = 0;
+ button[f] = false;
+ stateChanged = true;
+ e.Handled = true;
+ }
+ }
+ }
+ }
+
+ // Handle hold of stick
+ //
+ if (e.Location.State == TouchLocationState.Moved && e.Location.Id == stickId)
{
- for(int f = 0; !e.Handled && f < numButtons; f++)
+ e.Handled = true;
+
+ if (!deadzoneBreached)
{
- if ((buttonPositions[f] - e.Location.Position).Length() < buttonSize)
+ float l = (contact - e.Location.Position).Length();
+
+ if (l > deadzone)
{
- e.Handled = true;
- button[f] = true;
+ deadzoneBreached = true;
}
}
+
+ if (joystickType == JoystickType.Digital && deadzoneBreached && UpdatePosition(e.Location.Position))
+ {
+ stateChanged = UpdatePosition();
+ }
+ else if (joystickType == JoystickType.Analogue && deadzoneBreached)
+ {
+ stateChanged = UpdatePosition(e.Location.Position);
+ }
}
- else if (e.Location.State == TouchLocationState.Released)
+
+ // Handle touch of stick or buttons
+ //
+ if (e.Location.State == TouchLocationState.Pressed)
{
- for(int f = 0; !e.Handled && f < numButtons; f++)
+ float l = (joystickPosition - e.Location.Position).Length();
+
+ if (l < joystickSize)
{
- if ((buttonPositions[f] - e.Location.Position).Length() < buttonSize)
+ contact = e.Location.Position;
+ stickId = e.Location.Id;
+ deadzoneBreached = false;
+ e.Handled = true;
+ }
+ else
+ {
+ for(int f = 0; !e.Handled && f < numButtons; f++)
{
- e.Handled = true;
- button[f] = false;
+ if ((buttonPositions[f] - e.Location.Position).Length() < buttonSize)
+ {
+ e.Handled = true;
+ button[f] = true;
+ buttonId[f] = e.Location.Id;
+ stateChanged = true;
+ }
}
}
}
+
+ if (stateChanged && joystickType == JoystickType.Digital && DigitalEvent != null)
+ {
+ DigitalEvent(this, new DigitalJoystickEventArgs(digital, button));
+ }
+ else if (stateChanged && joystickType == JoystickType.Analogue && AnalogueEvent != null)
+ {
+ AnalogueEvent(this, new AnalogueJoystickEventArgs(analogue, button));
+ }
}
#endregion
@@ -138,18 +303,53 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
#region Public members
/// <summary>
- /// Stops consuming inputs.
+ /// Set the type of joystick lock.
/// </summary>
- public void StopJoytstickUpdates()
+ public JoystickLock LockType {set {joylock = value;}}
+
+
+ /// <summary>
+ /// Stops consuming inputs and resets joystick and fire buttons.
+ /// </summary>
+ /// <param name="generateEvents">Generates events for cleared state.</param>
+ public void StopJoytstickUpdates(bool generateEvents)
{
if (subscribed)
{
manager.TouchEvent -= TouchScreenHandler;
subscribed = false;
+
+ digital = DigitalJoystickState.Centre;
+ analogue = Vector2.Zero;
+ stickId = 0;
+ deadzoneBreached = false;
+
+ for(int f = 0; f < numButtons; f++)
+ {
+ button[f] = false;
+ buttonId[f] = 0;
+ }
+
+ if (generateEvents && joystickType == JoystickType.Digital && DigitalEvent != null)
+ {
+ DigitalEvent(this, new DigitalJoystickEventArgs(digital, button));
+ }
+ else if (generateEvents && joystickType == JoystickType.Analogue && AnalogueEvent != null)
+ {
+ AnalogueEvent(this, new AnalogueJoystickEventArgs(analogue, button));
+ }
}
}
/// <summary>
+ /// Stops consuming inputs and resets joystick and fire buttons. Generates events for the cleared state.
+ /// </summary>
+ public void StopJoytstickUpdates()
+ {
+ StopJoytstickUpdates(true);
+ }
+
+ /// <summary>
/// Starts consuming inputs.
/// </summary>
public void StartJoystickUpdates()
@@ -169,8 +369,16 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
{
spriteBatch.Draw(backgroundImage, backgroundPosition, Color.White);
- spriteBatch.Draw(joystickImage, joystickPosition + analogue,
- null, Color.White, 0f, joystickOffset, 1f, SpriteEffects.None, 0f);
+ if (joystickType == JoystickType.Digital)
+ {
+ spriteBatch.Draw(joystickImage, joystickPosition + digitalPositions[(int)digital],
+ null, Color.White, 0f, joystickOffset, 1f, SpriteEffects.None, 0f);
+ }
+ else
+ {
+ spriteBatch.Draw(joystickImage, joystickPosition + analogue,
+ null, Color.White, 0f, joystickOffset, 1f, SpriteEffects.None, 0f);
+ }
for(int f = 0; f < numButtons; f++)
{
@@ -183,6 +391,10 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
#region Events
+ public EventHandler<DigitalJoystickEventArgs> DigitalEvent;
+
+ public EventHandler<AnalogueJoystickEventArgs> AnalogueEvent;
+
#endregion
#region Constructors
@@ -207,6 +419,7 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
float deadzone, float stickSize)
{
this.manager = manager;
+ this.joystickType = joystickType;
this.backgroundImage = backgroundImage;
this.joystickImage = joystickImage;
this.buttonImage = buttonImage;
@@ -224,6 +437,7 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
this.numButtons = buttonPositions.Length;
this.button = new bool[numButtons];
+ this.buttonId = new int[numButtons];
this.buttonPositions = new Vector2[numButtons];
for(int f = 0; f < numButtons; f++)
@@ -239,12 +453,47 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
}
this.deadzone = deadzone;
+ this.deadzoneBreached = false;
this.stickSize = stickSize;
this.digital = DigitalJoystickState.Centre;
this.joylock = JoystickLock.EightWay;
this.analogue = Vector2.Zero;
+ this.digitalPositions = new Vector2[16];
+
+ this.digitalPositions[(int)DigitalJoystickState.Centre] = Vector2.Zero;
+
+ this.digitalPositions[(int)DigitalJoystickState.Up] = new Vector2(0, -stickSize);
+ this.digitalPositions[(int)DigitalJoystickState.Down] = new Vector2(0, stickSize);
+ this.digitalPositions[(int)DigitalJoystickState.Left] = new Vector2(-stickSize, 0);
+ this.digitalPositions[(int)DigitalJoystickState.Right] = new Vector2(stickSize, 0);
+
+ this.digitalPositions[(int)DigitalJoystickState.UpLeft] = new Vector2(-stickSize, -stickSize);
+ this.digitalPositions[(int)DigitalJoystickState.UpRight] = new Vector2(stickSize, -stickSize);
+ this.digitalPositions[(int)DigitalJoystickState.DownLeft] = new Vector2(-stickSize, stickSize);
+ this.digitalPositions[(int)DigitalJoystickState.DownRight] = new Vector2(stickSize, stickSize);
+
+ this.digitalAngles = new DigitalJoystickState[8]
+ {
+ //DigitalJoystickState.Up,
+ //DigitalJoystickState.UpRight,
+ //DigitalJoystickState.Right,
+ //DigitalJoystickState.DownRight,
+ //DigitalJoystickState.Down,
+ //DigitalJoystickState.DownLeft,
+ //DigitalJoystickState.Left,
+ //DigitalJoystickState.UpLeft
+ DigitalJoystickState.Right,
+ DigitalJoystickState.DownRight,
+ DigitalJoystickState.Down,
+ DigitalJoystickState.DownLeft,
+ DigitalJoystickState.Left,
+ DigitalJoystickState.UpLeft,
+ DigitalJoystickState.Up,
+ DigitalJoystickState.UpRight
+ };
+
StartJoystickUpdates();
}
diff --git a/src/Noddybox.Emulation.Xna.Input/Joystick/JoystickState.cs b/src/Noddybox.Emulation.Xna.Input/Joystick/JoystickState.cs
index 3933127..5c23313 100644
--- a/src/Noddybox.Emulation.Xna.Input/Joystick/JoystickState.cs
+++ b/src/Noddybox.Emulation.Xna.Input/Joystick/JoystickState.cs
@@ -31,11 +31,15 @@ namespace Noddybox.Emulation.Xna.Input.Joystick
[Flags]
public enum DigitalJoystickState
{
- Centre = 0x00,
- Up = 0x01,
- Down = 0x02,
- Left = 0x04,
- Right = 0x08
+ Centre = 0x00,
+ Up = 0x01,
+ Down = 0x02,
+ Left = 0x04,
+ Right = 0x08,
+ UpLeft = Up | Left,
+ UpRight = Up | Right,
+ DownLeft = Down | Left,
+ DownRight = Down | Right
}
/// <summary>