最近学习了下cocos2dx3.x版本的事件响应和分发逻辑,由于3.x版本作者个人用的比较少,结果是看的一头雾水。这里简单的笔记下大概的代码流程吧,以后用的多了理解加深了在随时更新吧。
先看写基础的类的定义。
CONTENTS
CCEventTouch.h/cpp:
触摸事件类,继承了Event。用来管理触摸中的触摸点等。
#define TOUCH_PERF_DEBUG 1 class EventTouch : public Event { public: static const int MAX_TOUCHES = 5;//最多保存5个触摸点 enum class EventCode { BEGAN, MOVED, ENDED, CANCELLED };//触摸点的类型 EventTouch(); inline EventCode getEventCode() const { return _eventCode; }; inline const std::vector<Touch*>& getTouches() const { return _touches; }; #if TOUCH_PERF_DEBUG void setEventCode(EventCode eventCode) { _eventCode = eventCode; }; void setTouches(const std::vector<Touch*>& touches) { _touches = touches; }; #endif private: EventCode _eventCode; std::vector<Touch*> _touches; friend class GLViewProtocol; //将GLViewProtocol设置为友元类,由于各个平台实现不同,因此获取触摸点的方式不同,这里就不笔记了。 }; ====== EventTouch::EventTouch() : Event(Type::TOUCH) {//调用构造函数时,申请特定大小的vector,用来存储触摸点 _touches.reserve(MAX_TOUCHES); }
CCEventListenerTouch.h/cpp:
触摸事件响应类,继承自EventListener。用来管理各个回调函数。
class EventListenerTouchOneByOne : public EventListener { public: static const std::string LISTENER_ID; static EventListenerTouchOneByOne* create(); virtual ~EventListenerTouchOneByOne(); void setSwallowTouches(bool needSwallow); bool isSwallowTouches(); /// 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; private: EventListenerTouchOneByOne(); bool init(); std::vector<Touch*> _claimedTouches; bool _needSwallow; friend class EventDispatcher; }; class EventListenerTouchAllAtOnce : public EventListener { public: static const std::string LISTENER_ID; static EventListenerTouchAllAtOnce* create(); virtual ~EventListenerTouchAllAtOnce(); /// Overrides virtual EventListenerTouchAllAtOnce* clone() override; virtual bool checkAvailable() override; // 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: EventListenerTouchAllAtOnce(); bool init(); private: friend class EventDispatcher; };
EventDispatcher事件分发代码:
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 there aren't any touch listeners, return directly. 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()); // // process the target handlers 1st // //先处理特定目标响应(OneByOne) if (oneByOneListeners) { auto mutableTouchesIter = mutableTouches.begin(); auto touchesIter = originalTouches.begin(); for (; touchesIter != originalTouches.end(); ++touchesIter) { bool isSwallowed = false; //触摸响应函数表达式 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的target设为传入listener的node,非常重要。这样graphic级别的listener回调函数就可以获取到自己的node了 event->setCurrentTarget(listener->_node); bool isClaimed = false; std::vector<Touch*>::iterator removedIter; EventTouch::EventCode eventCode = event->getEventCode(); if (eventCode == EventTouch::EventCode::BEGAN) { if (listener->onTouchBegan) {//touchbegan时传入了第一个触摸点,返回是否处理 isClaimed = listener->onTouchBegan(*touchesIter, event); if (isClaimed && listener->_isRegistered) { listener->_claimedTouches.push_back(*touchesIter); //将这个起始触摸点放到vector中。用来判断该listener是否开始处理触摸了。个人认为用_claimedTouches来作为判断条件,而且这个成员变量的用途也很奇怪~~ } } } else if (listener->_claimedTouches.size() > 0 && ((removedIter = std::find(listener->_claimedTouches.begin(), listener->_claimedTouches.end(), *touchesIter)) != listener->_claimedTouches.end())) { //如果传入的点是MOVE型而且listener接受了响应(符合该if条件),那么就说明这些MOVE点也是被处理的。 //这样isClaimed会被设置成true。以便于后面判断是否需要Swallow。 isClaimed = true; switch (eventCode) { case EventTouch::EventCode::MOVED: if (listener->onTouchMoved) { listener->onTouchMoved(*touchesIter, event); } break; case EventTouch::EventCode::ENDED://当传入的触摸点的类型是ENDED时,调用onTouchEnded if (listener->onTouchEnded) { listener->onTouchEnded(*touchesIter, event); } if (listener->_isRegistered) {//结束后把_claimedTouches中的元素删掉。 listener->_claimedTouches.erase(removedIter); } break; case EventTouch::EventCode::CANCELLED://和ENDED差不多 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(), ""); //如果listener设置为Swallow,那么经过它处理的所有的点都要被删掉。 //这里采取的措施是通过for循环,处理一个点,删除一个点。 if (isClaimed && listener->_isRegistered && listener->_needSwallow) { if (isNeedsMutableSet) { mutableTouchesIter = mutableTouches.erase(mutableTouchesIter); isSwallowed = true; } return true; } return false; }; //调用函数表达式onTouchEvent dispatchEventToListeners(oneByOneListeners, onTouchEvent); if (event->isStopped()) { return; } //mutableTouches是拷贝自originalTouches的,因此初始时数据是相同的。 //所以如果没有Swallow,mutableTouchesIter也要随着循环增加而增加。 //保证在程序执行时,mutableTouchesIter和mutableTouchesIter指向的内容是对应的。 if (!isSwallowed) ++mutableTouchesIter; } } // // process standard handlers 2nd // //如果还有剩下的触摸点没有被吞噬,那么一次丢给标准触摸响应(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); }
发表评论