首页 > 代码库 > Cocos2dx引擎8-事件处理

Cocos2dx引擎8-事件处理

本文从主要介绍点击事件的处理过程,分别从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);
………
}<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>

在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 < num; ++i)//遍历所有的触摸点,若多点触摸则需要
    {
        id = ids[i];
        x = xs[i];
        y = ys[i];
        //在本地Touch字典中查询该touch是否已经存在
        auto iter = g_touchIdReorderMap.find(id);
        // 如果是一个新Touch
        if (iter == g_touchIdReorderMap.end())
        {
            unusedIndex = getUnUsedIndex();//获取新Touch标记符
            ……
            //收集Touch信息
            Touch* touch =g_touches[unusedIndex] = new Touch();
            touch->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 < num; ++i) //遍历所有的触摸点,若多点触摸则需要
    {
        id = ids[i];
        x = xs[i];
        y = ys[i];
        //查询该释放事件对应的点击事件是否存在
        auto iter =g_touchIdReorderMap.find(id);
       ……
        Touch* touch =g_touches[iter->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。

Cocos2dx引擎8-事件处理