Written by: Thursday, May 12, 2011
In the last post, we introduced the (still empty) input service interface. Now it is time to add a few functions. This blog post describes
Using the XNA classes Keyboard, Mouse, and GamePad, we can get the device state (e.g. KeyboardState) and can check if a key or button is currently pressed or released. But we cannot directly query whether a key or button was released in the last frame and pressed down in this frame. And we cannot simply query if a button click belongs to a double-click.
Therefore, the input service provides methods to check if a button is down, up, pressed, or released:
The method parameter will be a button or a key, e.g.
bool IsReleased(Keys key);
XNA provides enumerations for Keys and gamepad Buttons, but not for mouse buttons – so this enumeration is a useful addition:
public enum MouseButtons { Left, Middle, Right, XButton1, XButton2, }
The implementation of IsDown and IsUp is easy: We simply check the button state in the current device state. For IsPressed and IsReleased, we also have to check the device state of the last frame. The device states are retrieved and stored in InputManager.Update().
To detect double-clicks, InputManager.Update() must check all keys and buttons remembers the last pressed key/button and when it was pressed. If the same button is pressed again within a certain time limit, then we have a double-click. (Note: A click that was part of a double-click cannot be part of a second double-click. That means, if a button is pressed 3 times, we have a double-click followed by a single-click – not 2 double-clicks.)
Key repetition is useful for keys in text boxes and for buttons in game menus:
To support key repetition, the IsPressed() methods have a second parameter, e.g.
bool IsPressed(Keys key, bool useKeyRepetition);
If the second parameter is true, IsPressed returns true when the key was pressed down in this frame or when the key was pressed down long enough for key repetition. Every component, which processes input, can decide whether key repetition should be used.
In InputManager.Update() we already remember the last pressed keys and buttons and the press-time to detect double-clicks. The same information can be used to decide when to create virtual key presses.
Using the XNA MouseState, it is easy to get the absolute mouse position (relative to the game window). In some games, we are only interested in relative mouse movements, for example in first-person-shooter games where the relative mouse change is used to rotate the view. We get the relative mouse position simply be subtracting the mouse position of the last frame.
But this approach is limited – namely by the screen limits. The mouse cursor cannot be moved out of the screen and once the mouse cursor has reached, for instance, the left screen border, the mouse X position will not change if the user tries to move the mouse more to the left. This is not acceptable in a first-person-shooter game. To avoid this, we must make sure that the mouse has enough room to move in all directions in each frame. Therefore, InputManager.Update() resets the mouse position in each frame. We can set the mouse position to the center of the game window, or simply to fixed “mouse center”:
public void Update(float deltaTime) { … if (EnableMouseCentering) Mouse.SetPosition((int)Settings.MouseCenter.X, (int)Settings.MouseCenter.Y); }
And the input service computes the relative mouse position when we need it:
public Vector2F MousePositionDeltaRaw { get { if (EnableMouseCentering) return new Vector2F(_newMouseState.X - Settings.MouseCenter.X, _newMouseState.Y - Settings.MouseCenter.Y); else return new Vector2F(_newMouseState.X - _previousMouseState.X, _newMouseState.Y - _previousMouseState.Y); } }
In the next blog posts, we will discuss how we are
The full input service with documentation and class diagrams is available with our DigitalRune Game UI library.
0 comment(s) so far...
A collection of the most useful blog articles can be found here:
Article Collection (on Documentation page)
DigitalRune is a trademark of Garstenauer Information Technology OG.
Garstenauer Information Technology OG Weingartenstrasse 35, 4452 Ternberg Austria (EUROPE) office@digitalrune.com