事件和监听器 cocos2dx 3.0 中事件和监听器,结合CCEvent
和CCEventListener
的代码
Event
Listener
TOUCH
TOUCH_ONE_BY_ONE
TOUCH_ALL_AT_ONCE
KEYBOARD
KEYBOARD
ACCELERATION
ACCELERATION
MOUSE
MOUSE
CUSTOM
CUSTOM
EventListener::Type中还有一个UNKNOW
对于手机客户端来说,最常用的便是TouchEvent和AccelerationEvent
触摸 对于EventListenerTouch,这里有两种类型:
EventListenerTouchOneByOne 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class EventListenerTouchOneByOne : public EventListener{ public : static const std ::string LISTENER_ID; ... void setSwallowTouches (bool needSwallow) ; bool isSwallowTouches () ; ... 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; private : ... std ::vector <Touch*> _claimedTouches; bool _needSwallow; friend class EventDispatcher; };
其实最关键的一句话就是friend class EventDispatcher;
所有的操作都是在EventDispatcher中操作,所以重点分析的还是EventDispatcher
EventListenerTouchAllAtOnce 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class EventListenerTouchAllAtOnce : public EventListener{ public : static const std ::string LISTENER_ID; ... public : 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; private : friend class EventDispatcher; };
和EventListenerTouchOneByOne的区别在于不可吞噬,还有就是回调函数的区别
分发器 成员变量 接下来便是成员变量,这里面有太多的表和集合,第一时间还不是很知道在搞毛。
1 2 3 4 5 6 7 enum class DirtyFlag{ NONE = 0 , FIXED_PRIORITY = 1 << 0 , SCENE_GRAPH_PRIORITY = 1 << 1 , ALL = FIXED_PRIORITY | SCENE_GRAPH_PRIORITY };
Type
Name
Usage
<string, EventListenerVector*>
_listenerMap
查找这种监听器对应的监听器数组
<ListenerID, DirtyFlag>
_priorityDirtyFlagMap;
表示这种监听器的标志位类别
<Node*, vector<EventListener*>*>
_nodeListenersMap;
根据Node去查找对应的监听器数组
<Node*, int>
_nodePriorityMap;
根据Node查找优先级表,用于排序
<float, vector<Node*>>
_globalZOrderNodeMap;
根据全局Z轴查找的Node节点数组,用于生成_nodePriorityMap
vector<EventListener*>
_toAddedListeners;
待加加入分发数组的监听器
set<Node*>
_dirtyNodes;
待更新标识的显示顺序监听器
int
_inDispatch;
在分发中的事件个数
bool
_isEnabled;
是否开启事件分发
int
_nodePriorityIndex
在生成_nodePriorityMap的时候的公共索引
set<string>
_internalCustomListenerIDs
EventListenerVector 先看一个Dispatcher的内置类EventListenerVector
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 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; };
这个EventListenerVector实际上就是管理两个 std::vector
带有优先级的监听器 (_fixedListeners)
按显示顺序的监听器 (_sceneGraphListeners)
Event内置类型
Event
ListenerID
EventListenerTouchOneByOne
__cc_touch_one_by_one
EventListenerTouchAllAtOnce
__cc_touch_all_at_once
EventListenerKeyBoard
__cc_keyboard
EventListenerMouse
__cc_mouse
EventListenerAcceleration
__cc_acceleration
添加监听器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* Listener, Node *node){ if (!listener->checkAvailable()) return ; listener->setAssociatedNode(node); listener->setFixedPriority(0 ); listener->setRegistered(true ); addEventListener(listener); } void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority){ if (!listener->checkAvailable()) return ; listener->setAssociatedNode(nullptr ); listener->setFixedPriority(fixedPriority); listener->setRegistered(true ); listener->setPaused(false ); addEventListener(listener); } EventListenerCustom* EventDispatcher::addCustomEventListener(const std ::string &eventName, const std ::function<void (EventCustom*)>& callback) { EventListenerCustom *listener = EventListenerCustom::create(eventName, callback); addEventListenerWithFixedPriority(listener, 1 ); return listener; } void EventDispatcher::addEventListener(EventListener* listener){ if (_inDispatch == 0 ) { forceAddEventListener(listener); } else { _toAddedListeners.push_back(listener); } listener->retain(); } void EventDispatcher::forceAddEventListener(EventListener* listener){ EventListenerVector* listeners = nullptr ; EventListener::ListenerID listenerID = listener->getListenerID(); auto itr = _listenerMap.find(listenerID); if (itr == _listenerMap.end()) { listeners = new EventListenerVector(); _listenerMap.insert(std ::make_pair(listenerID, listeners)); } else { listeners = itr->second; } listeners->push_back(listener); if (listener->getFixedPriority() == 0 ) { setDirty(listenerID, DirtyFlag::SCENE_GRAPH_PRIORITY); auto node = listener->getAssociatedNode(); CCASSERT(node != nullptr , "Invalid scene graph priority!" ); associateNodeAndEventListener(node, listener); if (node->isRunning()) { resumeEventListenersForTarget(node); } } else { setDirty(listenerID, DirtyFlag::FIXED_PRIORITY); } }
为啥对于按显示顺序的监听器
不需要setPaused(false)?
对于这类监听器,setPaused是会在onEnter和onExit的过程中调用到。 (详见Node::resume && Node::pause) (最后还是调用EventDispatcher::pauseEventListenersForTarget, EventDispatcher::resumeEventListenersForTarget)
EventDispatcher::resumeEventListenersForTarget 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void EventDispatcher::resumeEventListenersForTarget(Node* target, bool recursive){ auto listenerIter = _nodeListenersMap.find(target); if (listenerIter != _nodeListenersMap.end()) { auto listeners = listenerIter->second; for (auto & l : *listeners) l->setPaused(false ); } setDirtyForNode(target); if (recursive) { const auto & children = target->getChildren(); for (const auto & child : children) resumeEventListenersForTarget(child, true ); } }
事件分发 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 void EventDispatcher::dispatchEvent(Event* event){ if (!_isEnabled) return ; updateDirtyFlagForSceneGraph(); DispatchGuard guard (_inDispatch) ; if (event->getType() == Event::Type::TOUCH) { dispatchTouchEvent(static_cast <EventTouch*>(event)); return ; } auto listenerID = __getListenerID(event); sortEventListeners(listenerID); auto iter = _listenerMap.find(listenerID); if (iter != _listenerMap.end()) { auto listeners = iter->second; auto onEvent = [&event](EventListener* listener) -> bool { event->setCurrentTarget(listener->getAssociatedNode()); listener->_onEvent(event); return event->isStopped(); }; dispatchEventToListeners(listeners, onEvent); } updateListeners(event); }
分发触摸事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 void EventDispatcher::dispatchTouchEvent(EventTouch* event){ sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID); sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID); auto oneByOneListeners = getListeners(EventListenerTouchOneByOne::LISTENER_ID); auto allAtOnceListeners = getListeners(EventListenerTouchAllAtOnce::LISTENER_ID); if (nullptr == oneByOneListeners && nullptr == allAtOnceListeners) return ; bool isNeedsMutableSet = (oneByOneListeners && allAtOnceListeners); const std ::vector <Touch*>& originalTouches = event->getTouches(); std ::vector <Touch*> mutableTouches(originalTouches.size()); std ::copy(originalTouches.begin(), originalTouches.end(), mutableTouches.begin()); if (oneByOneListeners) { auto mutableTouchesIter = mutableTouches.begin(); auto touchesIter = originalTouches.begin(); for (; touchesIter != originalTouches.end(); ++touchesIter) { bool isSwallowed = false ; auto onTouchEvent = [&](EventListener* l) -> bool { ... }; dispatchEventToListeners(oneByOneListeners, onTouchEvent); if (event->isStopped()) return ; if (!isSwallowed) ++mutableTouchesIter; } } if (allAtOnceListeners && mutableTouches.size() > 0 ) { auto onTouchesEvent = [&](EventListener* l) -> bool { ... }; dispatchEventToListeners(allAtOnceListeners, onTouchesEvent); if (event->isStopped()) return ; } updateListeners(event); }