使用过CCLayer的都应该知道,CCLayer的众多父类中有CCTouchDelegate这么一个类,他使CCLayer能接收touch事件成为可能。cocos2d-x的touch事件是由CCTouchDispatcher这个touch分发器类来进行派发的,所有需要接收touch事件的对象都必须注册到CCTouchDispatcher中,而只有继承于CCTouchDelegate的对象才能被注册到touch分发器中。 先看看cocos2d-x的touch事件的触发流程,我们能看得见的游戏界面我且称之为视图(view),touch的产生正是从视图开始的,在程序的消息处理中心检测到touch事件时,将事件整理成CCTouch的集合并传递给注册在视图内的touch分发器CCTouchDispatcher,这个touch分发器是在导演类设置openglView的时候注册的://1、直接设置touch分发器void CCDirector::setTouchDispatcher(CCTouchDispatcher* pTouchDispatcher){ //设置touch分发器 if (m_pTouchDispatcher != pTouchDispatcher) { CC_SAFE_RETAIN(pTouchDispatcher); CC_SAFE_RELEASE(m_pTouchDispatcher); m_pTouchDispatcher = pTouchDispatcher; } }//2、导演类初始化的时候创建touch分发器bool CCDirector::init(void){ ...... //导演类初始化的时候生成touch分发器 m_pTouchDispatcher = new CCTouchDispatcher(); m_pTouchDispatcher->init(); ... ... return true;}void CCDirector::setOpenGLView(CCEGLView *pobOpenGLView){ CCAssert(pobOpenGLView, "opengl view should not be null"); if (m_pobOpenGLView != pobOpenGLView) { ...... //注册touch分发器到openglView中,接收view传递过来的touch事件 m_pobOpenGLView->setTouchDelegate(m_pTouchDispatcher); m_pTouchDispatcher->setDispatchEvents(true); }}在查看touch分发器怎么处理touch事件之前,先了解传递的数据CCTouch,CCtouch的数据很简单,只有属性:int m_nId;CCPoint m_point;CCPoint m_prevPoint;CCTouch.cpp:// returns the current touch location in screen coordinatesCCPoint CCTouch::getLocationInView() const{ //获取屏幕坐标 return m_point; } // returns the current previous location in screen coordinatesCCPoint CCTouch::getPreviousLocationInView() const{ //获取上一次的屏幕坐标 return m_prevPoint; } // returns the current touch location in OpenGL coordinatesCCPoint CCTouch::getLocation() const{ //获取在opengl坐标系中的坐标 return CCDirector::sharedDirector()->convertToGL(m_point); } // returns the previous touch location in OpenGL coordinatesCCPoint CCTouch::getPreviousLocation() const{ //获取上一次在opengl坐标系中的位置 return CCDirector::sharedDirector()->convertToGL(m_prevPoint); } // returns the delta position between the current location and the previous location in OpenGL coordinatesCCPoint CCTouch::getDelta() const{ //返回当前和上次位置在opengl坐标系中差值 return ccpSub(getLocation(), getPreviousLocation()); }CCTouch提供查询坐标点的接口。 所有能接收touch事件的对象都需要继承于CCTouchDelegate,这个类定义了接收touch事件的众多接口,CCTouchDelegateProtocol.h:class CC_DLL CCTouchDelegate{public: CCTouchDelegate() {} virtual ~CCTouchDelegate() { } virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent); return false;}; // optional virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} // optional virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} }; //此类型的触控对象,可以通过ccTouchBegan的返回值决定此次touch是否有后续的反馈//返回值为false的时候,此次touch后续的moved、ended、cancelled都不再反馈给此触控对象//具备touch阻断功能的触控对象 class CC_DLL CCTargetedTouchDelegate : public CCTouchDelegate { public: /** Return YES to claim the touch. @since v0 */ virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);return false;}; // optional virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);} }; //此类型的触控对象不具有阻止后续反馈的功能,一次touch事件,触控对象将接收到所有的后续反馈 //典型的触控对象接收多点触控数据 class CC_DLL CCStandardTouchDelegate : public CCTouchDelegate { public: // optional virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);} };其中定义了两种触控对象,一种是接收单触控并具有阻挡策略,另一种是接收多点触控 touch分发器中,将触控对象转换为触控对象句柄CCTouchHandler之后,才进行存储和处理的,CCTouchHandler.h://触控对象的句柄,相当于一个容器,保存了触控对象以及触控对象的触控优先级class CC_DLL CCTouchHandler : public CCObject{public: virtual ~CCTouchHandler(void); /** delegate */ //触控对象的获取与设置 CCTouchDelegate* getDelegate(); void setDelegate(CCTouchDelegate *pDelegate); /** priority */ //触控优先级的获取与设置 int getPriority(void); void setPriority(int nPriority); /** enabled selectors */ //好像没有什么用处 int getEnabledSelectors(void); void setEnalbedSelectors(int nValue); /** initializes a TouchHandler with a delegate and a priority */ //初始化触控句柄,参数为触控对象和触控优先级 virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority); public: /** allocates a TouchHandler with a delegate and a priority */ //创建一个触控句柄,参数为触控对象和触控优先级 static CCTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority); protected: CCTouchDelegate *m_pDelegate; int m_nPriority; int m_nEnabledSelectors;}; /** CCStandardTouchHandler It forwards each event to the delegate. */ //典型触控句柄class CC_DLL CCStandardTouchHandler : public CCTouchHandler{public: /** initializes a TouchHandler with a delegate and a priority */ virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority); public: /** allocates a TouchHandler with a delegate and a priority */ static CCStandardTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority);}; /** CCTargetedTouchHandler Object than contains the claimed touches and if it swallows touches. Used internally by TouchDispatcher *///具有touch阻断功能的触控句柄class CC_DLL CCTargetedTouchHandler : public CCTouchHandler{public: ~CCTargetedTouchHandler(void); /** whether or not the touches are swallowed */ //是否阻止touch事件冒泡,继续分发给接下来的其他对象 bool isSwallowsTouches(void); void setSwallowsTouches(bool bSwallowsTouches); /** MutableSet that contains the claimed touches */ //获取集合、此集合中保存了touch对象,针对这些touch对象,触控对象将接收他们的后续反馈 CCSet* getClaimedTouches(void); /** initializes a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */ bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow); public: /** allocates a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */ static CCTargetedTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow); protected: bool m_bSwallowsTouches; CCSet *m_pClaimedTouches;};触控对象句柄也有两种,单点触控对象句柄具有一个集合属性 CCSet *m_pClaimedTouches,用来存储得到认可的touch事件,使该事件的后续反馈将对这个触控对象有效。 接下来看看touch分发器的具体实现,看看他是怎么样分发touch消息的,主要分发逻辑在touches方法中。CCTouchDispatcher.h:#ifndef __TOUCH_DISPATCHER_CCTOUCH_DISPATCHER_H__#define __TOUCH_DISPATCHER_CCTOUCH_DISPATCHER_H__ #include "CCTouchDelegateProtocol.h"#include "cocoa/CCObject.h"#include "cocoa/CCArray.h" NS_CC_BEGIN /** * @addtogroup input * @{ */ typedef enum{ ccTouchSelectorBeganBit = 1 << 0, ccTouchSelectorMovedBit = 1 << 1, ccTouchSelectorEndedBit = 1 << 2, ccTouchSelectorCancelledBit = 1 << 3, ccTouchSelectorAllBits = ( ccTouchSelectorBeganBit | ccTouchSelectorMovedBit | ccTouchSelectorEndedBit | ccTouchSelectorCancelledBit),} ccTouchSelectorFlag; enum { CCTOUCHBEGAN, CCTOUCHMOVED, CCTOUCHENDED, CCTOUCHCANCELLED, ccTouchMax,}; class CCSet;class CCEvent; struct ccTouchHandlerHelperData { // we only use the type// void (StandardTouchDelegate::*touchesSel)(CCSet*, CCEvent*);// void (TargetedTouchDelegate::*touchSel)(NSTouch*, CCEvent*); int m_type;}; class CC_DLL EGLTouchDelegate{public: virtual void touchesBegan(CCSet* touches, CCEvent* pEvent) = 0; virtual void touchesMoved(CCSet* touches, CCEvent* pEvent) = 0; virtual void touchesEnded(CCSet* touches, CCEvent* pEvent) = 0; virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent) = 0; virtual ~EGLTouchDelegate() {}}; class CCTouchHandler;struct _ccCArray; class CC_DLL CCTouchDispatcher : public CCObject, public EGLTouchDelegate{public: ~CCTouchDispatcher(); bool init(void); CCTouchDispatcher() : m_pTargetedHandlers(NULL) , m_pStandardHandlers(NULL) , m_pHandlersToAdd(NULL) , m_pHandlersToRemove(NULL) {} public: /** Whether or not the events are going to be dispatched. Default: true */ //是否分发touch事件 bool isDispatchEvents(void); void setDispatchEvents(bool bDispatchEvents); /** Adds a standard touch delegate to the dispatcher's list. See StandardTouchDelegate description. IMPORTANT: The delegate will be retained. */ //添加接收touch事件的典型触控对象 void addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority); /** Adds a targeted touch delegate to the dispatcher's list. See TargetedTouchDelegate description. IMPORTANT: The delegate will be retained. */ //添加接受touch事件的,具有阻断功能的触控对象 void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches); /** Removes a touch delegate. The delegate will be released */ //移除触控对象 void removeDelegate(CCTouchDelegate *pDelegate); /** Removes all touch delegates, releasing all the delegates */ void removeAllDelegates(void); /** Changes the priority of a previously added delegate. The lower the number, the higher the priority */ void setPriority(int nPriority, CCTouchDelegate *pDelegate); void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex); virtual void touchesBegan(CCSet* touches, CCEvent* pEvent); virtual void touchesMoved(CCSet* touches, CCEvent* pEvent); virtual void touchesEnded(CCSet* touches, CCEvent* pEvent); virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent); public: CCTouchHandler* findHandler(CCTouchDelegate *pDelegate);protected: void forceRemoveDelegate(CCTouchDelegate *pDelegate); void forceAddHandler(CCTouchHandler *pHandler, CCArray* pArray); void forceRemoveAllDelegates(void); void rearrangeHandlers(CCArray* pArray); CCTouchHandler* findHandler(CCArray* pArray, CCTouchDelegate *pDelegate); protected: //两个队列,用来保存注册进来的单触控对象和多点触控对象 CCArray* m_pTargetedHandlers; CCArray* m_pStandardHandlers; //触控对象队列是否被锁定不可增删改 bool m_bLocked; //是否有触控对象在等待添加到触控队列中 bool m_bToAdd; //是否有触控对象在等待从触控队列中移除掉 bool m_bToRemove; //保存等待加入触控队列的触控对象 CCArray* m_pHandlersToAdd; //保存等待从触控队列中删除的触控对象 struct _ccCArray *m_pHandlersToRemove; //是否将推出 bool m_bToQuit; //是否分发touch事件 bool m_bDispatchEvents; // 4, 1 for each type of event struct ccTouchHandlerHelperData m_sHandlerHelperData[ccTouchMax];}; // end of input group/// @} NS_CC_END #endif // __TOUCH_DISPATCHER_CCTOUCH_DISPATCHER_H__