2010年2月27日星期六

C++开发游戏手柄代码 (Developing the Joystick Code)

还是坚持每周一博,照例写正文前废话一段:最近天气越来越好,不下雪了,偶尔下点雨,下了一次冰雹,但可以看到10+的温度了,晚上6点坐车回家的时候天还是是微亮。哈,德国的春天终于来了。
迫于项目时间的压力,项目只剩下最后一周的时间,本周的工作效率还不错,写了非常多的代码,突然发现,我最近最能集中心力,最具生产力的时段是下午5到6点,就是回家前一个小时,似乎所有最有创造力的生产和想法都是在这个小时产生的,很奇怪。最近,所里的咖啡机又坏了,苦了很多人,有一个意大利同事对我说说,没有咖啡就不能Coffee in, Code out,没法编程了。还好我不喝咖啡,每天只喝茶,所里提供的各种奇怪的茶包(德国的茶包的种类真是多的恐怖,各种奇怪的口味都有,喝过一种咖喱口味的茶)。

好了闲话不多谈,今天谈谈关于游戏手柄joystick的代码开发,最近接触了一些多媒体子系统的Win32 API,其实非常容易,通过一些google可以找到非常多的源代码和示例代码,可以非常快的利用多媒体的Win32 API开发出一些很有趣的东西,游戏手柄joystick代码开发就是一个很经典的例子。支持游戏手柄现在是一个Win32的标准的一部分,多媒体子系统单独的Win32 API,其中支持游戏手柄是一个组成部分。但是关于游戏手柄的功能和数据结构没有定义在标准windows.h头文件,而是位于mmsystem.h中头文件。
上代码之前,一些说明:

[1]

要使用游戏手柄的Win32 API
#include <windows.h>
#include <mmsystem.h>

编译器请使用VS2005以上版本。

[2]

当然了不要忘记加入winmm.lib

[3]

JOYSTATE数据类型包括描述游戏手柄的State
例如

1: typedef WORD JOYSTATE; 
2: const JOYSTATE JOY_NONE = 0x0000L, 
3: JOY_LEFT = 0x0001L, 
4: JOY_RIGHT = 0x0002L, 
5: JOY_UP = 0x0004L, 
6: JOY_DOWN = 0x0008L,


[4]

我们要做的事就是,写出以下方法:

BOOL InitJoystick(); 
void CaptureJoystick(); 
void ReleaseJoystick(); 
void CheckJoystick();

 

[5]

CaptureJoystick()ReleaseJoystick()的方法就是使用使用两个Win32 functions就是:joySetCapture()joyReleaseCapture()
JOYINFO structure用于检索游戏手柄状态通过joyGetPos() function。

[6]

以下代码结合了Qt,也可以不需要Qt运行,只需要删除Qt部分的代码即可,使用了Qt的signal slot机制,利用了QTime的timeout()不断对CheckJoystick()进行调用,以及时更新Joystick状态。

[7]

BTP_Joystick以下的代码的主体部分来自网上的一些示例代码,我进行了一些修改和裁剪,编译和使用没有任何问题,我使用的是北通小手柄 BTP-C024 USB游戏手柄(如附图所示)进行测试,运行很好。以下代码非常简单,应该很容易理解,不要问我,为什么不能用,或者如何使用,如果不能用,请google或再看看代码(你已经有了完整的代码),呵呵。

 

 

 

 

/*
 * \file GameEngine.h
 * \class GameEngine
 * \date   2010
 * \bug
 * \warning
 *
 */

10 #ifndef GAMEENGINE_H_
11 #define GAMEENGINE_H_
12
13 #include <QtGui>
14
15 #include <windows.h>
16 #include <mmsystem.h>
17
18 //-----------------------------------------------------------------
19 // Joystick Flags
20 //-----------------------------------------------------------------
21 typedef WORD    JOYSTATE;
22 const JOYSTATE  JOY_NONE  = 0x0000L,
23                 JOY_LEFT  = 0x0001L,
24                 JOY_RIGHT = 0x0002L,
25                 JOY_UP    = 0x0004L,
26                 JOY_DOWN  = 0x0008L,
27                 JOY_FIRE1 = 0x0010L,
28                 JOY_FIRE2 = 0x0020L,
29                 JOY_FIRE3 = 0x0030L,
30                 JOY_FIRE4 = 0x0040L;
31
32 class GameEngine : public QObject
33 {
34     Q_OBJECT
35
36 public:
37
38     GameEngine();
39     ~GameEngine();
40
41     void HandleJoystick(JOYSTATE jsJoystickState);
42    
43     BOOL InitJoystick();
44     void CaptureJoystick();
45     void ReleaseJoystick();
46    
47     UINT m_uiJoystickID;
48     RECT m_rcJoystickTrip;
49     HWND m_hWindow;
50
51 protected:
52
53 private slots:
54     void CheckJoystick();
55
56 signals:
57     void joystickLeft();
58     void joystickRight();
59     void joystickUp();
60     void joystickDown();
61     void joystickButton1();
62     void joystickButton2();
63     void joystickButton3();
64     void joystickButton4();
65
66 private:
67     QTimer *_poller;
68
69 };
70
71 #endif /* GAMEENGINE_H_ */

 

