From d3444080c31f10871ad8e97ceb8517565f74285a Mon Sep 17 00:00:00 2001 From: Ian C Date: Mon, 4 Jun 2012 23:24:52 +0000 Subject: Added code to handle joystick, and completed demo program. Ready to be used. --- .../Joystick/JoystickDriver.cs | 283 +++++++++++++++++++-- .../Joystick/JoystickState.cs | 14 +- .../Keyboard/KeyboardDriver.cs | 26 +- 3 files changed, 299 insertions(+), 24 deletions(-) (limited to 'src') 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 + /// + /// Update the analogue position with the passed state. This also applies the joylock clamp. + /// + /// The touch screen location. + /// True if the state was changed. + 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; + } + } + + /// + /// Update the digital position with the new analogue state. + /// + /// + /// True if the state was changed. + 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; + } + } + /// /// Updates the joystick. /// - 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,17 +303,52 @@ namespace Noddybox.Emulation.Xna.Input.Joystick #region Public members /// - /// Stops consuming inputs. + /// Set the type of joystick lock. /// - public void StopJoytstickUpdates() + public JoystickLock LockType {set {joylock = value;}} + + + /// + /// Stops consuming inputs and resets joystick and fire buttons. + /// + /// Generates events for cleared state. + 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)); + } } } + /// + /// Stops consuming inputs and resets joystick and fire buttons. Generates events for the cleared state. + /// + public void StopJoytstickUpdates() + { + StopJoytstickUpdates(true); + } + /// /// Starts consuming inputs. /// @@ -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 DigitalEvent; + + public EventHandler 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 } /// diff --git a/src/Noddybox.Emulation.Xna.Input/Keyboard/KeyboardDriver.cs b/src/Noddybox.Emulation.Xna.Input/Keyboard/KeyboardDriver.cs index 4fa265a..6379dd8 100644 --- a/src/Noddybox.Emulation.Xna.Input/Keyboard/KeyboardDriver.cs +++ b/src/Noddybox.Emulation.Xna.Input/Keyboard/KeyboardDriver.cs @@ -153,17 +153,39 @@ namespace Noddybox.Emulation.Xna.Input.Keyboard #region Public members /// - /// Stops consuming inputs. + /// Stops consuming inputs and releases all keys. /// - public void StopKeyboardUpdates() + /// Generates events for cleared keys. + public void StopKeyboardUpdates(bool generateEvents) { if (subscribed) { manager.TouchEvent -= TouchScreenHandler; subscribed = false; + + foreach (KeyState key in keymapState) + { + if (key.IsPressed) + { + key.IsPressed = false; + + if (generateEvents && KeyEvent != null) + { + KeyEvent(this, new KeyPressEventArgs() {Key = key.Symbol, Pressed = key.IsPressed}); + } + } + } } } + /// + /// Stops consuming inputs and releases all keys. Generates events for released keys. + /// + public void StopKeyboardUpdates() + { + StopKeyboardUpdates(true); + } + /// /// Starts consuming inputs. /// -- cgit v1.2.3