1. 程式人生 > >Cocos2d-x之CCTouchDispatcher事件分發

Cocos2d-x之CCTouchDispatcher事件分發

使用過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 coordinates CCPoint CCTouch::getLocationInView() const {      //獲取螢幕座標     return m_point;  }                // returns the current previous location in screen coordinates CCPoint CCTouch::getPreviousLocationInView() const {      //獲取上一次的螢幕座標     return m_prevPoint;  }                // returns the current touch location in OpenGL coordinates CCPoint CCTouch::getLocation() const {      //獲取在opengl座標系中的座標     return CCDirector::sharedDirector()->convertToGL(m_point);  }                // returns the previous touch location in OpenGL coordinates CCPoint CCTouch::getPreviousLocation() const {      //獲取上一次在opengl座標系中的位置     return CCDirector::sharedDirector()->convertToGL(m_prevPoint);   }                // returns the delta position between the current location and the previous location in OpenGL coordinates CCPoint 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__