1. 程式人生 > >cocos2d-x 源代碼分析 : EventDispatcher、EventListener、Event 源代碼分析 (新觸摸機制,新的NotificationCenter機制)

cocos2d-x 源代碼分析 : EventDispatcher、EventListener、Event 源代碼分析 (新觸摸機制,新的NotificationCenter機制)

get cti state 2.7 return 3.1 成了 available been

源代碼版本號來自3.x,轉載請註明

cocos2d-x 源代碼分析總文件夾

http://blog.csdn.net/u011225840/article/details/31743129


1.繼承結構

1.1 結構

不詳吐槽太多,也不貼圖了。貼圖要審核好久好久好久好久。 從小到大,先來看下Event的結構。 1.Event--------EventTouch,EventCustom,EventMouse,EventKeyboard,EventFocus,EventAcceleration 當中,EventTouch 和 EventCustom是比較特殊的兩個Event。EventTouch是3.x版本號的觸摸機制相關的Event,而EventCustom則是3.x自己定義事件機制的基礎。該機制代替了2.x版本號中的NotificationCenter。
2.EventListener-------------EventListenerTouchOneByOne,EventListenerTouchAllAtOnce,EventListenerCustom,EventListenerFocus。EventListenerMouse....相應 相比於Event,Listener多了一個,由於相應的Touch被拆分成了兩個Listener。一個是OneByone,一個是TouchAllAtOnce。前者是onTouchBegan等函數的Listener,後者是onTouchesBegan等函數的Listener。



1.2.EventDispatcher,EventListener,Event三者的關系

Event相當於data,EventListener包括了data與fuction的一種映射關系,而EventDispatcher相當於一個Manager,管理著EventListener,決定著Event的調用順序。 Event中包括了type。target等信息;EventListener包括了ListenerID。相關聯的Node。相應的callBack;EventDispatcher裏含有各種map,vector來管理不同的Listener。

詳細的,能夠看源代碼分析。

2.源代碼分析

本次源代碼分析的量比較大,大家要有心理準備喲~

2.1Event相關

2.1.1 Event


 enum class Type
    {
        TOUCH,
        KEYBOARD,
        ACCELERATION,
        MOUSE,
        FOCUS,
        CUSTOM
    };
    Type _type;     ///< Event type
    
    bool _isStopped;       ///< whether the event has been stopped.
    Node* _currentTarget;
Event主要包括了三個重要的變量,type,是一個enum變量,裏面定義了類型。isStopped定義該event是否已經停止。當一個event發生停止時。與其相關的Listener都要停止callback的調用;currentTarget是與該Event相關聯的node。

2.1.2 EventTouch

EventTouch是cocos2d-x引擎中很很重要的事件。相應於四種touch操作。該類內部定義了四種EventCode
 enum class EventCode
    {
        BEGAN,
        MOVED,
        ENDED,
        CANCELLED
    };

不同的EventCode能夠告訴Listener來調用不同的callback。
除此之外,EventTouch中含有std::vector<Touch*> _touches 來記錄該事件相關的touch,值得註意的是。本版本號默認含有的觸摸點最大是5個。


2.1.3 EventCustom


EventCustom的出現代替了統治2.x版本號多年的NotificationCenter,來看下EventCustom的兩個重要成員變量。
    void* _userData;       ///< User data
    std::string _eventName;

有沒有似曾相識的感覺,還是一樣的key。還是一樣的userData(有點不一樣。原來是CCObject*)。

其它的Event由於重要性以及使用度的原因,這裏不再贅述,假設以後筆者對他們有新的認識。將會在這裏進行加入。

2.2 EventListener相關

2.2.1 EventListener


    std::function<void(Event*)> _onEvent;   /// Event callback function
    Type _type;                             /// Event listener type
    ListenerID _listenerID;                 /// Event listener ID
    bool _isRegistered;                     /// Whether the listener has been added to dispatcher.

    int   _fixedPriority;   // The higher the number, the higher the priority, 0 is for scene graph base priority.
    Node* _node;            // scene graph based priority
    bool _paused;           // Whether the listener is paused
    bool _isEnabled;        // Whether the listener is enabled

重要的成員變量: 1.onEvent,是綁定於該Listener的callback function,該func的聲明使用了c++11的新特性。

