本文从主要介绍点击事件的处理过程,分别从win32、Android、IOS系统介绍Cocos2dx点击事件处理过程。
1、Win32系统
AppDelegate::applicationDidFinishLaunching()->GLView::create(…)->GLView::initWithRect(…)
bool GLView::initWithRect(conststd::string& viewName, Rect rect, float frameZoomFactor){
………
glfwSetMouseButtonCallback(_mainWindow,
GLFWEventHandler::onGLFWMouseCallBack);
………
}
在win32系统中点击事件为鼠标点击事件,使用glfwSetMouseButtonCallback绑定鼠标点击事件的时间处理函数;
static voidonGLFWMouseCallBack(GLFWwindow* window, int button, int action, int modify){
if (_view) _view->onGLFWMouseCallBack(window,button, action, modify);
}
voidGLView::onGLFWMouseCallBack(GLFWwindow* window, int button, int action, intmodify){
if(GLFW_MOUSE_BUTTON_LEFT == button) {//鼠标左键时
if(GLFW_PRESS == action) {//鼠标左键按下时
_captured = true;
if(this->getViewPortRect().equals(Rect::ZERO) ||
this->getViewPortRect().containsPoint(Vec2(_mouseX,_mouseY))){
intptr_t id = 0;
this->handleTouchesBegin(1, &id, &_mouseX, &_mouseY);
}
}elseif(GLFW_RELEASE == action) {//鼠标左键松开时
if(_captured) {
_captured = false;
intptr_t id = 0;
this->handleTouchesEnd(1, &id, &_mouseX, &_mouseY);
}
}
}
………//处理鼠标事件
}
上面的处理方法代码位于cocos2d\cocos\platform\win32\ CCGLView.cpp中;
2、Android系统
public class Cocos2dxGLSurfaceView extends GLSurfaceView {
……
public booleanonTouchEvent(final MotionEvent pMotionEvent) {
……….
switch(pMotionEvent.getAction() & MotionEvent.ACTION_MASK) {
……
caseMotionEvent.ACTION_DOWN://按下事件
this.queueEvent(newRunnable() {//新起一个线程处理该事件
publicvoid run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionDown
(idDown, xDown,yDown);
}
});
break;
…………….
caseMotionEvent.ACTION_UP: //抬起事件
this.queueEvent(newRunnable() {
publicvoid run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleActionUp
(idUp, xUp, yUp);
}
});
break;
…………
}
return true;
}
}
Cocos2dxGLSurfaceView继承View类,实现View中关于触摸屏事件处理函数onTouchEvent,当有触摸屏事件发生时会调用Cocos2dxGLSurfaceView中onTouchEvent方法,在onTouchEvent方法中会区分Down&Up事件,并使用新的线程执行Cocos2dxRenderer类中handleActionDown&handleActionUp方法;
public class Cocos2dxRenderer implements GLSurfaceView.Renderer{
private static native void nativeTouchesBegin(final int pID, final float pX, final float pY);
private static native void nativeTouchesEnd(final int pID, final float pX, final float pY);
public void handleActionDown(finalint pID, final float pX, final float pY) {
Cocos2dxRenderer.nativeTouchesBegin(pID,pX, pY);
}
public voidhandleActionUp(final int pID, final float pX, final float pY) {
Cocos2dxRenderer.nativeTouchesEnd(pID,pX, pY);
}
}
在Cocos2dxRenderer类中的handleActionDown&handleActionUp方法会通过JNI调用C++实现的nativeTouchesBegin&nativeTouchesEnd方法;
nativeTouchesBegin&nativeTouchesEnd分别对应
cocos2d\cocos\platform\android\jni\TouchesJni.cpp文件中:
JNIEXPORT voidJNICALL
Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesBegin(JNIEnv * env, jobject thiz, jint id, jfloatx, jfloat y) {
cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesBegin(1,&id, &x, &y);
}
JNIEXPORT voidJNICALL
Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesEnd(JNIEnv * env, jobject thiz, jint id, jfloatx, jfloat y) {
cocos2d::Director::getInstance()->getOpenGLView()->handleTouchesEnd(1,&id, &x, &y);
}
3、IOS系统
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
……
glview->handleTouchesBegin(i,(intptr_t*)ids, xs, ys);
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
……
glview->handleTouchesEnd(i,(intptr_t*)ids, xs, ys);
}
以上方法在cocos2d\cocos\platform\ios\CCEAGLView.mm中实现;
4、Cocs2dx事件处理
上文中handleTouchesBegin和handleTouchesEnd处理在Win32、Android、IOS中是相同的实现,接下来会继续分析;
voidGLViewProtocol::handleTouchesBegin(int num, intptr_t ids[], float xs[], floatys[]){//点击按下时执行
intptr_t id = 0;
float x = 0.0f;
float y = 0.0f;
int unusedIndex = 0;
EventTouch touchEvent;
for (int i = 0; i setTouchInfo(unusedIndex,(x - _viewPortRect.origin.x) / _scaleX,
(y -_viewPortRect.origin.y) / _scaleY);
CCLOGINFO("x = %f y =%f", touch->getLocationInView().x, touch->getLocationInView().y);
//将当前Touch添加入Touch查询字典中
g_touchIdReorderMap.insert(std::make_pair(id, unusedIndex));
touchEvent._touches.push_back(touch);
}
}
……
touchEvent._eventCode =EventTouch::EventCode::BEGAN;
auto dispatcher =Director::getInstance()->getEventDispatcher();
dispatcher->dispatchEvent(&touchEvent);//分发Touch事件
}
在handleTouchesBegin中:
(1)查询点击是否已经存在
(2)若点击记录中不存在当前点击,则收集点击信息,分发TouchBegin事件
在过程(1)中单点点击中传入的ids={0},点击事件是存储在touchIdReorderMap[0]位置,这么做事防止出现点击同一个位置时未释放前,出现点击其他位置从而调用handleTouchesBegin;
voidGLViewProtocol::handleTouchesEnd(int num, intptr_t ids[], float xs[], floatys[]){ //点击释放时执行
handleTouchesOfEndOrCancel(EventTouch::EventCode::ENDED, num, ids, xs,ys);
}
void GLViewProtocol::handleTouchesOfEndOrCancel(EventTouch::EventCodeeventCode, int num, intptr_t ids[], float xs[], float ys[])
{
intptr_t id = 0;
float x = 0.0f;
float y = 0.0f;
EventTouch touchEvent;
for (int i = 0; i second];
if (touch) {
touch->setTouchInfo(iter->second,(x - _viewPortRect.origin.x) / _scaleX,
(y -_viewPortRect.origin.y) / _scaleY);
touchEvent._touches.push_back(touch);
g_touches[iter->second] =nullptr;
removeUsedIndexBit(iter->second);
g_touchIdReorderMap.erase(id);//移除已经释放点击事件
}
……
}
……
touchEvent._eventCode = eventCode;
auto dispatcher =Director::getInstance()->getEventDispatcher();
dispatcher->dispatchEvent(&touchEvent);//派发点击释放事件
for(auto& touch : touchEvent._touches) {//释放点击
touch->release();
}
}
在handleTouchesOfEndOrCancel中:
(1)查询点击是否已经存在
(2)若点击记录存在点击,则收集点击信息,分发TouchEnd事件
因为在单点点击中传入的ids={0},只有查询到该点击事件存在才会执行释放操作,最后会将点击事件从g_touchIdReorderMap移除,保证在调用ToucheEnd之前一定有TouchBegin。