[历史归档]本文原发布于 cstriker1407.info 个人博客,内容为历史存档,仅供参考。
发布时间:2014-07-11| 标题:cocos2dx学习笔记:cocos2dx3.x版本触摸事件响应简单笔记|分类:编程 / C && C++ / cocos2dx |标签:cocos2dx·事件响应·EventDispatcher
cocos2dx学习笔记:cocos2dx3.x版本触摸事件响应简单笔记
- CCEventTouch.h/cpp:
- CCEventListenerTouch.h/cpp:
- EventDispatcher事件分发代码:
最近学习了下cocos2dx3.x版本的事件响应和分发逻辑,由于3.x版本作者个人用的比较少,结果是看的一头雾水。这里简单的笔记下大概的代码流程吧,以后用的多了理解加深了在随时更新吧。
先看写基础的类的定义。
CCEventTouch.h/cpp:
触摸事件类,继承了Event。用来管理触摸中的触摸点等。
#defineTOUCH_PERF_DEBUG1classEventTouch:publicEvent{public:staticconstintMAX_TOUCHES=5;//最多保存5个触摸点enumclassEventCode{BEGAN,MOVED,ENDED,CANCELLED};//触摸点的类型EventTouch();inlineEventCodegetEventCode()const{return_eventCode;};inlineconststd::vector<Touch*>&getTouches()const{return_touches;};#ifTOUCH_PERF_DEBUGvoidsetEventCode(EventCode eventCode){_eventCode=eventCode;};voidsetTouches(conststd::vector<Touch*>&touches){_touches=touches;};#endifprivate:EventCode _eventCode;std::vector<Touch*>_touches;friendclassGLViewProtocol;//将GLViewProtocol设置为友元类,由于各个平台实现不同,因此获取触摸点的方式不同,这里就不笔记了。};======EventTouch::EventTouch():Event(Type::TOUCH){//调用构造函数时,申请特定大小的vector,用来存储触摸点_touches.reserve(MAX_TOUCHES);}CCEventListenerTouch.h/cpp:
触摸事件响应类,继承自EventListener。用来管理各个回调函数。
classEventListenerTouchOneByOne:publicEventListener{public:staticconststd::string LISTENER_ID;staticEventListenerTouchOneByOne*create();virtual~EventListenerTouchOneByOne();voidsetSwallowTouches(boolneedSwallow);boolisSwallowTouches();/// OverridesvirtualEventListenerTouchOneByOne*clone()override;virtualboolcheckAvailable()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();boolinit();std::vector<Touch*>_claimedTouches;bool_needSwallow;friendclassEventDispatcher;};classEventListenerTouchAllAtOnce:publicEventListener{public:staticconststd::string LISTENER_ID;staticEventListenerTouchAllAtOnce*create();virtual~EventListenerTouchAllAtOnce();/// OverridesvirtualEventListenerTouchAllAtOnce*clone()override;virtualboolcheckAvailable()override;//public:std::function<void(conststd::vector<Touch*>&,Event*)>onTouchesBegan;std::function<void(conststd::vector<Touch*>&,Event*)>onTouchesMoved;std::function<void(conststd::vector<Touch*>&,Event*)>onTouchesEnded;std::function<void(conststd::vector<Touch*>&,Event*)>onTouchesCancelled;private:EventListenerTouchAllAtOnce();boolinit();private:friendclassEventDispatcher;};EventDispatcher事件分发代码:
voidEventDispatcher::dispatchTouchEvent(EventTouch*event){//首先对两个触摸响应函数进行排序sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID);//获取两个类别的触摸响应函数autooneByOneListeners=getListeners(EventListenerTouchOneByOne::LISTENER_ID);autoallAtOnceListeners=getListeners(EventListenerTouchAllAtOnce::LISTENER_ID);// If there aren't any touch listeners, return directly.if(nullptr==oneByOneListeners&&nullptr==allAtOnceListeners)return;boolisNeedsMutableSet=(oneByOneListeners&&allAtOnceListeners);conststd::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){automutableTouchesIter=mutableTouches.begin();autotouchesIter=originalTouches.begin();for(;touchesIter!=originalTouches.end();++touchesIter){boolisSwallowed=false;//触摸响应函数表达式autoonTouchEvent=[&](EventListener*l)->bool{// Return true to breakEventListenerTouchOneByOne*listener=static_cast<EventListenerTouchOneByOne*>(l);// Skip if the listener was removed.if(!listener->_isRegistered)returnfalse;//将event的target设为传入listener的node,非常重要。这样graphic级别的listener回调函数就可以获取到自己的node了event->setCurrentTarget(listener->_node);boolisClaimed=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来作为判断条件,而且这个成员变量的用途也很奇怪~~}}}elseif(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){caseEventTouch::EventCode::MOVED:if(listener->onTouchMoved){listener->onTouchMoved(*touchesIter,event);}break;caseEventTouch::EventCode::ENDED://当传入的触摸点的类型是ENDED时,调用onTouchEndedif(listener->onTouchEnded){listener->onTouchEnded(*touchesIter,event);}if(listener->_isRegistered){//结束后把_claimedTouches中的元素删掉。listener->_claimedTouches.erase(removedIter);}break;caseEventTouch::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);returntrue;}CCASSERT((*touchesIter)->getID()==(*mutableTouchesIter)->getID(),"");//如果listener设置为Swallow,那么经过它处理的所有的点都要被删掉。//这里采取的措施是通过for循环,处理一个点,删除一个点。if(isClaimed&&listener->_isRegistered&&listener->_needSwallow){if(isNeedsMutableSet){mutableTouchesIter=mutableTouches.erase(mutableTouchesIter);isSwallowed=true;}returntrue;}returnfalse;};//调用函数表达式onTouchEventdispatchEventToListeners(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){autoonTouchesEvent=[&](EventListener*l)->bool{EventListenerTouchAllAtOnce*listener=static_cast<EventListenerTouchAllAtOnce*>(l);// Skip if the listener was removed.if(!listener->_isRegistered)returnfalse;event->setCurrentTarget(listener->_node);//标准触摸响应就比较简单了,直接根据事件的类型调用响应的对应的回调函数即可。switch(event->getEventCode()){caseEventTouch::EventCode::BEGAN:if(listener->onTouchesBegan){listener->onTouchesBegan(mutableTouches,event);}break;caseEventTouch::EventCode::MOVED:if(listener->onTouchesMoved){listener->onTouchesMoved(mutableTouches,event);}break;caseEventTouch::EventCode::ENDED:if(listener->onTouchesEnded){listener->onTouchesEnded(mutableTouches,event);}break;caseEventTouch::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);returntrue;}returnfalse;};dispatchEventToListeners(allAtOnceListeners,onTouchesEvent);if(event->isStopped()){return;}}updateListeners(event);}