The System object is used to access the system clock as well as the physical input devices that may or may not be used during the game (keyboard, mouse, joystick). Optionally, additional data items within the System object can handle other tasks as well, such as time adjustment and control interpretation. Those subjects will be discussed here.
Access to System Clock
Ability to Poll Common Input Devices
A special class can be used to retrieve the system time from the system (the ::timeGetTime() function works well - it requires that you include the mmsystem.h header file, and link winmm.lib in your executable). Once the system time is retrieved, what happens next depends on the special situations that might occur in your game.
Typically, you want to convert the system time into session time (see the discussion of the Network object for the distinction between system time and session time) and pass that on to your game tick as a parameter. But special circumstances might require a modification of the session time before it is passed.
Other things to consider to add more functionality to your session time submittal routine include the following:
Ability to Poll Common Input Devices
Naturally, in order for a game to be a game, the player must have a way to interact with what they see on the screen. The most common devices used for this purpose are the keyboard, mouse and joystick. A strong engine will allow all three of these devices to be used.
The DirectInput API is the best used for this purpose. Hide the DirectInput calls from the programmer and provide wrapper functions so that the system object can take care of itself. The programmer should never need to know about the DirectInput API once this object is set up.
Ultimately, the result of the polled controls result in the following:
To further complicate matters, some game designs might demand that while a text box is up that you are typing chat messages in, the arrow keys on the keyboard might be needed to maneuver your craft. As a result, it isn't enough to simply tell the System object what kind of operation a particular device is being used for. Rather, a device input map has to be prepared for every case. For example, you may tell the System object that all alphabetic keys and the space bar are to be used only for text entry. All the numeric keys are to be used exclusively to fire off menu controls (for buttons that might be hotkeyed, as an example), and the rest of the keys are to be routed to game effects. Your engine should offer some default possibilities for these maps, and allow the programmer to create their own that can be assigned to the devices. Once the maps are set up, you just tell the System object which map is currently active, and the code you write into the System object does the rest.
You should support clicks (a single "up" to "down" transition), double clicks (two presses in quick succession) and holding (is the control down or up?) of controls as boolean values. Keyboard keys and buttons meet this criteria. Mouse and Joystick axis values can be stored separately as numeric values. Special cases for axis conditions can also be set up, such as "Joystick pressed up" or "Mouse moved left", which would be stored as boolean values. It is important to use the control templates to guide the System object to determine if the given control should even be stored in the given device data. For example, if the 'A' key is pressed, and the template map says that 'A' is a hotkey for a menu control, then it will NOT be submitted into this boolean array. Instead, it will be sent as a message ('A' keydown) to the menu system to be decoded there. Also, the delay for double clicks should be variable, with a default value initialized. The elapsed time between control clicks (NOT adjusted at all for slow motion, fast motion or catchup!) is used to detect the double clicked event. After a game tick is done and all controls are interpreted, all click and double click boolean values should be cleared.
The boolean values are important to detect game events. Once the boolean values are set up, another array that keeps track of exactly which boolean values to look at for game effects is used to determine which game effects are taking place. "Jump" might be keyed to the space bar, so that slot has a pointer that points to the boolean value in the keyboard array that holds whether or not the space bar has been clicked. It is possible that more than one value could throw off the same effect, so you should support multiple slots of boolean pointers and just OR the values together to see if any of the controls are activated for that game event.
It is possible for a single control to have multiple effects with different states. For example, in TIE Fighter, the second joystick button, when clicked, allows you to target the craft straight ahead. When the same button is held, it allow the craft to spin when the joystick is pressed left or right, while up and down affects the throttle. The design I've mentioned supports this feature. One game event, "Target click", is keyed to the boolean value "Second Joystick Button Clicked". Another game event, "Joystick Button 2 Mod", is keyed to the boolean value "Second Joystick Button Held".
The Mouse and Joystick values, along with any other values affected by the game events, can be referred to by the rest of the game engine to throw off other effects, such as the maneuvering of a craft. Only the mouse or joystick axis values should be used, never both - take the greater of the two, store the value in a separate location, and use THAT for your adjustment. Code that logic in the meat of your game engine, not the System object.
If there is a special key combination you want to set up for minimizing the application (such as Ctrl-Esc), check for that first before anything else. It takes precedence no matter what the mapping is.
Finally, there is the matter of making modification of the game event array possible, so that an interface screen for the user can be set up to map the game event keys as they wish. This may require some decoding of the game events, keys and controls into string names for display. Just something more to keep in mind, in case all this wasn't enough already!! The game event keying off a clicked, double clicked or held event should be hard coded into your game event. Only the source control for the event can be modified. That is, the "Run Forward" event could be keyed to 'A', the left mouse button, or the second joystick button if you wish, but it will ALWAYS be a HELD condition, and should not modifiable by the user. It is possible, I suppose to allow the user to configure a control for "clicked" or "double clicked" functionality so they can truly program their own custom set of controls, but the "held" conditions should not be changed to anything else. Your interface will determine what is possible, of course.