// This file is part of the Noddybox.Emulation C# suite.
//
// Noddybox.Emulation is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Noddybox.Emulation is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Noddybox.Emulation. If not, see .
//
// Copyright (c) 2012 Ian Cowburn
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input.Touch;
namespace Noddybox.Emulation.Xna.Input.Joystick
{
///
/// Displays and drives the joystick. Unlike the keyboard this is not
/// not done event driven, but as a clasic Joystick interface.
///
public class JoystickDriver
{
#region Event arguments
///
/// Event data when the digital joystick state changes
///
public class DigitalJoystickEventArgs : EventArgs
{
///
/// The joystick state.
///
public DigitalJoystickState State {get; private set;}
public bool[] Buttons {get; private set;}
private DigitalJoystickEventArgs(DigitalJoystickState state, bool[] buttons)
{
State = state;
Buttons = buttons;
}
}
///
/// Event data when the analogue joystick state changes
///
public class AnalogueJoystickEventArgs : EventArgs
{
///
/// The joystick state.
///
public Vector2 State {get; private set;}
public bool[] Buttons {get; private set;}
private AnalogueJoystickEventArgs(Vector2 state, bool[] buttons)
{
State = state;
Buttons = buttons;
}
}
#endregion
#region Private data
private InputManager manager;
private bool subscribed;
private Texture2D backgroundImage;
private Texture2D joystickImage;
private Texture2D buttonImage;
private DigitalJoystickState digital;
private Vector2 analogue;
private bool[] button;
private Vector2 backgroundPosition;
private Vector2 joystickPosition;
private Vector2[] buttonPositions;
private float deadzone;
private float stickSize;
private int numButtons;
private Vector2 joystickOffset;
private Vector2 buttonOffset;
private int joystickSize;
private int buttonSize;
private JoystickLock joylock;
#endregion
#region Private members
///
/// Updates the joystick.
///
public void TouchScreenHandler(object sender, InputManager.TouchLocationEventArgs e)
{
if (e.Location.State == TouchLocationState.Pressed)
{
for(int f = 0; !e.Handled && f < numButtons; f++)
{
if ((buttonPositions[f] - e.Location.Position).Length() < buttonSize)
{
e.Handled = true;
button[f] = true;
}
}
}
else if (e.Location.State == TouchLocationState.Released)
{
for(int f = 0; !e.Handled && f < numButtons; f++)
{
if ((buttonPositions[f] - e.Location.Position).Length() < buttonSize)
{
e.Handled = true;
button[f] = false;
}
}
}
}
#endregion
#region Public members
///
/// Stops consuming inputs.
///
public void StopJoytstickUpdates()
{
if (subscribed)
{
manager.TouchEvent -= TouchScreenHandler;
subscribed = false;
}
}
///
/// Starts consuming inputs.
///
public void StartJoystickUpdates()
{
if (!subscribed)
{
manager.TouchEvent += TouchScreenHandler;
subscribed = true;
}
}
///
/// Draw the joystick
///
///
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(backgroundImage, backgroundPosition, Color.White);
spriteBatch.Draw(joystickImage, joystickPosition + analogue,
null, Color.White, 0f, joystickOffset, 1f, SpriteEffects.None, 0f);
for(int f = 0; f < numButtons; f++)
{
spriteBatch.Draw(buttonImage, buttonPositions[f],
null, button[f] ? Color.LightGray : Color.White, 0f, buttonOffset, button[f] ? 0.9f : 1f, SpriteEffects.None, 0f);
}
}
#endregion
#region Events
#endregion
#region Constructors
///
/// Constructor.
///
/// The input manager to attach to.
/// The graphics device to associate textures with.
/// The type of joystick.
/// The image for the joystick background.
/// The image for the joystick knob.
/// The image for a joystick button.
/// Where to draw and offset the joystick background to.
/// Where to centre the joystick. Note this is absolute.
/// Positions for the buttons.
/// Deadzone radius where joystick movement is not picked up.
/// The maximum radius that the joystick can move.
public JoystickDriver(InputManager manager, GraphicsDevice graphics, JoystickType joystickType,
Texture2D backgroundImage, Texture2D joystickImage, Texture2D buttonImage,
Vector2 backgroundPosition, Vector2 joystickPosition, Vector2[] buttonPositions,
float deadzone, float stickSize)
{
this.manager = manager;
this.backgroundImage = backgroundImage;
this.joystickImage = joystickImage;
this.buttonImage = buttonImage;
this.backgroundPosition = backgroundPosition;
this.joystickPosition = joystickPosition + backgroundPosition;
this.joystickSize = Math.Min(joystickImage.Width, joystickImage.Height) / 2;
this.joystickOffset = new Vector2(joystickImage.Width / 2f, joystickImage.Height / 2f);
if (buttonImage != null)
{
this.buttonSize = Math.Min(buttonImage.Width, buttonImage.Height) / 2;
this.buttonOffset = new Vector2(buttonImage.Width / 2f, buttonImage.Height / 2f);
this.numButtons = buttonPositions.Length;
this.button = new bool[numButtons];
this.buttonPositions = new Vector2[numButtons];
for(int f = 0; f < numButtons; f++)
{
this.buttonPositions[f] = backgroundPosition + buttonPositions[f] + buttonOffset;
}
}
else
{
this.buttonSize = 0;
this.buttonOffset = Vector2.Zero;
this.numButtons = 0;
}
this.deadzone = deadzone;
this.stickSize = stickSize;
this.digital = DigitalJoystickState.Centre;
this.joylock = JoystickLock.EightWay;
this.analogue = Vector2.Zero;
StartJoystickUpdates();
}
#endregion
}
}