
[历史归档]本文原发布于 cstriker1407.info 个人博客内容为历史存档仅供参考。发布时间2014-07-11 标题cocos2dx学习笔记cocos2dx3.x版本触摸事件响应简单笔记分类编程 / C C / cocos2dx 标签cocos2dx·事件响应·EventDispatchercocos2dx学习笔记cocos2dx3.x版本触摸事件响应简单笔记CCEventTouch.h/cpp:CCEventListenerTouch.h/cpp:EventDispatcher事件分发代码最近学习了下cocos2dx3.x版本的事件响应和分发逻辑由于3.x版本作者个人用的比较少结果是看的一头雾水。这里简单的笔记下大概的代码流程吧以后用的多了理解加深了在随时更新吧。先看写基础的类的定义。CCEventTouch.h/cpp:触摸事件类继承了Event。用来管理触摸中的触摸点等。#defineTOUCH_PERF_DEBUG1classEventTouch:publicEvent{public:staticconstintMAX_TOUCHES5;//最多保存5个触摸点enumclassEventCode{BEGAN,MOVED,ENDED,CANCELLED};//触摸点的类型EventTouch();inlineEventCodegetEventCode()const{return_eventCode;};inlineconststd::vectorTouch*getTouches()const{return_touches;};#ifTOUCH_PERF_DEBUGvoidsetEventCode(EventCode eventCode){_eventCodeeventCode;};voidsetTouches(conststd::vectorTouch*touches){_touchestouches;};#endifprivate:EventCode _eventCode;std::vectorTouch*_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::functionbool(Touch*,Event*)onTouchBegan;std::functionvoid(Touch*,Event*)onTouchMoved;std::functionvoid(Touch*,Event*)onTouchEnded;std::functionvoid(Touch*,Event*)onTouchCancelled;private:EventListenerTouchOneByOne();boolinit();std::vectorTouch*_claimedTouches;bool_needSwallow;friendclassEventDispatcher;};classEventListenerTouchAllAtOnce:publicEventListener{public:staticconststd::string LISTENER_ID;staticEventListenerTouchAllAtOnce*create();virtual~EventListenerTouchAllAtOnce();/// OverridesvirtualEventListenerTouchAllAtOnce*clone()override;virtualboolcheckAvailable()override;//public:std::functionvoid(conststd::vectorTouch*,Event*)onTouchesBegan;std::functionvoid(conststd::vectorTouch*,Event*)onTouchesMoved;std::functionvoid(conststd::vectorTouch*,Event*)onTouchesEnded;std::functionvoid(conststd::vectorTouch*,Event*)onTouchesCancelled;private:EventListenerTouchAllAtOnce();boolinit();private:friendclassEventDispatcher;};EventDispatcher事件分发代码voidEventDispatcher::dispatchTouchEvent(EventTouch*event){//首先对两个触摸响应函数进行排序sortEventListeners(EventListenerTouchOneByOne::LISTENER_ID);sortEventListeners(EventListenerTouchAllAtOnce::LISTENER_ID);//获取两个类别的触摸响应函数autooneByOneListenersgetListeners(EventListenerTouchOneByOne::LISTENER_ID);autoallAtOnceListenersgetListeners(EventListenerTouchAllAtOnce::LISTENER_ID);// If there arent any touch listeners, return directly.if(nullptroneByOneListenersnullptrallAtOnceListeners)return;boolisNeedsMutableSet(oneByOneListenersallAtOnceListeners);conststd::vectorTouch*originalTouchesevent-getTouches();//把传入的触摸事件拷贝一份因为处理特定目标响应时可能会吞噬掉部分触摸事件。这里拷贝一份用来实现吞噬原数据就不会被更改了。std::vectorTouch*mutableTouches(originalTouches.size());std::copy(originalTouches.begin(),originalTouches.end(),mutableTouches.begin());//// process the target handlers 1st////先处理特定目标响应OneByOneif(oneByOneListeners){automutableTouchesItermutableTouches.begin();autotouchesIteroriginalTouches.begin();for(;touchesIter!originalTouches.end();touchesIter){boolisSwallowedfalse;//触摸响应函数表达式autoonTouchEvent[](EventListener*l)-bool{// Return true to breakEventListenerTouchOneByOne*listenerstatic_castEventListenerTouchOneByOne*(l);// Skip if the listener was removed.if(!listener-_isRegistered)returnfalse;//将event的target设为传入listener的node非常重要。这样graphic级别的listener回调函数就可以获取到自己的node了event-setCurrentTarget(listener-_node);boolisClaimedfalse;std::vectorTouch*::iterator removedIter;EventTouch::EventCode eventCodeevent-getEventCode();if(eventCodeEventTouch::EventCode::BEGAN){if(listener-onTouchBegan){//touchbegan时传入了第一个触摸点返回是否处理isClaimedlistener-onTouchBegan(*touchesIter,event);if(isClaimedlistener-_isRegistered){listener-_claimedTouches.push_back(*touchesIter);//将这个起始触摸点放到vector中。用来判断该listener是否开始处理触摸了。个人认为用_claimedTouches来作为判断条件而且这个成员变量的用途也很奇怪~~}}}elseif(listener-_claimedTouches.size()0((removedIterstd::find(listener-_claimedTouches.begin(),listener-_claimedTouches.end(),*touchesIter))!listener-_claimedTouches.end())){//如果传入的点是MOVE型而且listener接受了响应符合该if条件那么就说明这些MOVE点也是被处理的。//这样isClaimed会被设置成true。以便于后面判断是否需要Swallow。isClaimedtrue;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(isClaimedlistener-_isRegisteredlistener-_needSwallow){if(isNeedsMutableSet){mutableTouchesItermutableTouches.erase(mutableTouchesIter);isSwallowedtrue;}returntrue;}returnfalse;};//调用函数表达式onTouchEventdispatchEventToListeners(oneByOneListeners,onTouchEvent);if(event-isStopped()){return;}//mutableTouches是拷贝自originalTouches的因此初始时数据是相同的。//所以如果没有SwallowmutableTouchesIter也要随着循环增加而增加。//保证在程序执行时mutableTouchesIter和mutableTouchesIter指向的内容是对应的。if(!isSwallowed)mutableTouchesIter;}}//// process standard handlers 2nd////如果还有剩下的触摸点没有被吞噬那么一次丢给标准触摸响应AllAtOnceif(allAtOnceListenersmutableTouches.size()0){autoonTouchesEvent[](EventListener*l)-bool{EventListenerTouchAllAtOnce*listenerstatic_castEventListenerTouchAllAtOnce*(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);}