2.type與Event類似。添加一個Unknown的屬性。 3.isRegistered變量很重要,假設他沒有被註冊。則他的事件不會觸發。 4.優先級代表了響應一個事件時的順序。該值越低。越先響應。 5.node 代表了與該listener相關的node,用於 scene graph類的事件響應,詳細的在Dispatcher裏面有進行介紹。 6.最後說下ListenerID,這是該類型事件的標識符。除了EventCustomListener的ListerID是與name相關的。其余的ListenerID都是固定的。用於標識該類EventListener。


 /** Enables or disables the listener
     *  @note Only listeners with `enabled` state will be able to receive events.
     *        When an listener was initialized, it's enabled by default.
     *        An event listener can receive events when it is enabled and is not paused.
     *        paused state is always false when it is a fixed priority listener.
     */
    inline void setEnabled(bool enabled) { _isEnabled = enabled; };
/** Sets paused state for the listener
     *  The paused state is only used for scene graph priority listeners.
     *  `EventDispatcher::resumeAllEventListenersForTarget(node)` will set the paused state to `true`,
     *  while `EventDispatcher::pauseAllEventListenersForTarget(node)` will set it to `false`.
     *  @note 1) Fixed priority listeners will never get paused. If a fixed priority doesn't want to receive events,
     *           call `setEnabled(false)` instead.
     *        2) In `Node`'s onEnter and onExit, the `paused state` of the listeners which associated with that node will be automatically updated.
     */
    inline void setPaused(bool paused) { _paused = paused; };

上面兩段話。解釋了什麽時候一個Listener是能夠接收事件,什麽時候是不能夠的。 1.一個Listener想接收事件必須是enabled true 而且 paused false。 2.值得註意的是,pause的變量專門是為了scenGraph類的事件存在的(興許有說明),並且一個Node的onEnter和onExit 事件會影響到與Node相關的該類事件的pause狀態。

2.2.2 EventListenerOneByOne


    /// Overrides
    virtual EventListenerTouchOneByOne* clone() override;
    virtual bool checkAvailable() override;
    //

public:
    std::function<bool(Touch*, Event*)> onTouchBegan;
    std::function<void(Touch*, Event*)> onTouchMoved;
    std::function<void(Touch*, Event*)> onTouchEnded;
    std::function<void(Touch*, Event*)> onTouchCancelled;

上面的是OneByOne重載父類的方法。以及自己本身須要被綁定4個callBack 函數。

EventListenerTouchOneByOne* EventListenerTouchOneByOne::clone()
{
	//深拷貝
    auto ret = new EventListenerTouchOneByOne();
    if (ret && ret->init())
    {
        ret->autorelease();
        
        ret->onTouchBegan = onTouchBegan;
        ret->onTouchMoved = onTouchMoved;
        ret->onTouchEnded = onTouchEnded;
        ret->onTouchCancelled = onTouchCancelled;
        
        ret->_claimedTouches = _claimedTouches;
        ret->_needSwallow = _needSwallow;
    }
    else
    {
        CC_SAFE_DELETE(ret);
    }
    return ret;
}


bool EventListenerTouchOneByOne::checkAvailable()
{
    // EventDispatcher will use the return value of 'onTouchBegan' to determine whether to pass following 'move', 'end'
    // message to 'EventListenerTouchOneByOne' or not. So 'onTouchBegan' needs to be set.
	//OneByOne僅僅須要onTouchBegan不為空,則能夠覺得其是可用的。

if (onTouchBegan == nullptr) { CCASSERT(false, "Invalid EventListenerTouchOneByOne!"); return false; } return true; }

什麽是可用性,當在dispatcher進行事件分發時,假設一個Listener是不可用的。則不會將該事件分發給他。
    std::vector<Touch*> _claimedTouches;
    bool _needSwallow;

OneByOne的touch是能夠設置吞噬屬性的。

2.2.3 EventListenerAllAtOnce

    std::function<void(const std::vector<Touch*>&, Event*)> onTouchesBegan;
    std::function<void(const std::vector<Touch*>&, Event*)> onTouchesMoved;
    std::function<void(const std::vector<Touch*>&, Event*)> onTouchesEnded;
    std::function<void(const std::vector<Touch*>&, Event*)> onTouchesCancelled;

AllAtOnce就是所謂的standard touch處理機制。一次性處理全部的touch。
值得註意的是AllAtOnce的checkAvailable要求,上述四個函數指針都不能為空。


bool EventListenerTouchAllAtOnce::checkAvailable()
{
    if (onTouchesBegan == nullptr && onTouchesMoved == nullptr
        && onTouchesEnded == nullptr && onTouchesCancelled == nullptr)
    {
        CCASSERT(false, "Invalid EventListenerTouchAllAtOnce!");
        return false;
    }
    
    return true;
}

