作者:事过人空 | 来源:互联网 | 2023-01-02 13:24
统一输入接口目前我们已经会怎样和输入硬件通信的基本方法(Nowthatwehavethebasicsdownonhowtocommunicatewiththeinputha
统一输入接口
目前我们已经会怎样和输入硬件通信的基本方法(Now that we have the basics down on how to communicate with the input hardware),是时候把这些信息整合进游戏引擎了。游戏引擎只有一个类,封装了三种输入设备,并为游戏提供了一个统一的接口。这个类,我们把它叫做GameInput,从IDisposable接口继承而来。此接口定义了一个Dispose方法,提供清除函数,在C++里一般是析构函数。此类的构造函数会创建所有的输入设备,并只接受一个参数,即前面提到过的应用程序的窗口句柄。
虽然我们可以强加让游戏在游戏循环里查询GameInput来取得击键,但是有更好的方式:我们可以使用action映射。Action映射把一个键盘的键或者鼠标的按钮与一个指定的函数相关联。在每帧里有键或者按钮被按下(或者按下的状态被改变)则调用特定的函数。这让输入系统基于事件而不是基于查询,这会提供效率。DirectInput有内建的action映射功能。我们这个游戏引擎实现了分离的action映射系统,目的是示范action映射究竟是如何工作的。一旦你理解了其中的思想,只要你喜欢你可以直接使用微软内置的版本。
Action映射里的每一个实体包含mapping结构或者axis mapping结构的实例,如列表2-2所示:
列表:Mapping结构
struct Mapping
{
public int key;
public ButtonAction action;
public bool bOnTransition;
}
struct AxisMapping
{
public int key;
public AxisAction action;
}
结构中的key是索引,是键盘状态数据或者鼠标按钮数据,指示了控制action映射到什么上。开头的256个值表示键盘实体,接下来的8个是表示鼠标按钮,最后的32个是表示操纵杆按钮。ButtonAction委托(delegate)表示一个不需要参数也没有返回值的函数。此函数通常用来在游戏中执行一些动作,例如移动主角,开火或者游戏开发者想做的其他动作。AxisAction委托(delegate)使用这个数据为此轴每一帧都被调用。两个委托的定义如下:
public delegate void ButtonAction();
public delegate void AxisAction(int nCount);
类GameInput的公开方法如列表2-3所示。我将在随后的几页里为这些方法提供简短的说明。如果你对实现的细节有兴趣,请参考GameInput.cs 源文件(源代码的一部分,可以从Apress Web网站下载 http://www.apress.com)
列表2.3:GameInput方法列表
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()
Poll方法被游戏应用每一帧调用一次。此方法测试每一个硬件设备来取得输入,然后它检查action映射里的每个实体,看是否有被映射的函数需要被调用。如果是,则调用函数来响应玩家的动作。对于一个特殊的轴action的情况呢,函数则使用轴的当前值调用自己(In the case of the actions for a particular axis, the functions are called every time with the current value for that axis)。列表2-4中的这段代码位于Poll方法中,用来处理action映射。
列表2.4:action映射处理
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] )
var cpro_id = "u6885494";