using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using System;
using System.Collections.Generic;
namespace FuelCell
{
///
/// The interface definition for Input
///
public interface IInputState
{
///
/// Update the input state
///
void Update();
///
/// Get the state of the left thumbstick for a specific player
///
/// The of the player to request data for.
/// The directional state of the thumbstick
Vector2 GetThumbStickLeft(PlayerIndex? controllingPlayer);
///
/// Get the state of the left thumbstick for a specific player and output the player index
///
/// The of the player to request data for.
/// The output of the instance
/// The directional state of the thumbstick
Vector2 GetThumbStickLeft(PlayerIndex? controllingPlayer, out PlayerIndex playerIndex);
///
/// Get the state of the right thumbstick for a specific player
///
/// The of the player to request data for.
/// The directional state of the thumbstick
Vector2 GetThumbStickRight(PlayerIndex? controllingPlayer);
///
/// Get the state of the right thumbstick for a specific player and output the player index
///
/// The of the player to request data for.
/// The output of the instance
/// The directional state of the thumbstick
Vector2 GetThumbStickRight(PlayerIndex? controllingPlayer, out PlayerIndex playerIndex);
///
/// Get the state of the left trigger for a specific player
///
/// The of the player to request data for.
/// The state of the trigger
float GetTriggerLeft(PlayerIndex? controllingPlayer);
///
/// Get the state of the left trigger for a specific player and output the player index
///
/// The of the player to request data for.
/// The output of the instance
/// The state of the trigger
float GetTriggerLeft(PlayerIndex? controllingPlayer, out PlayerIndex playerIndex);
///
/// Get the state of the right trigger for a specific player
///
/// The of the player to request data for.
/// The state of the trigger
float GetTriggerRight(PlayerIndex? controllingPlayer);
///
/// Get the state of the right trigger for a specific player and output the player index
///
/// The of the player to request data for.
/// The output of the instance
/// The state of the trigger
float GetTriggerRight(PlayerIndex? controllingPlayer, out PlayerIndex playerIndex);
///
/// Get input from the player for movement forward and backwards in the game.
///
/// The of the player to request data for.
/// Returns a positional update for the player
Vector3 GetPlayerMove(PlayerIndex? controllingPlayer);
///
/// Get input from the player for movement left and right in the game.
///
/// The of the player to request data for.
/// Returns the new turn ratio for the player.
float GetPlayerTurn(PlayerIndex? controllingPlayer);
///
/// Respond to the player wanting to exit the game.
///
/// The of the player to request data for.
/// Returns true if the player has requested to exit the game.
bool PlayerExit(PlayerIndex? controllingPlayer);
///
/// Respond to the player wanting to start the game.
///
/// The of the player to request data for.
/// Returns true if the player has requested to start the game.
bool StartGame(PlayerIndex? controllingPlayer);
}
///
/// The current implementation for the InputState based on the IInputState interface
///
public class InputState : IInputState
{
private readonly Game _game;
// A constant value to limit the maximum number of gamepads that can be connected at a time,
// `4` is usually sufficient but consoles can support more if you want to.
public const int MaxGamePadInputs = 4;
// The CURRENT state of input, values as they are read from the device.
public KeyboardState CurrentKeyboardState;
public readonly GamePadState[] CurrentGamePadStates;
// The PREVIOUS state of the input, so we can compare if an input was just activated, or recently released.
public KeyboardState LastKeyboardState;
public readonly GamePadState[] LastGamePadStates;
// Which gamepads are connected and active
public readonly bool[] GamePadWasConnected;
// Simple boolean to determine if ANY gamepads are connected.
public bool GamePadsAvailable = false;
// If we are on mobile, what is the state of any touchscreen input
public TouchCollection TouchState;
// If we are on mobile, what gestures have been detected.
public readonly List Gestures = new List();
///
/// Constructs a new input state.
///
public InputState(Game game)
{
if (game == null)
{
throw new ArgumentNullException("game", "Game cannot be null.");
}
_game = game;
CurrentKeyboardState = new KeyboardState();
CurrentGamePadStates = new GamePadState[MaxGamePadInputs];
for (int i = 0; i < MaxGamePadInputs; i++)
{
GamePad.GetCapabilities(i);
}
LastKeyboardState = new KeyboardState();
LastGamePadStates = new GamePadState[MaxGamePadInputs];
GamePadWasConnected = new bool[MaxGamePadInputs];
if (_game.Services.GetService(typeof(IInputState)) != null)
{
throw new ArgumentException("An Input State class is already registered.");
}
// Once the InputState class has been initialized, then register the current instance with the Game Services registry.
_game.Services.AddService(typeof(IInputState), this);
}
///
/// Reads the latest state of the keyboard, gamepads and touch.
///
public void Update()
{
LastKeyboardState = CurrentKeyboardState;
CurrentKeyboardState = Keyboard.GetState();
GamePadsAvailable = false;
for (int i = 0; i < MaxGamePadInputs; i++)
{
LastGamePadStates[i] = CurrentGamePadStates[i];
CurrentGamePadStates[i] = GamePad.GetState((PlayerIndex)i);
// Keep track of whether a gamepad has ever been
// connected, so we can detect if it is unplugged.
if (CurrentGamePadStates[i].IsConnected)
{
GamePadsAvailable = true;
GamePadWasConnected[i] = true;
}
}
TouchState = TouchPanel.GetState();
Gestures.Clear();
while (TouchPanel.IsGestureAvailable)
{
Gestures.Add(TouchPanel.ReadGesture());
}
}
///
/// Helper for checking if a key was pressed during this update.
///
private bool IsKeyPressed(Keys key)
{
return CurrentKeyboardState.IsKeyDown(key);
}
///
/// Helper for checking if a key was newly pressed during this update.
/// Key is pressed this frame but was not previously pressed.
///
private bool IsNewKeyPress(Keys key)
{
return (CurrentKeyboardState.IsKeyDown(key) &&
LastKeyboardState.IsKeyUp(key));
}
///
/// Helper for checking if a key was held down during this update,
/// Key is pressed this frame and was already pressed.
///
private bool IsKeyHeld(Keys key)
{
return (CurrentKeyboardState.IsKeyDown(key) &&
LastKeyboardState.IsKeyDown(key));
}
///
/// Helper for checking if a key was released during this update,
/// Key is not pressed this frame but was previously pressed.
///
private bool IsKeyReleased(Keys key)
{
return (CurrentKeyboardState.IsKeyUp(key) &&
LastKeyboardState.IsKeyDown(key));
}
///
/// Helper for checking if a button was pressed during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
///
private bool IsButtonPressed(Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
// This should not happen, but if you request input from a player that is not connected, this will safely return false.
// It could not have been pressed because the player is not connected.
if (i > MaxGamePadInputs)
{
return false;
}
return CurrentGamePadStates[i].IsButtonDown(button);
}
else
{
// Accept input from any player.
return (IsButtonPressed(button, PlayerIndex.One, out playerIndex) ||
IsButtonPressed(button, PlayerIndex.Two, out playerIndex) ||
IsButtonPressed(button, PlayerIndex.Three, out playerIndex) ||
IsButtonPressed(button, PlayerIndex.Four, out playerIndex));
}
}
///
/// Helper for checking if a button was newly pressed during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
///
private bool IsNewButtonPress(Buttons button, PlayerIndex? controllingPlayer,
out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
if (i > MaxGamePadInputs)
{
return false;
}
return (CurrentGamePadStates[i].IsButtonDown(button) &&
LastGamePadStates[i].IsButtonUp(button));
}
else
{
// Accept input from any player.
return (IsNewButtonPress(button, PlayerIndex.One, out playerIndex) ||
IsNewButtonPress(button, PlayerIndex.Two, out playerIndex) ||
IsNewButtonPress(button, PlayerIndex.Three, out playerIndex) ||
IsNewButtonPress(button, PlayerIndex.Four, out playerIndex));
}
}
///
/// Helper for checking if a button was newly pressed during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
///
private bool IsButtonHeld(Buttons button, PlayerIndex? controllingPlayer,
out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
if (i > MaxGamePadInputs)
{
return false;
}
return (CurrentGamePadStates[i].IsButtonDown(button) &&
LastGamePadStates[i].IsButtonDown(button));
}
else
{
// Accept input from any player.
return (IsButtonHeld(button, PlayerIndex.One, out playerIndex) ||
IsButtonHeld(button, PlayerIndex.Two, out playerIndex) ||
IsButtonHeld(button, PlayerIndex.Three, out playerIndex) ||
IsButtonHeld(button, PlayerIndex.Four, out playerIndex));
}
}
///
/// Helper for checking if a button was newly pressed during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
///
private bool IsButtonReleased(Buttons button, PlayerIndex? controllingPlayer,
out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
if (i > MaxGamePadInputs)
{
return false;
}
return (CurrentGamePadStates[i].IsButtonUp(button) &&
LastGamePadStates[i].IsButtonDown(button));
}
else
{
// Accept input from any player.
return (IsButtonReleased(button, PlayerIndex.One, out playerIndex) ||
IsButtonReleased(button, PlayerIndex.Two, out playerIndex) ||
IsButtonReleased(button, PlayerIndex.Three, out playerIndex) ||
IsButtonReleased(button, PlayerIndex.Four, out playerIndex));
}
}
///
/// Helper for checking the state of the left thumbstick during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
/// If no connected gamepad found, it will return Vector2.Zero
///
public Vector2 GetThumbStickLeft(PlayerIndex? controllingPlayer)
{
PlayerIndex playerIndex;
return GetThumbStickLeft(controllingPlayer, out playerIndex);
}
///
/// Helper for checking the state of the left thumbstick during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
/// If no connected gamepad found, it will return Vector2.Zero
///
public Vector2 GetThumbStickLeft(PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
return CurrentGamePadStates[i].ThumbSticks.Left;
}
else
{
for (int i = 0; i < MaxGamePadInputs; i++)
{
if (CurrentGamePadStates[i].IsConnected)
{
playerIndex = (PlayerIndex)i;
return CurrentGamePadStates[i].ThumbSticks.Left;
}
}
playerIndex = PlayerIndex.One;
return Vector2.Zero;
}
}
///
/// Helper for checking the state of the left thumbstick during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
/// If no connected gamepad found, it will return Vector2.Zero
///
public Vector2 GetThumbStickRight(PlayerIndex? controllingPlayer)
{
PlayerIndex playerIndex;
return GetThumbStickRight(controllingPlayer, out playerIndex);
}
///
/// Helper for checking the state of the right thumbstick during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
/// If no connected gamepad found, it will return Vector2.Zero
///
public Vector2 GetThumbStickRight(PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
return CurrentGamePadStates[i].ThumbSticks.Right;
}
else
{
for (int i = 0; i < MaxGamePadInputs; i++)
{
if (CurrentGamePadStates[i].IsConnected)
{
playerIndex = (PlayerIndex)i;
return CurrentGamePadStates[i].ThumbSticks.Right;
}
}
playerIndex = PlayerIndex.One;
return Vector2.Zero;
}
}
///
/// Helper for checking the state of the left trigger during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
/// If no connected gamepad found, it will return Vector2.Zero
///
public float GetTriggerLeft(PlayerIndex? controllingPlayer)
{
PlayerIndex playerIndex;
return GetTriggerLeft(controllingPlayer, out playerIndex);
}
///
/// Helper for checking the state of the left trigger during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
/// If no connected gamepad found, it will return Vector2.Zero
///
public float GetTriggerLeft(PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
return CurrentGamePadStates[i].Triggers.Left;
}
else
{
for (int i = 0; i < MaxGamePadInputs; i++)
{
if (CurrentGamePadStates[i].IsConnected)
{
playerIndex = (PlayerIndex)i;
return CurrentGamePadStates[i].Triggers.Left;
}
}
playerIndex = PlayerIndex.One;
return 0;
}
}
///
/// Helper for checking the state of the right trigger during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
/// If no connected gamepad found, it will return Vector2.Zero
///
public float GetTriggerRight(PlayerIndex? controllingPlayer)
{
PlayerIndex playerIndex;
return GetTriggerRight(controllingPlayer, out playerIndex);
}
///
/// Helper for checking the state of the right trigger during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
/// If no connected gamepad found, it will return Vector2.Zero
///
public float GetTriggerRight(PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
return CurrentGamePadStates[i].Triggers.Right;
}
else
{
for (int i = 0; i < MaxGamePadInputs; i++)
{
if (CurrentGamePadStates[i].IsConnected)
{
playerIndex = (PlayerIndex)i;
return CurrentGamePadStates[i].Triggers.Right;
}
}
playerIndex = PlayerIndex.One;
return 0;
}
}
public bool PlayerExit(PlayerIndex? controllingPlayer)
{
return IsNewKeyPress(Keys.Escape) ||
IsNewButtonPress(Buttons.Back, controllingPlayer, out _);
}
public bool StartGame(PlayerIndex? controllingPlayer)
{
return IsNewKeyPress(Keys.Enter) ||
IsNewButtonPress(Buttons.Start, controllingPlayer, out _);
}
public float GetPlayerTurn(PlayerIndex? controllingPlayer)
{
float turnAmount = 0;
Vector2 thumbstickValue = GetThumbStickLeft(controllingPlayer);
if (IsKeyHeld(Keys.A))
{
turnAmount = 1;
}
else if (IsKeyHeld(Keys.D))
{
turnAmount = -1;
}
else if (thumbstickValue.X != 0)
{
turnAmount = -thumbstickValue.X;
}
return turnAmount;
}
public Vector3 GetPlayerMove(PlayerIndex? controllingPlayer)
{
Vector3 movement = Vector3.Zero;
Vector2 thumbstickValue = GetThumbStickLeft(controllingPlayer);
if (IsKeyHeld(Keys.W))
{
movement.Z = 1;
}
else if (IsKeyHeld(Keys.S))
{
movement.Z = -1;
}
else if (thumbstickValue.Y != 0)
{
movement.Z = thumbstickValue.Y;
}
return movement;
}
}
}