iPhone Coding Notes

~我的iPhone程式筆記~

在Cocos2d中使用touch event

最近網友的回應讓我想到,教學寫了那麼多,好像還沒教過怎麼處理觸控事件。實在是天大的疏忽,這個教學應該在早早之前就寫了說。iPhone唯一能讓使用者輸入的介面就是那一大片的觸控螢幕,如果一個iPhone app沒有觸控功能,那還搞屁啊?今天我們就來看看如何在程式裡處理觸控事件。

如果你已經看過其他iPone SDK的相關書籍,大概會知道,iPhone的觸控主要由三個函式方法負責:

﹣(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

﹣(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

﹣(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;


基本上看到函式的名稱就可以知道它所對應的功能。當使用者第一次按下螢幕時,touchesBegan的方法就會被觸發。如果使用者開啟移動,touchesMoved裡的程式便會被執行。最後一個touchesEnded就是當手指離開螢幕時要會觸發的函式。

這三個函式並沒有順序性的關係,也不需要三個函式的內容都寫,完全取決於這個app遇到對應的觸控事件時該怎麼處理對應的動作。

重點來了,如果你在cocos2d的CCLayer裡寫入這三個函式方法,是一點用處也沒有的,因為cocos2d有自己的觸控事件函式。但是也不用太擔心,基本上沒有什麼困難的地方,只不過就是在上述三個函式的名稱前加入cc兩個字而已:

﹣(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

﹣(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

﹣(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

至於為什麼要改名字,A兜。。。這個老實說我也不是很清楚,只能告訴你因為cocos2d並沒有直接繼承UIKit的類別,所以很多protocol都得重新稍微定義一下才行,大概是這個樣子。

好了,廢話不多說,來寫程式。這一次的程式目的是建立一個CCSprite物件,使用者可以觸碰這個物件並移動它,當使用者的手指離開螢幕後,物件會回到螢幕中心的位置。

前置作業就不再重覆了,開啟一個cocos2d專案,在HelloWorldScene.h裡的大括內加入

CCSprite *touchIcon;

接著到HelloWorldScene.m裡,把- (init)的部份改為下列程式碼:

-(id) init {
// always call “super” init
// Apple recommends to re-assign “self” with the “super” return value
if( (self=[super init] )) {

self.isTouchEnabled = YES;

touchIcon = [CCSprite spriteWithFile:@"Icon.png"];
[touchIcon setPosition:ccp(240,160)];
[touchIcon setOpacity:100];
[self addChild:touchIcon];
}
return self;
}

這裡比較重要的大概就是self.isTouchEnabled = YES這行,主要功能就是把接收觸控事件的功能打開,這樣等等加入的觸控函式才能發揮功用。剩下就只是touchIcon這個物件的一些相關設定,這次比較偷懶,連圖檔都不附了,反正cocos2d模版裡就有圖檔,我們就直接拿來用,省去大家還要下載的麻煩。

接著就是今天的重頭戲了,我們要加入負責接收觸控事件的三個函式。將下列程式碼加到HelloWorldScene.m裡:

- (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];

CGRect rect = CGRectMake(touchIcon.position.x -
touchIcon.contentSize.width/2, touchIcon.position.y -
touchIcon.contentSize.height/2,
touchIcon.contentSize.width, touchIcon.contentSize.height);

if (CGRectContainsPoint(rect, location)) {
[touchIcon setOpacity:255];
}
}

- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];

CGRect rect = CGRectMake(touchIcon.position.x -
touchIcon.contentSize.width/2, touchIcon.position.y -
touchIcon.contentSize.height/2,
touchIcon.contentSize.width, touchIcon.contentSize.height);

if (CGRectContainsPoint(rect, location)) {
[touchIcon setPosition:location];
}
}

- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];

CGRect rect = CGRectMake(touchIcon.position.x -
touchIcon.contentSize.width/2, touchIcon.position.y -
touchIcon.contentSize.height/2,
touchIcon.contentSize.width, touchIcon.contentSize.height);

if (CGRectContainsPoint(rect, location)) {
[touchIcon runAction:[CCMoveTo actionWithDuration:0.5             position:ccp(240,160)]];
[touchIcon setOpacity:100];
}
}

這三個函式的結構大同小異,所以這裡就將相同的部份統一說明。

首先看到的是

UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];

