In my last post I talked about controls and the control structure within the Tales Framework. In this post I will go over the input handling. The two most important ideas to understand are a) input gestures, which represent things like button presses, and b) how focus impacts input handling.
Input Gestures
When building a GameControl that takes input you need to bind a method to one or more input gestures that implement the IInputGesture interface.
The IInputGesture interface looks like this:
public interface IInputGesture {
bool MatchGesture( PlayerIndex thePlayerIndex, GameTime theGameTime );
}
A gesture’s MatchGesture method simply checks some state, like a pressed button, for the specified player and if the state is true the method returns true.
For example, this is a simple gesture that detects if a button was literally just pressed:
public class ButtonDownGesture : IInputGesture {
private readonly Buttons _buttons;
public ButtonDownGesture( Buttons theButtons ) {
_buttons = theButtons;
}
public Buttons Buttons {
get {
return _buttons;
}
}
public bool MatchGesture(
PlayerIndex thePlayerIndex,
GameTime theGameTime ) {
bool returnValue = false;
int index = ( int )thePlayerIndex;
if( InputManager.CurrentGamePadStates[ index ].IsButtonDown( _buttons ) &&
InputManager.PreviousGamePadStates[ index ].IsButtonUp( _buttons ) ) {
returnValue = true;
}
return returnValue;
}
}
The MatchGesture method uses the InputManager. The InputManager stores the current and previous states for gamepads and keyboards.
Developers can create their own gestures but the framework includes the critical gestures. There are simple gestures for detecting that a gamepad button or key was just pressed or just released, and there is support for more complicated gestures that only return true periodically while a user holds a button or key down.
Binding Gestures
So how do you use gestures in your controls or menus? GameControl has a protected method called BindGestures that takes a delegate and set of IInputGestures. By default the framework will automatically call the MatchGesture methods on the bound gestures and if one of the gestures indicates a match the delegate is called. Advanced framework users can also manually check gestures by using the InputManager.
This snippet of code from a sample spinner control shows the binding of gestures.
public class SampleSpinner : MenuItem {
protected override void InitializeInput( ) {
BindInputGestures(
this.HandlePrevValue,
new IInputGesture[] {
new ButtonDownGesture( Buttons.DPadLeft ),
new ButtonDownGesture( Buttons.LeftThumbstickLeft )
} );
BindInputGestures(
this.HandleNextValue,
new IInputGesture[] {
new ButtonDownGesture( Buttons.DPadRight ),
new ButtonDownGesture( Buttons.LeftThumbstickRight )
} );
}
protected void HandleNextValue(
GameControl theControl,
PlayerIndex thePlayer,
IInputGesture theGesture ) {
}
protected void HandlePrevValue(
GameControl theControl,
PlayerIndex thePlayer,
IInputGesture theGesture ) {
}
}
Input and Focus
Another important aspect of input, and making sure that your registered delegates are called, is understanding focus. The framework doesn’t call every single registered gesture for every single control, instead it checks the gestures for the controls that are in focus, and if a gesture isn’t matched it will traverse up through parent controls checking the registered gestures.
I said ‘checks the gestures for the controls that are in focus’. This implies more than one control can be in focus. This is true, however only one control can be in focus for each player. More details on this are discussed below in Advanced Focus.
To put a control in focus, you simply need to set its Focused property to true. Some of the high-level controls will automatically set the focus. For example, the ScreenManager will set the focus on Menus as they are made active while Menus will set the focus of MenuItems as a user moves between the menu options.
Advanced Focus
One of the advanced features for focus and input is the notion of FocusScope. While the default FocusScope will accept input from all players, you can create FocusScopes that control which players’ input will be accepted and processed. This means not only must a control be in focus, but a FocusScope must exist that allows input from the player. This is best explained with the following example.
It is common during game play that if a player hits the Start button the game will load a pause menu that pauses the game and only that same player can hit the Back button to close the pause menu. Input from other players is ignored.
This advanced ability can also be used to bind certain controls of a HUD to particular players in local multi-player games. If you want to use this ability I recommend you have a look at the FocusManager.
The above hopefully has given a good overview of input and focus handling. Additional posts regarding the framework will be coming soon.