Unified Input Interface


Now that we have the basics down on how to communicate with the input hardware, it is time to put this information into the context of the game engine. The game engine will have a single class that encapsulates the three input devices and provides a single unified interface to the game. This class, which we will call GameInput , will inherit from the IDisposable interface. This interface defines a Dispose method to provide the cleanup function normally programmed into the destructor in C++. The constructor for the class will create all of the input devices and will accept a single argument as mentioned earlier, the handle to the applications window.

Although we could force the game to query GameInput for each keystroke it needs every pass through the game loop, there is a better way: We could use an action map. An action map associates a keyboard key or mouse button with a specified function. In every frame which the key or button is pressed (or in the transition of being pressed) the function is called. This makes the input system event based rather than query based, which improves performance. Directlnput comes with built-in action mapping capability. This introductory game engine implements a separate action mapping system in order to demonstrate exactly how action mapping works under the covers. Once you understand the concepts, it is straightforward to use Microsoft s imbedded version if you prefer.

Each entry in the action map consists of an instance of the mapping structure or the axis mapping structure shown in Listing 2 “2.

Listing 2.2: Mapping Structures
start example
 struct Mapping  {     public int key;     public ButtonAction action;     public bool bOnTransition;  }  struct AxisMapping  {     public int key;     public AxisAction action;  } 
end example
 

The key is an index into the keyboard state data or the mouse button data to indicate which control the action is mapped against. The first 256 values represent keyboard entries and the next 8 are for mouse buttons. The last 32 values are for joystick buttons . The ButtonAction delegate represents a function that takes no arguments and returns no value. The function will typically perform some action within the game such as moving the protagonist, firing a weapon, or anything else the game developer decides that the player can do. The AxisAction delegate is called once per frame with the data for that axis. The definition of the two delegates is shown here:

 public delegate void ButtonAction();  public delegate void AxisAction(int nCount); 

The public methods of the GameInput class are shown in Listing 2 “3. I will be providing a brief explanation of the methods in the following pages. If you are interested in the details of the implementation, I refer you to the GameInput.cs source file (available as part of the source code, downloadable from the Apress Web site at http://www.apress.com).

Listing 2.3: GameInput Methods
start example
 GameInput(System.Windows.Forms.Form form)  void Poll()  bool IsMouseButtonDown( int nButton )  bool IsKeyPressed()  bool IsKeyPressed(Key key)  void MapKeyboardAction( Key key, ButtonAction proc, bool bTransition )  void MapMouseButtonAction( int nButton, ButtonAction proc, bool bTransition )  void MapJoystickButtonAction( int nButton, ButtonAction proc, bool bTransition )  void MapMouseAxisAction( int nAxis, AxisAction proc )  void MapJoystickAxisAction( int nAxis, AxisAction proc )  void UnMapKeyboardAction( Key key )  void UnMapMouseButtonAction( int nButton )  void UnMapJoystickButtonAction( int nButton )  void UnMapMouseAxisAction( int nAxis )  void UnMapJoystickAxisAction( int nAxis )  void ClearActionMaps()  Point GetMousePoint()  int GetMouseX()  int GetMouseY()  int GetMouseZ()  int GetJoystickX( )  int GetJoystickY( )  int GetJoystickNormalX( )  int GetJoystickNormalY( )  int GetJoystickZ( )  bool GetJoystickButton( int nIndex )  int GetJoystickSlider( int nIndex )  void Dispose() 
end example
 

The Poll method is called by the game application once per frame. This method polls each of the hardware devices for input. It then checks each entry in the action map to see if the mapped function needs to be called. If it does, the function is called to respond to the player s action. In the case of the actions for a particular axis, the functions are called every time with the current value for that axis. The code in Listing 2 “4 resides in the Poll method to process the action maps.

Listing 2.4: Action Map Processing
start example
 foreach ( AxisMapping map in m_AxisActionMap )  {     switch ( map.key )     {        case 0:           map.action(m_mousedata.X);           break;        case 1:           map.action(m_mousedata.Y);           break;        case 2:           map.action(m_mousedata.Z) ;           break;        case 3:           map.action(m_joystick.X);           break;        case 4:           map.action(m_joystick.X);           break;        case 5:           map.action(m_joystick.X);           break;     }  }  // Only process the action map if the console is not visible.  if ( !Game Engine.Console.IsVisible )  {     foreach ( Mapping map in m_ActionMap )     {        // If this mapping is against the keyboard        if ( map.key < 256 )        {            // take the action if the key is down or transitioning.           if ( m_keydata[(Key)map.key] )          {              if ( !map.bOnTransition   oldkeydata[(Key)map.key] )              {                 map.action();              }         }       }       else if ( map. key < 264 ) // Space for 8 mouse buttons        {           if ( (m_mousedata.GetMouseButtons()[map.key-256] & 080) != 0 )           {              if ( !map.bOnTransition                   (oldmousedata. GetMouseButtons() [map.key-256] & 080) == 0 )              {                 map.action();              }           }        }        else // joystick buttons        {           if ( (m_joystick.GetButtons()[map.key-264] & 080) != 0 )           {              if ( !map.bOnTransition                   (oldjoystickdata.Buttons[map.key-264] & 080) == 0 )              {                 map.action();              }           }        }     }  } 
end example
 

The Is and Get methods provide low-level access to the input data. If for some reason the game needs to explicitly check an input rather than use a mapped action, these are the methods that would be used.




Introduction to 3D Game Engine Design Using DirectX 9 and C#
Introduction to 3D Game Engine Design Using DirectX 9 and C#
ISBN: 1590590813
EAN: 2147483647
Year: 2005
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net