1   /*
2    * \file GameEngine.cpp
3    * \class GameEngine
4    * \date   2010
5    * \bug
6    * \warning
7    *
8    */
9  
10  #include <QDebug>
11 
12  #include "GameEngine.h"
13 
14 
15  GameEngine::GameEngine()
16  {
17   
18      InitJoystick();
19      CaptureJoystick();
20 
21      //start timer to trigger every 100 ms 
22      _poller = new QTimer(this);
23      connect(_poller, SIGNAL(timeout()), this, SLOT(CheckJoystick()));
24      _poller->start(100); 
25  }
26 
27  GameEngine::~GameEngine()
28  {
29 
30  }
31 
32  BOOL GameEngine::InitJoystick()
33  {
34      // Make sure joystick driver is present
35      UINT uiNumJoysticks;
36      if ((uiNumJoysticks = joyGetNumDevs()) == 0)
37          return FALSE;
38 
39      // Make sure the joystick is attached
40      JOYINFO jiInfo;
41      if (joyGetPos(JOYSTICKID1, &jiInfo) != JOYERR_UNPLUGGED)
42          m_uiJoystickID = JOYSTICKID1;
43      else
44          return FALSE;
45     
46      // Calculate the trip values
47      JOYCAPS jcCaps;
48      joyGetDevCaps(m_uiJoystickID, &jcCaps, sizeof(JOYCAPS));
49      DWORD dwXCenter = ((DWORD)jcCaps.wXmin + jcCaps.wXmax) / 2;
50      DWORD dwYCenter = ((DWORD)jcCaps.wYmin + jcCaps.wYmax) / 2;
51      m_rcJoystickTrip.left = (jcCaps.wXmin + (WORD)dwXCenter) / 2;
52      m_rcJoystickTrip.right = (jcCaps.wXmax + (WORD)dwXCenter) / 2;
53      m_rcJoystickTrip.top = (jcCaps.wYmin + (WORD)dwYCenter) / 2;
54      m_rcJoystickTrip.bottom = (jcCaps.wYmax + (WORD)dwYCenter) / 2;
55      return TRUE;
56  }
57 
58  void GameEngine::CaptureJoystick()
59  {
60      // Capture the joystick
61      if (m_uiJoystickID == JOYSTICKID1)
62      {
63         joySetCapture(m_hWindow, m_uiJoystickID, NULL, TRUE);
64          qDebug() << " Capture Joystick success!";
65      }
66  }
67 
68  void GameEngine::ReleaseJoystick()
69  {
70      // Release the joystick
71      if (m_uiJoystickID == JOYSTICKID1)
72      joyReleaseCapture(m_uiJoystickID);
73  }
74 
75  void GameEngine::CheckJoystick()
76  {
77  if (m_uiJoystickID == JOYSTICKID1)
78  {
79     JOYINFO jiInfo;
80     JOYSTATE jsJoystickState = 0;
81     if (joyGetPos(m_uiJoystickID, &jiInfo) == JOYERR_NOERROR)
82     {
83          // Check horizontal movement
84          if (jiInfo.wXpos < (WORD)m_rcJoystickTrip.left)
85              jsJoystickState |= JOY_LEFT;
86            else if (jiInfo.wXpos > (WORD)m_rcJoystickTrip.right)
87              jsJoystickState |= JOY_RIGHT;
88             // Check vertical movement
89             if (jiInfo.wYpos < (WORD)m_rcJoystickTrip.top)
90              jsJoystickState |= JOY_UP;
91             else if (jiInfo.wYpos > (WORD)m_rcJoystickTrip.bottom)
92              jsJoystickState |= JOY_DOWN;
93             // Check buttons
94             if(jiInfo.wButtons & JOY_BUTTON1)
95              jsJoystickState |= JOY_FIRE1;
96             if(jiInfo.wButtons & JOY_BUTTON2)
97              jsJoystickState |= JOY_FIRE2;
98          if(jiInfo.wButtons & JOY_BUTTON3)
99              jsJoystickState |= JOY_FIRE3;
100         if(jiInfo.wButtons & JOY_BUTTON4)
101             jsJoystickState |= JOY_FIRE4;
102     }
103
104     // Allow the game to handle the joystick
105     HandleJoystick(jsJoystickState);
106     }
107 }
108
109 void GameEngine::HandleJoystick(JOYSTATE jsJoystickState)
110 {
111     //这里加入你自己对jsJoystickState的处理,以下只是极简单的示范
112     //通过HandleJoystick得到JOYSTATE
113    
114     //qDebug() << " get information about Joystick!" ;
115     if (jsJoystickState == JOY_UP)
116     {
117         qDebug() << " get Joystick -- JOY_UP!" ;   
118     }
119     else if (jsJoystickState == JOY_DOWN)
120     {
121         qDebug() << " get Joystick -- JOY_DOWN!" ;
122     }
123     else if (jsJoystickState == JOY_LEFT)
124     {
125         qDebug() << " get Joystick -- JOY_LEFT!" ;
126     }
127     else if (jsJoystickState == JOY_RIGHT)
128     {
129         qDebug() << " get Joystick -- JOY_RIGHT!" ;
130     }
131     else if (jsJoystickState == JOY_FIRE1)
132     {
133         qDebug() << " get Joystick -- JOY_FIRE1!" ;
134     }
135     else if (jsJoystickState == JOY_FIRE2)
136     {
137         qDebug() << " get Joystick -- JOY_FIRE2!" ;
138     }
139     else if (jsJoystickState == JOY_FIRE3)
140     {
141         qDebug() << " get Joystick -- JOY_FIRE3!" ;
142     }
143     else if (jsJoystickState == JOY_FIRE4)
144     {
145         qDebug() << " get Joystick -- JOY_FIRE4!" ;
146     }
147 }
148

Enjoy!

没有评论: