源码版本来自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机制)