2.3 EventListenerCustom


相同的。EventListenerID是依據獨特的Name進行命名的,值得註意的是請確保你的name是具有唯一性的,否在在DispatchCustomEvent時會有問題。

3. EventDispatcher

從頭到尾寫了這麽多,才開始進入主題。上面的東西都是為了看EventDispatcher源代碼的開胃菜!!!在介紹這個之前,我們必需要看一個內部類

3.1 EventListenerVector


class EventListenerVector
    {
    public:
        EventListenerVector();
        ~EventListenerVector();
        size_t size() const;
        bool empty() const;
        
        void push_back(EventListener* item);
        void clearSceneGraphListeners();
        void clearFixedListeners();
        void clear();
        
        inline std::vector<EventListener*>* getFixedPriorityListeners() const { return _fixedListeners; };
        inline std::vector<EventListener*>* getSceneGraphPriorityListeners() const { return _sceneGraphListeners; };
        inline ssize_t getGt0Index() const { return _gt0Index; };
        inline void setGt0Index(ssize_t index) { _gt0Index = index; };
    private:
        std::vector<EventListener*>* _fixedListeners;
        std::vector<EventListener*>* _sceneGraphListeners;
        ssize_t _gt0Index;
    };

首先我要說明的是兩個很很重要的變量。fixedListeners和sceneGraphListeners。這是兩個截然不同的Listener列表。 1.sceneGraph類型的事件,是與當前正在執行的scene下node相關的事件,也就是說一個事件(比方說觸摸事件),須要依照一定的響應序列。依次對這些Node進行事件響應,所以該類型的事件都會綁定一個與此相關聯的node,而且響應順序是與node在scene下的zorder相關的。該類型下的事件優先級統一為0. 2.fixed類型的事件相對就比較簡單了,可是有一個限制就是其優先級不能為0.
在EventDispatcher的成員變量中有一個map :std::unordered_map<EventListener::ListenerID, EventListenerVector*> _listenerMap; 一種ListenerID相應了一個Vector。
size_t EventDispatcher::EventListenerVector::size() const
{
	//vector內部的size大小是兩個list的和
    size_t ret = 0;
    if (_sceneGraphListeners)
        ret += _sceneGraphListeners->size();
    if (_fixedListeners)
        ret += _fixedListeners->size();
    
    return ret;
}


void EventDispatcher::EventListenerVector::push_back(EventListener* listener)
{
	//查看listener的priority。假設為0,增加sceneGraphList,否則增加fixedList
    if (listener->getFixedPriority() == 0)
    {
        if (_sceneGraphListeners == nullptr)
        {
            _sceneGraphListeners = new std::vector<EventListener*>();
            _sceneGraphListeners->reserve(100);
        }
        
        _sceneGraphListeners->push_back(listener);
    }
    else
    {
        if (_fixedListeners == nullptr)
        {
            _fixedListeners = new std::vector<EventListener*>();
            _fixedListeners->reserve(100);
        }
        
        _fixedListeners->push_back(listener);
    }
}

上面兩個函數是與一般Vector不一樣的地方。須要註意的地方我已經標註了凝視。



3.2 Add操作

既然是一個類似於Manager的類,那就先從Add操作開始吧。


三種事件的加入方式:

3.2.1 sceneGraph類

void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
{
    CCASSERT(listener && node, "Invalid parameters.");
    CCASSERT(!listener->isRegistered(), "The listener has been registered.");
    
	//檢查Listener可用性
    if (!listener->checkAvailable())
        return;
    //設置listener相關屬性
    listener->setAssociatedNode(node);
    listener->setFixedPriority(0);
    listener->setRegistered(true);
    
    addEventListener(listener);
}

3.2.2 fixed類

void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
{
    CCASSERT(listener, "Invalid parameters.");
	//一個事件僅僅能被註冊一次
    CCASSERT(!listener->isRegistered(), "The listener has been registered.");
	//Fixed類型的事件優先級不能是0
    CCASSERT(fixedPriority != 0, "0 priority is forbidden for fixed priority since it's used for scene graph based priority.");
    
	//檢查可用性
    if (!listener->checkAvailable())
        return;
    
	//設置關聯屬性
    listener->setAssociatedNode(nullptr);
    listener->setFixedPriority(fixedPriority);
    listener->setRegistered(true);
    listener->setPaused(false);

    addEventListener(listener);
}

3.2.3 custom類

