cocos2d-x 源代碼分析 : EventDispatcher、EventListener、Event 源代碼分析 (新觸摸機制,新的NotificationCenter機制)
源代碼版本號來自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;
2.1.2 EventTouch
EventTouch是cocos2d-x引擎中很很重要的事件。相應於四種touch操作。該類內部定義了四種EventCodeenum 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不為空,則能夠覺得其是可用的。什麽是可用性,當在dispatcher進行事件分發時,假設一個Listener是不可用的。則不會將該事件分發給他。if (onTouchBegan == nullptr) { CCASSERT(false, "Invalid EventListenerTouchOneByOne!"); return false; } return true; }
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機制)