我們先建立一個UITouch物件myTouch,它的內容來自於touches。接著我們用locationInView這個方法從myTouch中取出觸碰的位置。最後一行相當重要,因為myTouch傳回的位置所用的座標原點是在螢幕左上角,但在cocos2d中所使用的座標原點則是在螢幕左下角,所以cocos2d提供了這個簡便的方法讓我們轉換兩者間的關係。這一步一定要記得做,不然到時觸控起來會很奇怪。

接著程式建立了一個CGrect,

CGRect rect = CGRectMake(touchIcon.position.x – touchIcon.contentSize.width/2, touchIcon.position.y – touchIcon.contentSize.height/2, touchIcon.contentSize.width, touchIcon.contentSize.height);

這是由Core Graphic所定義的矩形結構,我們用CGRectMake這個C語言函式來建立它。參數依序是矩形左下角的x和y值,以及矩形的寬和高。我們建立的這個大小就是touchIcon的範圍,有了這個範圍,我們再利用CGRectContainsPoint這個函式來判斷這個矩形是否有包函觸碰的位置。如果有,代表使用者按到這個圖形了,我們再依觸碰事件的種類來執行對應的動作,包括:

ccTouchesBegan:使用者第一次按到touchIcon,把圖檔的透明度調成255(即不再半透明)。

ccTouchesMoved:使用者開始移動手指,設定touchIcon的位置為手指移到的位置點。

ccTouchesEnded:使用者手指離開螢幕,此時令touchIcon執行回到中心點的動作,並將圖檔調回半透明。

趕快run一下你的程式,操作起來應該會下面的影片一樣。基本的觸控事件處理大概就是這麼一回事,是不是很簡單呢?