EventListenerCustom* EventDispatcher::addCustomEventListener(const std::string &eventName, const std::function<void(EventCustom*)>& callback)
{
	//custom類的事件加入是通過eventName 和 eventcallBack來進行加入的
    EventListenerCustom *listener = EventListenerCustom::create(eventName, callback);
	
	//custom的事件優先級被默覺得1
    addEventListenerWithFixedPriority(listener, 1);
	
    return listener;
}

能夠看出,加入函數最後都用到了一個函數addEventListener,以下對其進行剖析(這個函數又用到了其它函數。又。又,又。。

。。

。)

3.2.4 addEventListener

void EventDispatcher::addEventListener(EventListener* listener)
{
	//假設當前Dispatcher正在進行事件Dispatch,則放到toAddList中。
    if (_inDispatch == 0)
    {
        forceAddEventListener(listener);
    }
    else
    {
		// std::vector
        _toAddedListeners.push_back(listener);
    }

    listener->retain();
}

3.2.5 forceAddEventListener


void EventDispatcher::forceAddEventListener(EventListener* listener)
{
    EventListenerVector* listeners = nullptr;
    EventListener::ListenerID listenerID = listener->getListenerID();
	
	//找到該類eventlistener的vector。此處的vector是EventVector
    auto itr = _listenerMap.find(listenerID);
	//假設沒有找到,則須要向map中加入一個pair
    if (itr == _listenerMap.end())
    {
        
        listeners = new EventListenerVector();
        _listenerMap.insert(std::make_pair(listenerID, listeners));
    }
    else
    {
        listeners = itr->second;
    }
    //將該類別listenerpush_back進去(這個函數調用的是EventVector的pushback哦)
    listeners->push_back(listener);
    
	//假設優先級是0。則設置為graph。
    if (listener->getFixedPriority() == 0)
    {
		//設置該listenerID的DirtyFlag
		//(setDirty函數能夠這樣理解,每一個ListenerID都有特定的dirtyFlag。每次進行add操作後,都要更新該ID的flag)
        setDirty(listenerID, DirtyFlag::SCENE_GRAPH_PRIORITY);
        
		//假設是sceneGraph類的事件。則須要處理兩個方面:
		//1.將node 與event 關聯
		//2.假設該node是執行中的。則須要恢復其事件(由於默認的sceneGraph listener的狀態時pause)
		//添加該listener與node的關聯
        auto node = listener->getAssociatedNode();
        CCASSERT(node != nullptr, "Invalid scene graph priority!");
        
        associateNodeAndEventListener(node, listener);
        
		//恢復node的執行狀態
        if (node->isRunning())
        {
            resumeEventListenersForTarget(node);
        }
    }
    else
    {
        setDirty(listenerID, DirtyFlag::FIXED_PRIORITY);
    }
}

3.2.6associateNodeAndEventListener

void EventDispatcher::associateNodeAndEventListener(Node* node, EventListener* listener)
{
	//將listener與node關聯,先從map中找到與該node相關的listener vector
    std::vector<EventListener*>* listeners = nullptr;
    auto found = _nodeListenersMap.find(node);
    if (found != _nodeListenersMap.end())
    {
        listeners = found->second;
    }
    else
    {
        listeners = new std::vector<EventListener*>();
        _nodeListenersMap.insert(std::make_pair(node, listeners));
    }
    //vector內加入該listener,這裏的vector 是std::vector
    listeners->push_back(listener);
}

3.2.7 removeEventListenersForTarget


void EventDispatcher::resumeEventListenersForTarget(Node* target, bool recursive/* = false */)
{
	//恢復Node的執行狀態
    auto listenerIter = _nodeListenersMap.find(target);
    if (listenerIter != _nodeListenersMap.end())
    {
        auto listeners = listenerIter->second;
        for (auto& l : *listeners)
        {
            l->setPaused(false);
        }
    }
    // toAdd List中也要進行恢復
    for (auto& listener : _toAddedListeners)
    {
        if (listener->getAssociatedNode() == target)
        {
            listener->setPaused(false);
        }
    }
	//將該Node 與 node的child 都放到dirtyNode中,來記錄與event相關的node
    setDirtyForNode(target);
    
    if (recursive)
    {
        const auto& children = target->getChildren();
        for (const auto& child : children)
        {
            resumeEventListenersForTarget(child, true);
        }
    }
}

3.3 Remove

看完了Add。當然要講remove

3.3.1 removeEventListener

