戲談cocos2d-x 2.0.4 Touch

先把跟Touch相關的類列一下: EAGLView  CCEGLView  CCEGLViewProtocol  EGLTouchDelegate  CCTouchDispatcher  CCTouchHandler  CCStandardTouchHandler  CCTargetedTouchHandler  CCTouchDelegate CCTargetedTouchDelegate  CCStandardTouchDelegate  CCLayer  CCTouch
EAGLView  真正的view Cocosd-x已經把各個平臺的view已經封裝成EAGLView.EAGLView中含有 
     1. -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event      2. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event      3. - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event      4. - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
     上訴四個方法能直接監聽反饋用戶的點擊事件。同時能獲取點擊的座標,以及有幾個手指點擊移動,再分別通過調用CCEGLViewProtocol的以下四個方法
     1.virtual void handleTouchesBegin(int num, int ids[], float xs[], float ys[]);
     2.virtual void handleTouchesMove(int num, int ids[], float xs[], float ys[]);
     3. virtual void handleTouchesEnd(int num, int ids[], float xs[], float ys[]);
     4.virtual void handleTouchesCancel(int num, int ids[], float xs[], float ys[]);
     將touches***方法中的信息傳遞到handleTouches***方法中.(其中通過cocos2d::CCEGLView::sharedOpenGLView()->handleTouches***(i, ids, xs, ys)來調用以上四個方法,sharedOpenGLView返回的是CCEGLView,由於CCEGLView是CCEGLViewProtocol的子類,不過handleTouches***這些方法的主要邏輯處理還是在CCEGLViewProtocol處理的)。CCEGLViewProtocol類中有個EGLTouchDelegate* m_pDelegate屬性,在handleTouches***方法中主要是把觸摸點point放到CCTouch中,再把其放入CCSet中。通過m_pDelegate->touches***(&set, NULL)方法將CCSet信息傳遞給CCTouchDispatcher。關於CCTouchDispatcher這個類,她可是出生於名門世家-EGLTouchDelegate,EGLTouchDelegate有四個我們熟悉的方法也就是:
     1.virtual void touchesBegan(CCSet* touches, CCEvent* pEvent) = 0;
     2.virtual void touchesMoved(CCSet* touches, CCEvent* pEvent) = 0;
     3.virtual void touchesEnded(CCSet* touches, CCEvent* pEvent) = 0;
     4.virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent) = 0;

CCEvent繼承於CCObject,關於CCTouch他也是繼承於CCObject,她能獲取
     1.CCPoint getLocation() const;
     2.CCPoint getPreviousLocation() const;
     3.CCPoint getStartLocation() const;
     4.CCPoint getDelta() const;
     5.CCPoint getLocationInView() const;
     6.CCPoint getPreviousLocationInView() const;
     7.CCPoint getStartLocationInView() const;

上訴四個方法都是虛函數,真正的實現方法都在CCTouchDispatcher中,但是在CCTouchDispatcher中的上訴四個方法其實也沒幹了什麼大不了的事情,他們都做了相同的事情就是統一回調了CCTouchDispatcher中的void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex)方法,根據uIndex來區分是Began呢還是Moved等相關事件,所以上面講了一堆,其實真正幹事情的就只有CCTouchDispatcher中的touches方法,通過這個方法把觸摸事件分發出去,那怎麼分發事件的呢?說道這,咱還是得回顧下其他知識。
  
     先聊聊CCTouchDelegate吧,這位老祖宗還真是祖宗。它有一堆的虛函數
     /*******CCTargetedTouchDelegate 單點觸摸*****/
     1.virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent); return false;};
     2.virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);}
     3.virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);}     4.virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouch); CC_UNUSED_PARAM(pEvent);}
     /**********CCStandardTouchDelegate****多點觸摸***********/
      5.virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}     6.virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}     7.virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}     8.virtual void ccTouchesCancelled(CCSet *pTouches, CCEvent *pEvent) {CC_UNUSED_PARAM(pTouches); CC_UNUSED_PARAM(pEvent);}
 
上訴CCTargetedTouchDelegate以及CCStandardTouchDelegate都是CCTouchDelegate的子類,分別對應於單點觸摸以及多點觸摸。當然CCTouchDelegate的子類還有CCLayer。CCLayer含有他爸的全部方法,也就是單點觸摸,多點觸摸的方法她都有了。當然不能同時響應單點觸摸以及多點觸摸,其實多點觸摸也就包含了單點觸摸。CCLayer是通過ccTouchesMode這個結構來區分單點觸摸以及多點觸摸的-kCCTouchesAllAtOnce/kCCTouchesOneByOne.