40 Responses to 在Cocos2d中使用touch event

  1.  Jack 2010/03/28 at 23:33:07

    哇~~太讚了,我一直在讀你的教學,每個我都有成功,真是太謝謝你了
    要加油喔~~~~今天你一貼上,我就試成功了~~~
    能不能再寫一篇三軸加速度計,如何讀取呀???

    謝謝了

    • bonjouryentinglai 2010/03/28 at 23:38:47

      呵呵,是忠實觀眾耶~應該要表揚一下~哈哈~
      加速度計的部份有空我會寫的,不過最近還滿忙的,又要寫程式又要寫部落格實在有點忙不太過來,還請您耐心等候^^

  2. jack 2010/03/29 at 21:24:11

    bonjouryentinglai :呵呵,是忠實觀眾耶~應該要表揚一下~哈哈~加速度計的部份有空我會寫的,不過最近還滿忙的,又要寫程式又要寫部落格實在有點忙不太過來,還請您耐心等候^^

    對了~~我們有三個人在寫iphone程式,有一個是美工,我想寫一個大一點的game,但是我們都是新手,不知你有沒有興趣參與~~~
    呵~~我們也都是工作之餘的~~~

    • bonjouryentinglai 2010/03/29 at 21:48:04

      只要有遊戲寫我都還滿感興趣的,不過最近有件急事要處理,大概要四月底才會結束,可能要那時才有空(好像有點太久了XD)。如果您不介意,是否方便在”About”的頁面留下您的聯絡方式,如果到時還缺人手或需要幫忙,我們可以再詳談^^

    • YH 2010/04/01 at 16:56:08

      我現在也都在寫iPhone程式,學寫iPhone也有一段時間了,一直對寫遊戲非常有興趣,不知道是不是可以參與你們?我的MSN是
      yuh_hung@yahoo.co.uk
      如果怕人多手雜,不介意的話還是可以加我一起討論或分享經驗也好:)

  3. Lemon 2010/03/30 at 22:18:40

    請問一下~~假設我今天畫面中有兩個可以被touch移動的sprite
    我要怎麼判斷這次是按到誰

    謝謝

    • bonjouryentinglai 2010/03/30 at 22:52:38

      通常的作法是,把畫面中所有的sprite放到一個array裡,然後用迴圈一個個去判斷這個sprite的rect有沒有包含touch的位置,有的話再對該sprite進行動作。

  4. Lemon 2010/04/03 at 16:57:09

    請問一下~~~如果我想用touchevent 傳送socket到PC要怎麼做?

    謝謝

  5. Lemon 2010/04/03 at 16:58:39

    Lemon :
    請問一下~~~如果我想用touchevent 傳送socket到PC要怎麼做?
    謝謝

    現在就差iPhone端的運作了

  6. Lemon 2010/04/09 at 23:53:40

    呵呵~~socket以解決了~~~

    期待版主發新文哩

    期待有加速度計的教學

    謝謝

  7. 2010/05/26 at 16:20:39

    我是剛進入cocos2d的新手,十分期待看板主的教學文,清楚易懂!!

    期待有新教學可以學習!!

  8. HeChian 2010/06/03 at 21:04:28

    最近剛好想學Cocos2D
    感謝您的教學,我終於抓到一點訣竅了
    謝謝

  9. chih 2010/07/31 at 08:04:39

    板大你好
    照著你的方法練習到這
    都還很順利也學到很多
    但是TOUCH這邊
    照著練習玩卻還是還無動靜
    也有嘗試 其他人的範例
    但依舊沒有動靜只好求助板大

    有一些小小問題想要先提問
    ﹣(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

    ﹣(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

    ﹣(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
    此三個方法 並非寫在INIT裡面是麼?
    就是要寫在外面吧!!

    此外 全部寫玩後編譯完
    會出現警告
    initialization from distinct Objective-C type
    此時 Simulator 中間出現圖片 但對TOUCH毫無反應
    SO
    我在HwlloWorldScene.h
    @end 前 把方法宣告上去
    警告消失了
    但simulator ㄧ樣是出現圖片 但對 touch還是無反應
    還是找不出問題在哪
    請板大OR其他高手 幫幫忙謝謝

    • 2010/07/31 at 09:37:10

      那三行需要做一點變動
      原本是
      [quote]
      ﹣(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

      ﹣(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

      ﹣(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
      [/quote]
      實際在寫的時候應該是
      [quote]
      ﹣(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
      }

      ﹣(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
      }

      ﹣(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
      }
      [/quote]
      寫在@implementation裡面,它們是message/method

  10. chih 2010/07/31 at 12:41:05

    謝謝樓上
    你指的變更是
    加上 大括號
    在裡面寫入實做 這樣麼?
    如果是
    那我應該沒打錯
    我是照版大的寫法 打上去的

  11. chih 2010/07/31 at 13:29:30

    嘗試的做了一個小範例

    在init裡面加入
    self.isTouchEnabled=YES;
    NSString*str1=@”asd”;
    NSLog(@”qwe%@”,str1);
    NSLog(@”mikeqwe”);

    並加入
    -(BOOL)ccTouchBegan:(NSSet*)touches withEvent:(UIEvent*)event{
    NSLog(@”bettyissobuty”);
    return YES;

    }

    執行結果
    2010-07-31 13:18:28.620 touchtest3[18030:20b] qweasd
    2010-07-31 13:18:28.621 touchtest3[18030:20b] mikeqwe
    2010-07-31 13:18:28.632 touchtest3[18030:20b] cocos2d: surface size: 320×480

    touch後 還是無反應

    thx

  12. 2010/07/31 at 13:34:09

    XCode右下角有沒有出現黃色的三角形Warning圖示?

  13. chih 2010/07/31 at 17:18:59

    終於發現原因了
    不好意思 勞煩兩位
    由於習慣在打到一半時
    直接按ESC 選擇方法
    反而導致盲點
    事實上應該是才對…
    -(BOOL)ccTouchesBegan:…..event

    但是用ESC 選擇的方法 卻是
    -(BOOL)ccTouchBegan:…..event
    差別在ccTouch”es”Bgan
    不知原因何在

    另外
    而一開始打錯時
    會出現警告
    initialization from distinct Objective-C type
    此時要去h黨宣告方法

    -(BOOL)ccTouchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
    是cocos2d自己的觸控事件函式
    所以不需再h檔宣告

    不知道 這樣推論是否正確

    另外謝謝版大的所有文章
    真的受益良多

  14. Amas 2010/08/12 at 10:57:24

    HI,你的教學很棒,但是我想問如果我有一張圖片,想把拉到螢幕下方,然後圖就會住下消息應該怎樣做?
    我的MSN:supercat5@hotmail.com
    希望大家能交流一下

  15. jones 2010/09/09 at 00:17:14

    板主可以請教一下題外話嗎
    COCOS2D做出來的APP一開始一定要跑出她們的官方圖片嗎
    有沒有辦法拿掉呢

  16. 小鯨 2010/10/21 at 23:20:55

    我想請教一下~只有文字也是用這個觸發嗎??
    我想他點某段字就跳出東西來~
    也是用這個觸發寫嗎?還是不用用到這個~~

    不好意思我是IPHONE超級新手~XD~

  17. Logan 2010/10/22 at 10:15:21

    cocos2d的资料还真不多,能找到楼主的文章真令我兴奋不已,我看了你几乎所有的文章,希望有空能向你讨教,请加我MSN : happy10086@gmail.com

  18. bonjouryentinglai 2010/10/22 at 10:51:58

    小鯨 :

    我想請教一下~只有文字也是用這個觸發嗎??
    我想他點某段字就跳出東西來~
    也是用這個觸發寫嗎?還是不用用到這個~~

    不好意思我是IPHONE超級新手~XD~

    在Objective-C裡,不管是文字還是圖片,都是一個物件。只要把文字當作是圖片,剩下的作法都一樣喔。
    如果是在cocos2d裡,文字會用CCLabel實作。

  19. dean 2010/10/22 at 19:36:50

    樓主教學太棒了~
    還有很多希望數主可以教一下~
    例如:
    virtual joystick 加按鈕怎樣做….用touch event 嗎?還是用menu button?
    1些橫向action遊戲的原理又怎樣做…背景怎樣跑….?
    萬分感謝:)

    • bonjouryentinglai 2010/10/24 at 01:47:28

      virtual joystick好像google搜尋一下就有現成的模組可以使用了。
      橫向遊戲的背景要怎麼跑喔?
      就。。。。方向鍵按右的時候,令背景向左移,您是要問這個嗎??

  20. bonjouryentinglai 2010/10/27 at 20:26:54

    dean :

    對喔~但圖檔好像有限width??
    那背景要換很多圖嚕..?

    是啊,就換吧~

  21. Simon Lin 2010/10/28 at 18:28:08

    覺得你的教學寫的很淺顯易懂…非常不容易…
    方便的話…
    想加您的msn…
    我的是zhihmeng@hotmail.com…
    謝謝囉…

  22. joseph 2010/11/03 at 10:17:08

    看了一些教學 真的很厲害

    如果方便的話想加您的msn

    我的是kite129@yahoo.com.tw

    感謝啦!!

  23. bonjouryentinglai 2010/11/03 at 11:18:16

    joseph :

    看了一些教學 真的很厲害

    如果方便的話想加您的msn

    我的是kite129@yahoo.com.tw

    感謝啦!!

    已經加囉~~
    這裡快變成加好友專區了….

  24. KK 2010/12/03 at 08:57:55

    你好~
    你寫的文章真棒,且淺顯易懂,我們專題剛好有要做這方面的事
    方便的話可以加你msn嗎,想跟你討論一些事情…>”<
    giwawamsl@hotmail.com
    感謝你~

發表迴響

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 變更 )

Twitter picture

You are commenting using your Twitter account. Log Out / 變更 )

Facebook照片

You are commenting using your Facebook account. Log Out / 變更 )

連結到 %s

Follow

Get every new post delivered to your Inbox.