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中,在每幀中調用對應觸發的事件。

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