void EventDispatcher::removeEventListener(EventListener* listener)
{
	//說在前面,移除一個事件的代價比較大,假設沒有必要,請不要無故移除事件。
	//刪除一個listener的步驟:
    if (listener == nullptr)
        return;

    bool isFound = false;
    
	//lambda函數。函數從std::vector<EventListener*>* listeners 中移除該listener
    auto removeListenerInVector = [&](std::vector<EventListener*>* listeners){
        if (listeners == nullptr)
            return;
        //遍歷
        for (auto iter = listeners->begin(); iter != listeners->end(); ++iter)
        {
            auto l = *iter;
            if (l == listener)
            {
				//找到後的處理方法,標記狀態位,並處理關聯Node
                CC_SAFE_RETAIN(l);
                l->setRegistered(false);
                if (l->getAssociatedNode() != nullptr)
                {
                    dissociateNodeAndEventListener(l->getAssociatedNode(), l);
                    l->setAssociatedNode(nullptr);  // NULL out the node pointer so we don't have any dangling pointers to destroyed nodes.
                }
                //當前沒有在分發事件 則直接從listeners中移除該listener(由於標記了狀態未。假設此時在分發事件。則會等結束後再移除)
                if (_inDispatch == 0)
                {
                    listeners->erase(iter);
                    CC_SAFE_RELEASE(l);
                }
                
                isFound = true;
                break;
            }
        }
    };
    
    for (auto iter = _listenerMap.begin(); iter != _listenerMap.end();)
    {
		//從listenersmap 中遍歷全部。拿出全部的vector
        auto listeners = iter->second;
        auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
        auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();

		//從graphList中尋找。

找到後須要更新該listenerID的dirty flag。 removeListenerInVector(sceneGraphPriorityListeners); if (isFound) { // fixed #4160: Dirty flag need to be updated after listeners were removed. setDirty(listener->getListenerID(), DirtyFlag::SCENE_GRAPH_PRIORITY); } //從fixedList中尋找 else { removeListenerInVector(fixedPriorityListeners); if (isFound) { setDirty(listener->getListenerID(), DirtyFlag::FIXED_PRIORITY); } } //假設vector在刪除後是空的,則須要移除該vector。而且將對應的listenerID從_priorityDirtyFlagMap中移除。 if (iter->second->empty()) { _priorityDirtyFlagMap.erase(listener->getListenerID()); auto list = iter->second; iter = _listenerMap.erase(iter); CC_SAFE_DELETE(list); } else { ++iter; } if (isFound) break; } if (isFound) { CC_SAFE_RELEASE(listener); } //假設在上述過程中未找到。則從toAddList中尋找 else { for(auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end(); ++iter) { if (*iter == listener) { listener->setRegistered(false); listener->release(); _toAddedListeners.erase(iter); break; } } } }


3.3.2 removeEventListenersForListenerID


void EventDispatcher::removeEventListenersForListenerID(const EventListener::ListenerID& listenerID)
{
    auto listenerItemIter = _listenerMap.find(listenerID);
    if (listenerItemIter != _listenerMap.end())
    {
        auto listeners = listenerItemIter->second;
        auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
        auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();
        
		//啊哦 又是一個lambda函數。將std::vector<EventListener*>* listenerVector中的Listener所有移除
        auto removeAllListenersInVector = [&](std::vector<EventListener*>* listenerVector){
            if (listenerVector == nullptr)
                return;
            
            for (auto iter = listenerVector->begin(); iter != listenerVector->end();)
            {
				//設置要刪除的listener狀態,清空與其相關的node信息
                auto l = *iter;
                l->setRegistered(false);
                if (l->getAssociatedNode() != nullptr)
                {
                    dissociateNodeAndEventListener(l->getAssociatedNode(), l);
                    l->setAssociatedNode(nullptr);  // NULL out the node pointer so we don't have any dangling pointers to destroyed nodes.
                }
                
                if (_inDispatch == 0)
                {
                    iter = listenerVector->erase(iter);
                    CC_SAFE_RELEASE(l);
                }
                else
                {
                    ++iter;
                }
            }
        };
        
		//兩種類型的事件哦
        removeAllListenersInVector(sceneGraphPriorityListeners);
        removeAllListenersInVector(fixedPriorityListeners);
        
        // Remove the dirty flag according the 'listenerID'.
        // No need to check whether the dispatcher is dispatching event.
        _priorityDirtyFlagMap.erase(listenerID);
        
        if (!_inDispatch)
        {
            listeners->clear();
            delete listeners;
            _listenerMap.erase(listenerItemIter);
        }
    }
    
	//toAddList 的清理,真可憐,還沒來得及進入家門就要被掃地出門了麽。。。。
    for (auto iter = _toAddedListeners.begin(); iter != _toAddedListeners.end();)
    {
        if ((*iter)->getListenerID() == listenerID)
        {
            (*iter)->setRegistered(false);
            (*iter)->release();
            iter = _toAddedListeners.erase(iter);
        }
        else
        {
            ++iter;
        }
    }
}

與其相關的兩個remove函數
void EventDispatcher::removeEventListenersForType(EventListener::Type listenerType)
{
    if (listenerType == EventListener::Type::TOUCH_ONE_BY_ONE)
    {
        removeEventListenersForListenerID(EventListenerTouchOneByOne::LISTENER_ID);
    }
    else if (listenerType == EventListener::Type::TOUCH_ALL_AT_ONCE)
    {
        removeEventListenersForListenerID(EventListenerTouchAllAtOnce::LISTENER_ID);
    }
    else if (listenerType == EventListener::Type::MOUSE)
    {
        removeEventListenersForListenerID(EventListenerMouse::LISTENER_ID);
    }
    else if (listenerType == EventListener::Type::ACCELERATION)
    {
        removeEventListenersForListenerID(EventListenerAcceleration::LISTENER_ID);
    }
    else if (listenerType == EventListener::Type::KEYBOARD)
    {
        removeEventListenersForListenerID(EventListenerKeyboard::LISTENER_ID);
    }
    else
    {
        CCASSERT(false, "Invalid listener type!");
    }
}

void EventDispatcher::removeCustomEventListeners(const std::string& customEventName)
{
    removeEventListenersForListenerID(customEventName);
}

3.3.3 removeAllEventListeners

void EventDispatcher::removeAllEventListeners()
{
    bool cleanMap = true;
    std::vector<EventListener::ListenerID> types(_listenerMap.size());
    
    for (const auto& e : _listenerMap)
    {
        if (_internalCustomListenerIDs.find(e.first) != _internalCustomListenerIDs.end())
        {
            cleanMap = false;
        }
        else
        {
            types.push_back(e.first);
        }
    }

    for (const auto& type : types)
    {
        removeEventListenersForListenerID(type);
    }
    
    if (!_inDispatch && cleanMap)
    {
        _listenerMap.clear();
    }
}


3.4 DispatchEvent(核心內容)

最終到了核心內容了。為啥我要把核心內容放到後面。假設不看上面,不了解Event。EventListener,EventVector以及Dispatcher是怎樣管理EventListener的。看以下的代碼就會有非常多的疑惑。

ok,讓我們靜靜贊賞源代碼吧。

3.4.1 dispatchEvent

void EventDispatcher::dispatchEvent(Event* event)
{
    if (!_isEnabled)
        return;
    
	//為dirtyNodesVector中的dirtyNode更新Scene Flag。

updateDirtyFlagForSceneGraph(); DispatchGuard guard(_inDispatch); //特殊touch事件,轉到特殊的touch事件處理 if (event->getType() == Event::Type::TOUCH) { dispatchTouchEvent(static_cast<EventTouch*>(event)); return; } //依據事件的類型。獲取事件的ID auto listenerID = __getListenerID(event); //依據事件ID,將該類事件進行排序(先響應誰) sortEventListeners(listenerID); auto iter = _listenerMap.find(listenerID); if (iter != _listenerMap.end()) { auto listeners = iter->second; //該類事件的lambda函數 auto onEvent = [&event](EventListener* listener) -> bool{ //設置event的target event->setCurrentTarget(listener->getAssociatedNode()); //調用響應函數 listener->_onEvent(event); //返回是否已經停止 return event->isStopped(); }; //將該類事件的listeners 和 該類事件的 lambda函數傳給該函數 dispatchEventToListeners(listeners, onEvent); } //更新該事件相關的listener updateListeners(event); }


我們能夠看出,特殊的touchEvent和普通的event走的不是同一條控制流程,既然如此,我們就先一般後特殊吧。先來看看一般流程下的DispatchEventToListeners吧

3.4.2 dispatchEventToListeners


void EventDispatcher::dispatchEventToListeners(EventListenerVector* listeners, const std::function<bool(EventListener*)>& onEvent)
{
    bool shouldStopPropagation = false;
    auto fixedPriorityListeners = listeners->getFixedPriorityListeners();
    auto sceneGraphPriorityListeners = listeners->getSceneGraphPriorityListeners();
    
	//總體操作流程分為三個部分,處理優先級<0,=0,>0三個部分
    ssize_t i = 0;
    // priority < 0
    if (fixedPriorityListeners)
    {
        CCASSERT(listeners->getGt0Index() <= static_cast<ssize_t>(fixedPriorityListeners->size()), "Out of range exception!");
        
        if (!fixedPriorityListeners->empty())
        {
            for (; i < listeners->getGt0Index(); ++i)
            {
                auto l = fixedPriorityListeners->at(i);
				// onEvent(l)的操作調用了event的callBack,而且會返回是否停止,假設停止後,則將shouldStopPropagation標記為true
				//在其後面的listeners則不會響應到該事件(這裏能夠看出觸摸事件是怎樣被吞噬的)
                if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
                {
                    shouldStopPropagation = true;
                    break;
                }
            }
        }
    }
    
    if (sceneGraphPriorityListeners)
    {
        if (!shouldStopPropagation)
        {
            // priority == 0, scene graph priority
            for (auto& l : *sceneGraphPriorityListeners)
            {
                if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
                {
                    shouldStopPropagation = true;
                    break;
                }
            }
        }
    }

    if (fixedPriorityListeners)
    {
        if (!shouldStopPropagation)
        {
            // priority > 0
            ssize_t size = fixedPriorityListeners->size();
            for (; i < size; ++i)
            {
                auto l = fixedPriorityListeners->at(i);
                
                if (l->isEnabled() && !l->isPaused() && l->isRegistered() && onEvent(l))
                {
                    shouldStopPropagation = true;
                    break;
                }
            }
        }
    }
}

3.4.3 dispatchTouchEvent(3.x版本號的觸摸機制)

void EventDispatcher::dispatchTouchEvent(EventTouch* event)
{
	//先將EventListeners排序
    sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);
    sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
    
    auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID);
    auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);
    
    // If there aren't any touch listeners, return directly.
    if (nullptr == oneByOneListeners && nullptr == allAtOnceListeners)
        return;
    
	//mutableTouches是用來處理allAtOnce的
    bool isNeedsMutableSet = (oneByOneListeners && allAtOnceListeners);
    
	//這些touch都來自該事件
    const std::vector<Touch*>& originalTouches = event->getTouches();
    std::vector<Touch*> mutableTouches(originalTouches.size());
    std::copy(originalTouches.begin(), originalTouches.end(), mutableTouches.begin());

    //
    // process the target handlers 1st
    //
    if (oneByOneListeners)
    {
        auto mutableTouchesIter = mutableTouches.begin();
        auto touchesIter = originalTouches.begin();
        //遍歷touches,每個touch都來自於同一個事件
        for (; touchesIter != originalTouches.end(); ++touchesIter)
        {
            bool isSwallowed = false;

			//事件處理的lambda函數
            auto onTouchEvent = [&](EventListener* l) -> bool { // Return true to break
                EventListenerTouchOneByOne* listener = static_cast<EventListenerTouchOneByOne*>(l);
                
                // Skip if the listener was removed.
                if (!listener->_isRegistered)
                    return false;
             
                event->setCurrentTarget(listener->_node);
                //claimed代表該listener是否接收了該touch(Began返回true or false)
                bool isClaimed = false;
                std::vector<Touch*>::iterator removedIter;
                
				//依據eventNode的不同,會調用不同的callBack函數
                EventTouch::EventCode eventCode = event->getEventCode();
                
                if (eventCode == EventTouch::EventCode::BEGAN)
                {
					//調用began
                    if (listener->onTouchBegan)
                    {
                        isClaimed = listener->onTouchBegan(*touchesIter, event);
                        if (isClaimed && listener->_isRegistered)
                        {
							//返回true後 將該touch放入該listener的claimedTouches
                            listener->_claimedTouches.push_back(*touchesIter);
                        }
                    }
                }
				//假設是後三個move end cancel
                else if (listener->_claimedTouches.size() > 0
                         && ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end()))
                {
                    isClaimed = true;
                    //調用對應的callBack
                    switch (eventCode)
                    {
                        case EventTouch::EventCode::MOVED:
                            if (listener->onTouchMoved)
                            {
                                listener->onTouchMoved(*touchesIter, event);
                            }
                            break;
                        case EventTouch::EventCode::ENDED:
                            if (listener->onTouchEnded)
                            {
                                listener->onTouchEnded(*touchesIter, event);
                            }
                            if (listener->_isRegistered)
                            {
                                listener->_claimedTouches.erase(removedIter);
                            }
                            break;
                        case EventTouch::EventCode::CANCELLED:
                            if (listener->onTouchCancelled)
                            {
                                listener->onTouchCancelled(*touchesIter, event);
                            }
                            if (listener->_isRegistered)
                            {
                                listener->_claimedTouches.erase(removedIter);
                            }
                            break;
                        default:
                            CCASSERT(false, "The eventcode is invalid.");
                            break;
                    }
                }
                
                // If the event was stopped, return directly.
                if (event->isStopped())
                {
                    updateListeners(event);
                    return true;
                }
                
                CCASSERT((*touchesIter)->getID() == (*mutableTouchesIter)->getID(), "");
                
				//假設接收該touch而且須要吞噬該touch。會有兩個影響
				//1.Touches(standard 觸摸機制)的觸摸操作都接收不到該touch了
				//2.由於返回值是true,在調用dispatchEventToListeners時。在該node之後的node將會不再接收該touch
                if (isClaimed && listener->_isRegistered && listener->_needSwallow)
                {
                    if (isNeedsMutableSet)
                    {
                        mutableTouchesIter = mutableTouches.erase(mutableTouchesIter);
                        isSwallowed = true;
                    }
                    return true;
                }
                
                return false;
            };
            
            //結合上面的dispatchEventToListeners的源代碼分析。能夠看出新版本號的OneByOne touch機制是這種:
			//1.listener依據Node的優先級排序後。依次響應。

值得註意的是,新版本號的優先級是依據Node的global Zorder來的。而不是2.x的觸摸優先級。

//2.當TouchEvent Began來了之後,全部的listener會依次影響Touch Began。

然後再依次響應Touch Move...而不是一個listener響應完 //began move end之後 輪到下一個listener響應的順序。 //3.吞噬操作僅僅有發生在began return true後才幹夠發生 dispatchEventToListeners(oneByOneListeners, onTouchEvent); if (event->isStopped()) { return; } if (!isSwallowed) ++mutableTouchesIter; } } // // process standard handlers 2nd // //相比於OneByOne。AllAtOnce要簡單很多。值得註意的是被吞噬的touch也不會被AllAtOnce響應到 if (allAtOnceListeners && mutableTouches.size() > 0) { auto onTouchesEvent = [&](EventListener* l) -> bool{ EventListenerTouchAllAtOnce* listener = static_cast<EventListenerTouchAllAtOnce*>(l); // Skip if the listener was removed. if (!listener->_isRegistered) return false; event->setCurrentTarget(listener->_node); switch (event->getEventCode()) { case EventTouch::EventCode::BEGAN: if (listener->onTouchesBegan) { listener->onTouchesBegan(mutableTouches, event); } break; case EventTouch::EventCode::MOVED: if (listener->onTouchesMoved) { listener->onTouchesMoved(mutableTouches, event); } break; case EventTouch::EventCode::ENDED: if (listener->onTouchesEnded) { listener->onTouchesEnded(mutableTouches, event); } break; case EventTouch::EventCode::CANCELLED: if (listener->onTouchesCancelled) { listener->onTouchesCancelled(mutableTouches, event); } break; default: CCASSERT(false, "The eventcode is invalid."); break; } // If the event was stopped, return directly. if (event->isStopped()) { updateListeners(event); return true; } return false; }; dispatchEventToListeners(allAtOnceListeners, onTouchesEvent); if (event->isStopped()) { return; } } updateListeners(event); }


非常多須要註意的地方我全給了中文標識。可是這裏我還要再次說明下新版本號的touch OneByOne機制: 1.listener依據Node的優先級排序後。依次響應。值得註意的是,新版本號的優先級是依據Node的global Zorder來的,而不是2.x的觸摸優先級。
2.當TouchEvent Began來了之後,全部的listener會依次影響Touch Began。然後再依次響應Touch Move...而不是一個listener響應完 began move end之後 輪到下一個listener響應的順序。
3.吞噬操作僅僅有發生在began return true後才幹夠發生

3.4.4 DispatchCustomEvent (新版本號的NotificationCenter機制)

void EventDispatcher::dispatchCustomEvent(const std::string &eventName, void *optionalUserData)
{
    EventCustom ev(eventName);
    ev.setUserData(optionalUserData);
    dispatchEvent(&ev);
}

好簡單,這個函數像不像 postNotification(......)?,在3.x的事件中。再也不要使用NotificationCenter了哦~

4.小結

Event,EventListener,EventDispatcher的關系 新的觸摸機制 新的NotificationCenter方法

cocos2d-x 源代碼分析 : EventDispatcher、EventListener、Event 源代碼分析 (新觸摸機制,新的NotificationCenter機制)