Cocos2d-x 事件机制

基本元素:

  • 事件监听器( EventListener):负责接收事件,并执行预定义的事件处理函数
  • 事件分发器(EventDispatcher):负责发起通知
  • 事件对象(Event):记录事件的相关信息

 

流程图:

 

Node:     //_eventDispatcher统一指向CCDirector中的_eventDispatcher

class CC_DLL Node : public Ref
{
protected:
    /* 省略 */

    EventDispatcher* _eventDispatcher;  ///< event dispatcher used to dispatch all kinds of events

   /* 省略 */
}

Node::Node():   //_eventDispatcher统一指向CCDirector中的_eventDispatcher

Node::Node()
/* 省略 */
{
    // set default scheduler and actionManager
    /* 省略 */

    _director = Director::getInstance();
    _eventDispatcher = _director->getEventDispatcher();
    _eventDispatcher->retain(); 
}

Director: 

class CC_DLL Director : public Ref
{   
    /* 省略 */

    /* EventDispatcher associated with this director */
    EventDispatcher* _eventDispatcher = nullptr;

    /* 省略 */
}

void Director::mainLoop():   //更新函数,每帧被调用

void Director::mainLoop()
{
    /* 省略 */

    drawScene();

    /* 省略 */
}

void Director::drawScene():   //调用事件

// Draw the Scene
void Director::drawScene()
{
    /* 省略 */

    if (_openGLView)
    {
        _openGLView->pollEvents();
    }

    /* 省略 */
}

上面代码表明,Cocos事件机制大概思路是:对对象添加的事件都会保存到CCDirector中的_eventDispatcher对象中,然后在每一帧绘制时,根据事件调用时间顺序分别调用事件包含的回掉函数。

事件根据调用时间可分为:

  • _eventBeforeUpdate   
  • _eventAfterUpdate      
  • _eventBeforeDraw      
  • _eventAfterVisit           
  • _eventAfterDraw         

 

示例:

接下来以UIButton组件的点击(Click)事件举例来跑整个流程:

Button:  //Button继承Widget

class CC_GUI_DLL Button : public Widget
{
    /* 省略 */
}
typedef std::function<void(Ref*)> ccWidgetClickCallback;

ccWidgetClickCallback _clickEventListener;

void Widget::addClickEventListener(const ccWidgetClickCallback &callback):   // 给UIButton添加点击事件

void Widget::addClickEventListener(const ccWidgetClickCallback &callback)
{
    this->_clickEventListener = callback;
}

onTouchEnded(Touch *touch, Event* /*unusedEvent*/) :   //事件被保存在std::function<bool(Touch*, Event*)>的变量中

class CC_DLL EventListenerTouchOneByOne : public EventListener
{
public:
    typedef std::function<void(Touch*, Event*)> ccTouchCallback;

    ccTouchCallback onTouchEnded;
}

void Widget::setTouchEnabled(bool enable):   // 创建监听器,然后监听事件,最后传给CCdirector的_eventDispatcher

void Widget::setTouchEnabled(bool enable)
{
    /* 省略 */
    _touchListener = EventListenerTouchOneByOne::create();
    CC_SAFE_RETAIN(_touchListener);
    _touchListener->setSwallowTouches(true);
    _touchListener->onTouchEnded = CC_CALLBACK_2(Widget::onTouchEnded, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(_touchListener, this);
    /* 省略 */
}

void Widget::onTouchEnded(Touch *touch, Event* /*unusedEvent*/)
{
    /* 省略 */

    if (highlight)
    {
        releaseUpEvent();
    }

    /* 省略 */
}

void Widget::releaseUpEvent()
{
    /* 省略 */
    if (_clickEventListener) {
        _clickEventListener(this);
    }
   /* 省略 */
}

在每一帧绘制时,调用CCDirector::mainLoop(),调用 _openGLView->pollEvents()执行Touch事件

// Draw the Scene
void Director::drawScene()
{
    /* 省略 */
    
    if (_openGLView)
    {
        _openGLView->pollEvents();
    }

    /* 省略 */
}

void GLViewImpl::pollEvents(): 

void GLViewImpl::pollEvents()
{
    glfwPollEvents();
}
class CC_DLL GLFWEventHandler
{
public:

    static void onGLFWMouseCallBack(GLFWwindow* window, int button, int action, int modify)
    {
        if (_view)
            _view->onGLFWMouseCallBack(window, button, action, modify);
    }

    /* 省略 */
};

void GLViewImpl::onGLFWMouseCallBack(GLFWwindow* /*window*/, int button, int action, int /*modify*/) 

void GLViewImpl::onGLFWMouseCallBack(GLFWwindow* /*window*/, int button, int action, int /*modify*/)
{
     /* 省略 */

     this->handleTouchesEnd(1, &id, &_mouseX, &_mouseY);

     /* 省略 */
}
void GLView::handleTouchesEnd(int num, intptr_t ids[], float xs[], float ys[])
{
    handleTouchesOfEndOrCancel(EventTouch::EventCode::ENDED, num, ids, xs, ys);
}

void GLView::handleTouchesOfEndOrCancel(EventTouch::EventCode eventCode, int num, intptr_t ids[], float xs[], float ys[])
{
    /* 省略 */

    touchEvent._eventCode = eventCode;
    auto dispatcher = Director::getInstance()->getEventDispatcher();
    dispatcher->dispatchEvent(&touchEvent);
    
    for (auto& touch : touchEvent._touches)
    {
        // release the touch object.
        touch->release();
    }
}

以上就是Cocos底层的事件机制,总的来说就就是添加事件时会把事件添加到CCDirector中的_eventDispatcher中,在每帧中调用对应触发的事件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章