A simple input manager for xNa
For personal use only, do not reprint, do not use for any commercial purposes.
(Update on 4.28 09: This articleArticleThere are bugs in the design. For detailed updates, refer to here)
Why we need input manager? On the PC platform, keyboardstate and mousestate provide basic user input information, but there are still several key functions missing for the actual preparation of the game. First, these two classes can only pull data, but cannot actively push data. That is to say, the client needs to explicitly query the status of a key, the customer cannot be notified when the key status changes. Second, the values returned by iskeydown and iskeyup are not as expected. For a common keydown event, it is triggered only when the key is pressed for the first time. For example, when we press the key at T1, The keydown event is triggered until T2, the keydown event should not be triggered even if the button is still pressed. For iskeydown, true is always returned whenever the key is pressed, and iskeyup has the same behavior. I am used to turning the iskeydown of xNa into pressing, and turning the event triggered only when the first state change of the button into keydown or keyup. Finally, it is a common operation to query how long a key has been pressed.
Based on the above discussion, the input manager is actually a simple class and only needs the following features:
1. Support both push and pull models
2. The following events are supported: keydown, keyup, keypressing, mousedown, mouseup, mousepressing, mousemove, and mousewheel. Most events receive a void genericeventhandle <t> (T); Type delegate
3. query the time when a key is pressed.
We can immediately write the input manger interface:
The implementation is also very simple, saving the current and last updated keyboard and mouse status. The game master calls update cyclically. Each time the update is updated, all keys are iterated. Check whether the status changes and trigger corresponding events. To support Time query, A dirctionay is used to record the time when each key is pressed.
There are two points to note: First, do not use the foreach + enum. getvalues (typeof (KEYS) method to update the key status during iteration. Getvalues is a relatively slow operation based on reflection. You can try to save all the enumerated values to a normal array, and iterate the array to traverse all the keys much faster. In addition, do not use Enum as the key to record the dirctionay of each key time. The enum type is used as the key and needs to be packed. Converting Enum to int and then using it as dirctionay's key value can greatly improve the performance.
Of course, there is another potential problem. How fast should I update the input status? As mentioned above, calling Update () in the main loop of the game means that for xNa games with isfixedtimestep being true, it will be updated 60 times per second. For games with isfixedtimestep being false, based on the actual situation, it is possible to update dozens or hundreds of times per second. Is the problem that we need to update so many times per second? At present, the world record of keyboard typing speed is about 800 times per minute, that is, 13 times per second. I did not find the world record of Mouse clicking speed, but I tested the following, 6 ~ Eight clicks are already the limit speed. According to the nequest sampling theorem, as long as the sampling frequency is twice the highest frequency of the signal, the information in the original signal can be fully retained, that is, even if you are the World Champion, 30 updates per second are enough to capture all your input. As shown in the preceding figure, you can set the update frequency of the keyboard and mouse keys and the trigger frequency of the mouse movement event. ThereforeCodeIt may look like this:
-
- Public VoidUpdate (gametime)
-
- {
-
- FloatElapsedtime = (Float) (Gametime. elapsedgametime. totalseconds );
- Keyboardupdatecount + = elapsedtime;
-
- Mousebuttonupdatecount + = elapsedtime;
-
- Mousemoveupdatecount + = elapsedtime;
-
- If(Keyboardupdatecount> = keyboardupdateinterval)
-
- {
-
- // Update keyboard state, fire keyboard event
-
- Keyboardupdatecount = 0;
-
- }
- If(Mousebuttonupdatecount> = mousebuttonupdateinterval)
-
- {
-
- // Update mouse state, fire mouse event
-
- Mousebuttonupdatecount = 0;
-
- }
-
- If(Mousemoveupdatecount> = mousemoveupdateinterval)
-
- {
-
- // Update mouse position, fire mouse move event if needed
- Mousemoveupdatecount = 0;
-
- }
-
- }
You can note that the input manager has an active attribute. The reason is that when the xNa game loses focus, keyboardstate and mousestate can still capture user input, which is obviously unnecessary for most games, so when the game loses focus, we will set the active attribute of input manager to false to stop updating input.
Next work
finally, all the keyboard messages returned by keyboardstate are values enumerated by keys. If you want to write a text box, user input is allowed. The enumerated values must be converted to corresponding characters. The detailed implementation may be very complicated. You need to consider whether shift-down or Caps Lock is enabled, or you want to map each Keyboard Message to a message in the game. Then you may need to create an inputmessagetranslator and other things on top of the input manage.