講了半天的CCTouchDelegate以及子類,那它怎麼跟CCTouchDispatcher勾搭上啊,其實很簡單,就只需要到CCTouchDispatcher註冊一下。接下來重點將下CCLayer是怎麼註冊的。CCLayer藏的很深,她僅僅就是讓我們通過CCLayer::setTouchEnabled(bool enabled)這個方法設置下是否能觸摸,她就去乖乖的到CCTouchDispatcher註冊去了。
下面具體看看setTouchEnabled做了啥事情吧,他去找了CCLayer中的registerWithTouchDispatcher()這個方法,在這個方法中,他會去到CCDirector中找到CCTouchDispatcher(CCTouchDispatcher* pDispatcher = CCDirector::sharedDirector()->getTouchDispatcher()),其實CCTouchDispatcher在CCDirector的初始化中,他就生出來了。找到CCTouchDispatcher後也就方便了,通過ccTouchesMode這個值判斷是去註冊單點呢,還是多點呢,CCLayer中ccTouchesMode默認值是kCCTouchesAllAtOnce。具體方法:pDispatcher->addStandardDelegate(this, 0);//標準多點觸摸。pDispatcher->addTargetedDelegate(this, m_nTouchPriority, true);//正統的單點觸摸,注意這個true,這玩意就是個火藥桶,如果他是true的時候,你一玩完,就偷偷的把CCSet中的CCTouch給釋放了,具體要看證據還是得在CCTouchDispatcher中的touches才能看到,當然他僅僅只針對單點觸摸,誰叫你單點啊。

好了現在也註冊到CCTouchDispatcher了,也是屬於有身份的合法公民了,跟着政府就好。那現在我們就看這個政府CCTouchDispatcher是怎麼管理這個觸摸小國家的吧。CCTouchDispatcher管理這個國家也不是親力親爲的,她也請了外援CCTouchHandler,這個Handler還拖家帶口的,有兩個親兒子CCStandardTouchHandler以及CCTargetedTouchHandler。
CCTouchHandler主要乾的啥事情呢?保存CCTouchDelegate以及priority這兩個東東。CCTouchDelegate就不需要怎麼說了,他到CCTouchDispatcher一報到,CCTouchDispatcher二話不說,把CCTouchDelegate以及CCTouchDelegate的priority直接扔給CCTouchHandler,給打包下。當然CCTouchHandler也不是蠻幹,先看看CCTouchDelegate你是CCTargetedTouchDelegate還是CCStandardTouchDelegate呀,CCTouchHandler驗明瞭CCTouchDelegate的身份之後自己也不直接上去,而是叫自己的兒子CCStandardTouchHandler以及CCTargetedTouchHandler兩個活寶上去打包的。打包方法:
    1.static CCTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority);//在該方法中會調用initWithDelegate
    2.virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority);
對了關於上面兩個方法對於CCStandardTouchHandler以及CCTargetedTouchHandler都有不同的個性化,特別是CCTargetedTouchHandler,誰叫他打包的是CCTargetedTouchDelegate呀,CCTargetedTouchDelegate這玩意有個bSwallowsTouches,是否吞了該觸摸。也就是在上文講到的true,在addTargetedDelegate中如果將bSwallowsTouches設爲true,則當你觸發完事件後,她就把你從觸發的點上刪除。所以此處CCTargetedTouchHandler針對CCTargetedTouchDelegate的特殊需求,也得滿足不是,我就把你的bSwallowsTouches一併打包和CCTouchDelegate以及nPriority。CCTouchHandler通過兩個乖兒子,把CCTouchDelegate相關屬性一併打包,就去向CCTouchDispatcher總理報到了。這到哪報到呢,就是上文說的void CCTouchDispatcher::addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority)以及void CCTouchDispatcher::addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches)這兩個方法啊。在這兩個方法中都能將打包好的CCTouchHandler,通過forceAddHandler這個方法,把她分別提交給m_pStandardHandlers以及m_pTargetedHandlers兩個CCArray*大官人那,哪天CCTouchDispatcher想找哪個CCTouchHandler的時候,直接找兩個大官人就好。好了上面說了一堆終於把CCTouchDelegate跟CCTouchDispatcher不得不說的事情說完了。

終於得做點事情了,前面也談到了當有觸摸事件來的時候,不管是Began還是Moved啥的,一併都去void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex);這個辦事處。這地方也就相當於總理大衙門-中南海,不管是觸摸的消息CCSet,還是CCTouchHandler都得在這交代的一清二百。上文所說的m_pStandardHandlers以及m_pTargetedHandlers通過遍歷找到CCTouchHandler,然後將CCTouchHandler總理處理的結果傳遞到下面各個小羅羅上。
1.pHandler->getDelegate()->ccTouchBegan(pTouch, pEvent);
2.pHandler->getDelegate()->ccTouchesBegan(pMutableTouches, pEvent);
pHandler->getDelegate()也就是被打包封裝的CCTouchDispatcher,現在就是被解綁了而已。

好了,說到這關於細說touch事情也差不多結束了。。。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章