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; } } }