最近有个机顶盒项目,需要用到遥控器的方向键在游戏中控制方向。
如果是一般Android设备、iOS设备或Win32平台,cocos2d-x提供了“CCAccelerometer”类,可用于游戏控制UI。但由于机顶盒在使用过程中是使用遥控器与玩家交互,而遥控器中缺少GSenser,所以只能暂时使用方向键和中键。好在机顶盒厂家使用了Android标准的键值,方向键和中键与Andriod DPAD按键一一对应。
下面讲一下如何修改cocos2d-x,以使我们在游戏中能感知DPAD按键消息。
一 修改cocos2dx\keypad_dispatcher\CCKeypadDelegate.h
为” CCKeypadDelegate”添加2个虚函数,完成后为:
class CC_DLL CCKeypadDelegate
{
public:
// The back key clicked
virtual void keyBackClicked() {}
// The menu key clicked. only available on wophone & android
virtual void keyMenuClicked() {};
// The enter key clicked. only available on win32 & android
virtual void keyEnterClicked() {};
// The arrow key clicked. only available on win32 & android
virtual void keyArrowClicked(int arrow) {};
};
其中” keyEnterClicked”函数用于响应”Enter”键,”keyArrowClicked”函数用于响应方向键消息。
二 cocos2dx\keypad_dispatcher\CCKeypadDispatcher.h
修改枚举 ccKeypadMSGType的定义为:
typedef enum {
// the back key clicked msg
kTypeBackClicked = 1,
// the menu key clicked msg
kTypeMenuClicked,
// the Enter key clicked msg
kTypeEnterClicked,
// the arrow key clicked msg
kTypeLeftArrowClicked,
kTypeUpArrowClicked,
kTypeRightArrowClicked,
kTypeDownArrowClicked,
} ccKeypadMSGType;
三 cocos2dx\keypad_dispatcher\CCKeypadDispatcher.cpp
修改” dispatchKeypadMSG”函数,在:
case kTypeMenuClicked:
pDelegate->keyMenuClicked();
后添加:
case kTypeEnterClicked:
pDelegate->keyEnterClicked();
break;
case kTypeLeftArrowClicked:
case kTypeUpArrowClicked:
case kTypeRightArrowClicked:
case kTypeDownArrowClicked:
pDelegate->keyArrowClicked(nMsgType);
break;
针对Android平台还需要一下修改:
四 cocos2dx\platform\android\java\src\org\cocos2dx\lib\Cocos2dxGLSurfaceView.java
找到” onKeyDown”函数,在其中添加几个键值处理,使函数如下:
@Override
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent) {
switch (pKeyCode) {
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_MENU:
case KeyEvent.KEYCODE_DPAD_UP: // 19
case KeyEvent.KEYCODE_DPAD_DOWN: // 20
case KeyEvent.KEYCODE_DPAD_LEFT: // 21
case KeyEvent.KEYCODE_DPAD_RIGHT: // 22
case KeyEvent.KEYCODE_DPAD_CENTER: // 23
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyDown(pKeyCode);
}
});
return true;
default:
return super.onKeyDown(pKeyCode, pKeyEvent);
}
}
*注意:项目目录中proj.android\src\org\cocos2dx\lib\Cocos2dxGLSurfaceView.java需要修改与此相同。
五 cocos2dx\platform\android\jni\TouchesJni.cpp
找到:
#define KEYCODE_BACK 0x04
#define KEYCODE_MENU 0x52
紧接着在下面添加:
#define KEYCODE_DPAD_UP 19
#define KEYCODE_DPAD_DOWN 20
#define KEYCODE_DPAD_LEFT 21
#define KEYCODE_DPAD_RIGHT 22
#define KEYCODE_DPAD_CENTER 23
然后修改”Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeKeyDown”函数,如下:
JNIEXPORT jboolean JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeKeyDown(JNIEnv * env, jobject thiz, jint keyCode) {
CCDirector* pDirector = CCDirector::sharedDirector();
switch (keyCode) {
case KEYCODE_BACK:
if (pDirector->getKeypadDispatcher()->dispatchKeypadMSG(kTypeBackClicked))
return JNI_TRUE;
break;
case KEYCODE_MENU:
if (pDirector->getKeypadDispatcher()->dispatchKeypadMSG(kTypeMenuClicked))
return JNI_TRUE;
break;
case KEYCODE_DPAD_UP:
if (pDirector->getKeypadDispatcher()->dispatchKeypadMSG(kTypeUpArrowClicked))
return JNI_TRUE;
break;
case KEYCODE_DPAD_DOWN:
if (pDirector->getKeypadDispatcher()->dispatchKeypadMSG(kTypeDownArrowClicked))
return JNI_TRUE;
break;
case KEYCODE_DPAD_LEFT:
if (pDirector->getKeypadDispatcher()->dispatchKeypadMSG(kTypeLeftArrowClicked))
return JNI_TRUE;
break;
case KEYCODE_DPAD_RIGHT:
if (pDirector->getKeypadDispatcher()->dispatchKeypadMSG(kTypeRightArrowClicked))
return JNI_TRUE;
break;
case KEYCODE_DPAD_CENTER:
if (pDirector->getKeypadDispatcher()->dispatchKeypadMSG(kTypeEnterClicked))
return JNI_TRUE;
break;
default:
return JNI_FALSE;
}
return JNI_FALSE;
}
至此Android平台修改完成。
为了方便我们在VS2010中开发,还有针对Win32平台进行修改:
六 cocos2dx\platform\win32\CCEGLView.cpp
找到”WindowProc”函数,找到:
if (wParam == VK_F1 || wParam == VK_F2)
{
CCDirector* pDirector = CCDirector::sharedDirector();
if (GetKeyState(VK_LSHIFT) < 0 || GetKeyState(VK_RSHIFT) < 0 || GetKeyState(VK_SHIFT) < 0)
pDirector->getKeypadDispatcher()->dispatchKeypadMSG(wParam == VK_F1 ? kTypeBackClicked : kTypeMenuClicked);
}
else if (wParam == VK_ESCAPE)
{
CCDirector::sharedDirector()->getKeypadDispatcher()->dispatchKeypadMSG(kTypeBackClicked);
}
紧接着在后边添加:
else if (wParam == VK_RETURN)
{
CCDirector::sharedDirector()->getKeypadDispatcher()->dispatchKeypadMSG(kTypeEnterClicked);
}
else if (wParam >= VK_LEFT && wParam <= VK_DOWN)
{
CCDirector::sharedDirector()->getKeypadDispatcher()->dispatchKeypadMSG((ccKeypadMSGType)(kTypeLeftArrowClicked + wParam - VK_LEFT));
}
好,现在Win32平台也添加完成了,程序中可以响应键盘上的方向键和回车键。
使用方法如下:
假设我们要在继承自CCLayer的HelloWorld中相应按键,那么首先在HelloWorld的头文件中添加两个函数:
void keyArrowClicked(int arrow);
void keyEnterClicked();
然后,在HelloWorld初始化时启用按键功能:
setKeypadEnabled(true);
在HelloWorld中实现之前声明的2个虚函数:
void LLPlaneControlLayer::keyArrowClicked(int arrow)
{
if (arrow == kTypeLeftArrowClicked)
{
// 左方向键按下
}
else if (arrow == kTypeRightArrowClicked)
{
// 右方向键按下
}
if (arrow == kTypeUpArrowClicked)
{
// 上方向键按下
}
else if (arrow == kTypeDownArrowClicked)
{
// 下方向键按下
}
}
void LLPlaneControlLayer::keyEnterClicked()
{
// Enter键按下
}
当用户按下方向键,keyArrowClicked会被执行,参数arrow表示按下的键;当用户按下Enter键(Android平台为DPAD_CENTER键),keyEnterClicked函数会执行。