第二章 第五节 统一输入接口

统一输入接口

目前我们已经会怎样和输入硬件通信的基本方法(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.3GameInput方法列表

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.4action映射处理

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] & 0×80) != 0 )

         {

            if ( !map.bOnTransition | |

               (oldmousedata. GetMouseButtons() [map.key-256] & 0×80) == 0 )

            {

               map.action();

            }

         }

      }

      else // joystick buttons

      {

         if ( (m_joystick.GetButtons()[map.key-264] & 0×80) != 0 )

         {

            if ( !map.bOnTransition | |

               (oldjoystickdata.Buttons[map.key-264] & 0×80) == 0 )

            {

               map.action();

            }

         }

      }

   }

}

 

这些IsGet方法提供了访问输入数据的低层方式。如果因为某种原因,游戏需要显式的检查一个输入而不是使用映射的动作,这些方法就可以被使用。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值