李華明Himi 原創,轉載務必在明顯處註明:轉載自【黑米GameDev街區】 原文連結: http://www.himigame.com/iphone-cocos2d/450.html-----------------------------------本章補充開始!---------------------------------- 本篇對於多觸點和觸屏事件已經做了一個詳細的說明,但是有一點忽略了,就是開啟多觸點的支援!步驟如下: 首先進入AppDelegate.m 類中, [cpp] view plaincopy<strong>- (void) applicationDidFinishLaunching:(UIApplication*)application{}</strong> 在上面這個方法中添加如下一句開啟多觸點支援的代碼:[cpp] view plaincopy<strong> //支援多觸點 [viewController.view setMultipleTouchEnabled:YES];</strong> 其他類設定多觸點:[[[CCDirector sharedDirector]openGLView]setMultipleTouchEnabled:YES];--------------------------本章補充完畢------------------------------------------------------------------------------最近幾天一直在啃cocos2d,消化了不少東西,基本可以有些把握下手寫公司的遊戲了;那麼今天就把一些重點的拿出來分享下經驗,給新童鞋們作為參考;這篇就來詳細介紹下cocos2d對使用者觸屏的監聽事件進行下分析(cocos2d有很多詳細的文章和教程,我這裡只是出於自己的理解來說)進入正題:從整體cocos2d對觸屏的事件監聽可以分為兩種:1.單一監聽,所謂單一監聽其實是跟cocos2d引擎架構有關,因為在cocos2d中每個遊戲介面都可以使用一個CCLayout完成,那麼當一個CCLayout在螢幕顯示出來後,想要監聽使用者的按鍵事件,一般都會使用以下形式來進行監聽:(注意:這裡是CCLayout類進行監聽的方式)首先開啟監聽:[cpp] view plaincopyself.isTouchEnabled=YES; 然後重寫監聽函數即可:[cpp] view plaincopy//監聽首次觸發事件 - (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { } //觸摸事件 - 當手指在螢幕上進行移動 - (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { } //觸摸事件 - 當手指從螢幕抬起時調用的方法 -(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { } 此種監聽狠eazy,但是要注意這裡是對CCLayout類進行的監聽方式;2.監聽分發; 剛才說了,遊戲的每個介面可能都是一個CCLayout,但是如果我想讓一個CCSprite精靈主角單獨進行監聽,或者說在CCLayout有很多個精靈我想單獨監聽其中的一種的時候,這時候就需要使用監聽分發的形式了;假設我們自訂了一個類XX繼承CCSprite,還有一個YY類也繼承CCSprite,而且XX類型與YY類的執行個體都存在於一個Layout上,那麼我想對XX與YY類型分別單獨監聽的話;首先我們先讓當前繼承的CCSprite類的XX於YY類都使用 <CCTargetedTouchDelegate>協議;(CCSprite中沒有 self.isTouchEnabled=YES; 這個函數,別直接寫這個哦~) 代碼如下:[cpp] view plaincopy@interface XX : CCSprite <CCTargetedTouchDelegate>{ } 然後在當前實作類別中重寫一個函數如下:[cpp] view plaincopy-(void) registerWithTouchDispatcher { [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES]; } 或者將註冊的這句代碼,放在重寫的onEnter函數中也可;(此函數是註冊監聽,如果裡面什麼都不寫,則當前不會相應任何觸屏事件;)重寫觸摸的各事件函數,如下:[cpp] view plaincopy//監聽首次觸發事件 - (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { return NO; } //監聽移動事件 - (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event { } //監聽離開事件 - (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event { } 大家可以看到,此種監聽方式除了各種監聽函數與第一種類似之外,在 ccTouchBegan的函數有個傳回型別-布爾值;那麼其作用下面詳細介紹;如果XX與YY類都實現了第二種監聽方式的話,那麼當使用者觸屏後,(目前使用者觸發的是XX與YY類執行個體所在的CCLayout)首先會進入XX或者YY的其中的ccTouchBegan函數中,這裡假設首先進入了XX類中,那麼XX類中的ccTouchBegan將會被響應,如果return true;表示不再將使用者觸屏的訊息傳遞給YY類中進行響應,也就是說不再響應YY類中的ccTouchBegan函數,那麼如果 return false;則會將當前觸屏資訊傳遞給其他註冊過的類型中;一句話概括:return 的值,如果是真則表明使用者觸摸事件已經被處理,其他不會再去進行監聽;如果為假,則會繼續交給其他註冊過的類型中進行處理;那麼第二種監聽的方式比較常用,這樣便於處理,那麼至於註冊,一般都是放在 onEnter函數中;onEnter函數是每個CCScene之間切換會被響應的函數,相當於是CCScene的生命週期函數,具體調用順序如下:[cpp] view plaincopy//使用[CCDirector replaceScene:XX],替換情境時,會調用以下3個方法 //調用順序依次為: //1.othterScene的+(id)Scene——> //2.otherScene的init——> //3.otherScene的onEnter——> //4.運行過渡效果 //5.當前Scene的onExit函數——> //6.otherLayout的onEnterTransitionDidFinish() //7.當前Scene的dealoc函數 -(void) onEnter{ //調用其他Scene的init方法以後會調用此方法 //如果使用了CCTransitionScene,本方法將在過渡效果開始後調用 //(如果不調用super onEnter新情境可能對觸摸和加速計無發應) [super onEnter]; } -(void) onEnterTransitionDidFinish{ //調用onEnter後會調用此函數 //如果使用了CCTransitionScene,將會在過渡效果完成時調用此方法 [super onEnterTransitionDidFinish]; } -(void)onExit{ //在調用dealloc之前會調用此函數; //如果使用了CCTransitionScene,將會在過渡效果結束以後調用此方法 //(如果不調用super onExit,當前情境可能不會從記憶體中釋放) [super onExit]; } 那麼大概介紹了監聽事件後,那麼觸屏中最關心的就應該是多觸點啦;[cpp] view plaincopy//-----擷取多點觸摸 NSSet *allTouches = [event allTouches]; UITouch *touchOne = [[allTouches allObjects]objectAtIndex:0]; UITouch *touchTwo = [[allTouches allObjects]objectAtIndex:1]; //...類推 擷取多點狠簡單,那麼下面再將基本常用到的幾個判斷寫下:1-判斷使用者單擊還是雙擊(針對一個觸點)[cpp] view plaincopy</pre><p></p><pre name="code" class="cpp">if([allTouches count]==1) { UITouch *touchOne = [[allTouches allObjects]objectAtIndex:0]; switch ([touchOne tapCount]) { case 1: //單擊 CCLOG(@"%@",@"單擊"); break; case 2: //雙擊 CCLOG(@"%@",@"雙擊"); break; } } 1-判斷使用者兩個觸點之間是合攏還是分開(針對兩個觸點)[cpp] view plaincopy</pre><p></p><p class="p1"></p><pre name="code" class="cpp"> <pre name="code" class="cpp">if([allTouches count]==2) { //適當修改處理,不能同時取,否則肯定一樣的啦(可以一個在began 一個在end) UITouch *touchOne = [[allTouches allObjects]objectAtIndex:0]; UITouch *touchTwo = [[allTouches allObjects]objectAtIndex:1]; CGFloat *disFirst =[self distance:[touchOne locationInView:[self view]] todistance:[touchTwo locationInView:[self view]]]; UITouch *touchOne = [[allTouches allObjects]objectAtIndex:0]; UITouch *touchTwo = [[allTouches allObjects]objectAtIndex:1]; CGFloat *disFinal =[self distance:[touchOne locationInView:[self view]] todistance:[touchTwo locationInView:[self view]]]; if (disFirst>disFinal) { CCLOG(@"%@",@"合攏"); }else{ CCLOG(@"%@",@"分開"); } } 這裡我就粗略的寫在一起,判定兩個觸點是否合攏其實就是使用者剛觸屏時記錄兩點之間的距離記做disFirst,然後在兩個觸點離開螢幕(或者移動事件中)的時候計算當前的兩個觸點的距離disFinal,那麼最後根據disFirst與disFinal距離關係就能知道是合攏還是分開;(CCLOG 是cocos2d封裝的列印方法,此種列印在編譯發布正式遊戲程式的時候是不會編譯到程式中的,但是NSLOG會一直存在!要注意!)最後給出兩個函數,用於計算不同方式監聽的函數中擷取(轉換)座標的,因為cocos2d是openGL進行搭建的架構,所以需要座標轉換;[cpp] view plaincopy+(CGPoint) locationFromTouches:(NSSet*)touches { return [self locationFromTouch:[touches anyObject]]; } +(CGPoint) locationFromTouch:(UITouch*)touch { CGPoint touchLocation = [touch locationInView: [touch view]]; return [[CCDirector sharedDirector] convertToGL:touchLocation]; } 兩個方法一看就能看出區別,一個是UITouch的,一個是NSSet,一個是單一監聽,一個是分發監聽;ok,本章就到這裡~~~(下周進入封閉開發了,吃睡都在公司了,咳咳,帶上我的多啦a夢的小褲衩,娃哈哈~)要講的問題主要是在使用註冊監聽(事件分配方式監聽觸屏)中的問題,上一章節中說過,此種方式首先要註冊:如下代碼:[cpp] view plaincopy//註冊獨立觸摸事件 [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES]; 那麼如果多個註冊監聽的話,可以根據優先順序(priority)參數進行設定,此參數的值越大,優先順序越低,假設有XX與YY註冊了監聽,如果XX優先順序>YY的話,那麼首先會進入XX的監聽函數;使用上面的方式進行監聽的話,會進行監聽以下這幾個事件:[cpp] view plaincopy- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event { return NO; } - (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event { } - (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event { } 如果XX中的ccTouchBegan函數中返回Yes的話,就不會響應其他監聽的(YY)中重寫的監聽函數;這個上一章節中介紹過;但是要說的也正是這裡,如果你想要XX與YY都監聽事件,那麼兩個都可以在ccTouchBegan中返回NO,但是如果你想在處理YY或者XX中的ccTouchMoved移動事件函數中的話,你會發現XX與YY都不會響應其函數,原因是,當你retrun NO;的時候雖然執行了ccTouchBegan與return之間的代碼,但是你return NO其實就是告訴cocos2d放棄此次事件處理,讓cocos2d繼續將觸屏事件分配給其他註冊過的類去處理監聽,直到結束或者cocos2d擷取到return true為止;那麼解決的方案:比如你想監聽YY類中的ccTouchMoved事件,那麼為了不影響XX中的監聽ccTouchBegan事件,你應該讓XX類在註冊監聽的時候讓其優先順序調整高於YY類,並且XX類中ccTouchBegan函數return NO,那麼當使用者觸屏後,首先進入XX類中處理事件,然後會(因為XX類return NO)進入YY類,那麼在YY類的ccTouchBegan函數中因為return YES;這樣cocos2d就能響應ccTouchMoved函數了;如果說你想讓XX與YY類都響應ccTouchMoved函數,至少我利用此種事件分配的方式無法實現,不知道是不是cocos2d的1.0版本遺留的BUG還是其他原因,今天遇到所以拿出來跟大家分享;