#region File Description //----------------------------------------------------------------------------- // InputAction.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #endregion using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; namespace GameStateManagement { /// /// Defines an action that is designated by some set of buttons and/or keys. /// /// The way actions work is that you define a set of buttons and keys that trigger the action. You can /// then evaluate the action against an InputState which will test to see if any of the buttons or keys /// are pressed by a player. You can also set a flag that indicates if the action only occurs once when /// the buttons/keys are first pressed or whether the action should occur each frame. /// /// Using this InputAction class means that you can configure new actions based on keys and buttons /// without having to directly modify the InputState type. This means more customization by your games /// without having to change the core classes of Game State Management. /// public class InputAction { private readonly Buttons[] buttons; private readonly Keys[] keys; private readonly bool newPressOnly; // These delegate types map to the methods on InputState. We use these to simplify the evalute method // by allowing us to map the appropriate delegates and invoke them, rather than having two separate code paths. private delegate bool ButtonPress(Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex player); private delegate bool KeyPress(Keys key, PlayerIndex? controllingPlayer, out PlayerIndex player); /// /// Initializes a new InputAction. /// /// An array of buttons that can trigger the action. /// An array of keys that can trigger the action. /// Whether the action only occurs on the first press of one of the buttons/keys, /// false if it occurs each frame one of the buttons/keys is down. public InputAction(Buttons[] buttons, Keys[] keys, bool newPressOnly) { // Store the buttons and keys. If the arrays are null, we create a 0 length array so we don't // have to do null checks in the Evaluate method this.buttons = buttons != null ? buttons.Clone() as Buttons[] : new Buttons[0]; this.keys = keys != null ? keys.Clone() as Keys[] : new Keys[0]; this.newPressOnly = newPressOnly; } /// /// Evaluates the action against a given InputState. /// /// The InputState to test for the action. /// The player to test, or null to allow any player. /// If controllingPlayer is null, this is the player that performed the action. /// True if the action occurred, false otherwise. public bool Evaluate(InputState state, PlayerIndex? controllingPlayer, out PlayerIndex player) { // Figure out which delegate methods to map from the state which takes care of our "newPressOnly" logic ButtonPress buttonTest; KeyPress keyTest; if (newPressOnly) { buttonTest = state.IsNewButtonPress; keyTest = state.IsNewKeyPress; } else { buttonTest = state.IsButtonPressed; keyTest = state.IsKeyPressed; } // Now we simply need to invoke the appropriate methods for each button and key in our collections foreach (Buttons button in buttons) { if (buttonTest(button, controllingPlayer, out player)) return true; } foreach (Keys key in keys) { if (keyTest(key, controllingPlayer, out player)) return true; } // If we got here, the action is not matched player = PlayerIndex.One; return false; } } }