1. 程式人生 > >[轉載] 在Tiled Map中使用碰撞檢測

[轉載] 在Tiled Map中使用碰撞檢測

網上這篇教程的轉載非常氾濫,本來以為沒什麼參考價值。但是當我實際用上 tiledmap 做點東西時,發現TiledMap軟體本身,以及TMXTiledMap類的使用確實存在一些疑惑。所以,對於想真正使用 tiledmap 軟體做地圖的童鞋來說,這篇文章還是值得仔細看一遍的。文章裡用的是 cocos2d 引擎,還是 objc 程式碼, 但是在cocos2dx 3.0 裡依然適用.在此轉載,以作備忘。




        在這篇教程裡,我們會講解如何使用cocos2d和Tiled Map Editor建立一個基於tiled map的遊戲.作為例子,我們會製作一個小遊戲.遊戲的主要內容是一個忍者在沙漠裡尋找可口的西瓜吃.
        這篇教程主要學習的內容有:
  1. 如何建立Tiled Map。
  2. 如何將地圖載入到遊戲內。
  3. 如何讓地圖跟隨玩家滾動;如何使用物件層。
  4. 如何在地圖裡建立可碰撞(不可穿越)區域。
  5. 如何使用tile屬性。
  6. 如何使用可碰撞物體和動態修改地圖。
  7. 如何確定你的主角沒有產生穿越
        如果你是個iphone開發新手,作為基礎知識的準備,我建議你先閱讀一下How To Make A Simple iPhone Game with Cocos2D Tutorial Series.

建立遊戲骨架
      下面我們要建立遊戲骨架.並且準備好需要的資原始檔,開啟XCode,File\New Project,選擇cocos2d Application建立一個新工程。
      接下來,

下載這個zip檔案,這裡麵包含了遊戲需要的資源:

  • 主角精靈
  • 一些遊戲音效(使用cxfr工具製作)
  • 遊戲背景音(使用Garage Band製作,詳細資訊)
  • 用於構造tiled map的元件
  • 一些特殊的元件,後面會詳細解釋

       將下載到的資源解包拖入xcode的resources組,記得選中”Copy items into destination group’s folder(if needed)”。
       這樣,一切準備就緒.

建立遊戲地圖
       Cocos2d支援使用開源軟體Tiled Map Editor(貌似被偉大的牆擋住了,天朝的使用者可以直接訪問它在sourceforge的專案主頁

,杯具!)建立的TMX格式地圖.如果你訪問上面的連結,你會發現有兩個版本可用.
一個使用Qt應用程式框架編寫,另一個使用Java編寫.這是因為最初Tiled MapEditor使用Java編寫,後來移植到Qt框架上.使用哪個版本都可以.在這篇教程裡,我們以使用Qt版本的為例,因為它將作為今後的開發主線.
有些人喜歡使用java版本,是因為還有些老版本上的功能尚未移植到Qt框架上.

        執行Tiled Map Editor,新建一個地圖.填寫如下對話方塊:

        

        在orientation選項內,可以選擇Orthogonal(平面直角)或Isometric(45度視角,傳說中的2.5D),這裡選擇Orthogonal.
       接下來需要設定地圖大小.這裡的數值是指有多少格tiled元件,並不是畫素.選擇50×50即可.
       最後,確定tile元件的大小.根據美工提供的元件大小設定.這個教成立,我們使用32×32的大小.接下來,將tile元件新增到地圖內繪製地圖.在Map選單許做呢New Tileset,填寫下面的對話方塊:
       
       點選Browser從電腦裡找到tmw_desert_spacing.png檔案(下載的資源包內)
      保持長寬資料為32×32.
      對於margin和spacing,我沒有找到文件說明,但是我認為它們的意義是:
  • Margin 表示當前tiled在開始搜尋實際畫素時應該忽略多少個畫素 (譯者注:我理解應該是兩個tiled元件之間的間距)
  • Spacing 表示讀取下一個tiled資料後應該向前推進多少個畫素(譯者注:我理解應該是兩個tiled元件之間的空隙,不過,這好像與Margin重複了…)
        如果你仔細觀察tmw_desert_spacing.png,你會發現每個tiled元件之間都有1畫素的黑邊.這樣的圖片需要將margin和spacing設定為1
        

         點選OK,tiled元件將被顯示在Tilesets視窗內.現在你可以開始繪製地圖了.點選工具條上的Stamp(印章)圖示,選擇一個tiled元件,在地圖內需要的位置點選放置地圖元件.
         

          按上面的方法繪製一張地圖. 至少在地圖上繪製幾個建築,因為後面我們要用到它們.
         

          一些快速技巧最好記住:
  • 你可以一次新增多個tiled元件到地圖裡.(畫一個方塊選中多個tiled元件).
  • 可以使用油漆筒按鈕填充地圖背景.
  • 可以在view選單裡放大縮小地圖.
           畫好地圖後,雙擊Layers窗口裡的層(一般是取名為Layer1),改名為Background.在File選單內選擇Save,將地圖儲存到xcode專案內,取名tiledmap.tmx

           將Tiled Map新增到Cocos2d Scene中,將剛才建立的tmx檔案拖入專案resources內.開啟HelloWorldLayer.h檔案,新增一些程式碼:

#import "cocos2d.h"// HelloWorld Layer@interface HelloWorld : CCLayer
{
    CCTMXTiledMap 
*_tileMap;
    CCTMXLayer 
*_background;

}
@property (nonatomic, retain) CCTMXTiledMap 
*tileMap;
@property (nonatomic, retain) CCTMXLayer 
*background;
// returns a Scene that contains the HelloWorld as the only child+(id) scene;

@end
            在HelloWorldLayer.m新增程式碼:
// Import the interfaces#import "HelloWorldScene.h"// HelloWorld implementation@implementation HelloWorld

// Right after the implementation section@synthesize tileMap = _tileMap;
@synthesize background 
= _background;

// Replace the init method with the following-(id) init
{
    
if( (self=[super init] )) {
       
        self.tileMap 
= [CCTMXTiledMap tiledMapWithTMXFile:@"TileMap.tmx"];
        self.background 
= [_tileMap layerNamed:@"Background"];
       
        [self addChild:_tileMap z:
-1];
       
    }
    
return self;
}

+(id) scene
{
    
// 'scene' is an autorelease object.    CCScene *scene = [CCScene node];
   
    
// 'layer' is an autorelease object.    HelloWorld *layer = [HelloWorld node];
   
    
// add layer as a child to scene    [scene addChild: layer];
   
    
// return the scenereturn scene;
}

// on "dealloc" you need to release all your retained objects- (void) dealloc
{
    self.tileMap 
= nil;
    self.background 
= nil;
    [super dealloc];
}
@end

           這裡我們呼叫CCTMXTiledMap從map檔案建立了一個地圖.

          關於CCTMXTiledMap的一些簡要介紹
  • 它是CCNode的子類.所以我們可以設定position, scale等.
  • 這個node包含著地圖的層,並且包含一些函式使你可以通過名字找到它們.
  • 為了提高效能,每一層使用的都是CCSpriteSheet的子 類. 這也意味著每個tiled元件在每一層都只有一個例項.
          接下來我們要做的是利用地圖和層的引用把他們新增到HelloWorld層,編譯執行程式碼,你將能夠看到地圖的左下角.
          

          看起來不錯!不過作為一個遊戲,我們還需要做三件事:
  1. 一個遊戲主角;
  2. 一個放置主角的起始點;
  3. 移動檢視,讓我們的視角一直跟隨主角.
          這些才是開發這個遊戲關鍵工作,我們一個個解決.

物件層和設定Tiled Map的位置.
       Tiled Map Editor支援兩種層: tile layers(鋪展層,前面我們使用過)和object layers(物件層).
       Object layers 允許你以一點為中心在地圖上圈定一個區域.這個區域內可以觸發一些事件.比如:你可以製作一個區域來產生怪物,或者製作一個區域進去就會死亡.在我們的例子裡,我們製作一個區域作為主角的產生點.


        開啟TiledMapEditor,在Layer選單選擇Add Object Layer.新layer取名objects.注意,在object layer裡不會繪製tiled元件,它會繪製一些灰色的圓角形狀.你可以展開或者移動這些形狀.
       我們是想選擇一個tile元件作為主角的進入點.所以,在地圖裡點選一個tiled元件,產生的形狀的大小無所謂,我們會使用x,y座標來指定.
        

        接下來,右鍵選擇剛才新增的灰色形狀,點選Properties.設定名字為 “SpawnPoint”

       也許你可以設定這個物件的Type為Cocos2D的類名.並且它會建立一個物件(比如CCSprite),但是我沒有找到原始碼裡如何完成這些工作.不管它,我們保留type區域為空,它將建立一個NSMutableDictionary用來訪問物件的各種引數,比如x,y座標.儲存地圖回到xcode.

        修改HelloWorldScene.h
// Inside the HelloWorld class declarationCCSprite *_player;
 
// After the class declaration@property (nonatomic, retain) CCSprite *player;
        修改HelloWorldScene.m
// Right after the implementation section@synthesize player = _player;
 
// In deallocself.player = nil;
 
// Inside the init method, after setting self.backgroundCCTMXObjectGroup *objects = [_tileMap objectGroupNamed:@"Objects"];
NSAssert(objects 
!= nil, @"'Objects' object group not found");
NSMutableDictionary 
*spawnPoint = [objects objectNamed:@"SpawnPoint"];        
NSAssert(spawnPoint 
!= nil, @"SpawnPoint object not found");
int x = [[spawnPoint valueForKey:@"x"] intValue];
int y = [[spawnPoint valueForKey:@"y"] intValue];
 
self.player 
= [CCSprite spriteWithFile:@"Player.png"];
_player.position 
= ccp(x, y);
[self addChild:_player];
 
[self setViewpointCenter:_player.position];

         我們先花一點時間解釋一下object layer和object groups.
                首先,      我們通過CCTMXTiledMap物件的objectGroupNamed方法取回object layers.這個方法返回的是一個CCTMXObjectGroup物件.
                接下來,  呼叫CCTMXObjectGroup物件的objectNamed方法得到包含一組重要資訊的NSMutableDictionary.包括x,y座標,寬度,高度等.
                在這裡,  我們主要需要的是x,y座標.我們取得座標並用它們來設定主角精靈的位置.
                最後,      我們要把主角作為視覺中心來顯示.現在,新增下面的程式碼:
-(void)setViewpointCenter:(CGPoint) position
{
    CGSize winSize 
= [[CCDirector sharedDirector] winSize];
 
    
int x = MAX(position.x, winSize.width /2);
    
int y = MAX(position.y, winSize.height /2);
    x 
= MIN(x, (_tileMap.mapSize.width * _tileMap.tileSize.width)
        
- winSize.width /2);
    y 
= MIN(y, (_tileMap.mapSize.height * _tileMap.tileSize.height)
        
- winSize.height/2);
    CGPoint actualPosition 
= ccp(x, y);
 
    CGPoint centerOfView 
= ccp(winSize.width/2, winSize.height/2);
    CGPoint viewPoint 
= ccpSub(centerOfView, actualPosition);
    self.position 
= viewPoint;
 
}

        同樣做一下簡要的解釋.想象這個函式是把視線設定到取景中心.我們可以在地圖裡設定任何x,y座標,但是有些座標不能正確的處理顯示.比如,我們不能讓顯示區域超出地圖的邊界.否則就會出現空白區.下面的圖片更能說明這個問題:
        
        螢幕的寬高計算後,要與顯示區域的寬高做相應的適配.我們需要檢測螢幕到達地圖邊緣的情況.
       在cocos2d裡本來有一些操控camera(可以理解為可視取景區)的方法,但是使用它可能搞得更復雜.還不如靠直接移動layer裡的元素來解決更簡單有效.
       繼續看下面這張圖:
      

        把整張地圖想象為一個大的世界,我們的可見區是其中的一部分.主角實際的座標並不是世界實際的中心.但是在我們的視覺內,要把主角放在中心點,所以,我們只需要根據主角的座標便宜,調整世界中心的相對位置就可以了.
       實現的方法是把實際中心與螢幕中心做一個差值,然後把HelloWorld Layer設定到相應的位置.好,現在編譯執行,我們會看到小忍者出現在螢幕上.
       

使主角移動
       前面進行的都不錯,但是到目前為止,我們的小忍者還不會動.
       接下來,我們讓小忍者根據使用者在螢幕上點選的位置方向來移動(點選螢幕上半部分向上移,依此類推),修改HelloWorldScene.m的程式碼:
// Inside init methodself.isTouchEnabled = YES;
 
-(void) registerWithTouchDispatcher
{
    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self
            priority:
0 swallowsTouches:YES];
}
 
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    
return YES;
}
 
-(void)setPlayerPosition:(CGPoint)position {
    _player.position 
= position;
}
 
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
 
    CGPoint touchLocation 
= [touch locationInView: [touch view]];      
    touchLocation 
= [[CCDirector sharedDirector] convertToGL: touchLocation];
    touchLocation 
= [self convertToNodeSpace:touchLocation];
 
    CGPoint playerPos 
= _player.position;
    CGPoint diff 
= ccpSub(touchLocation, playerPos);
    
if (abs(diff.x) > abs(diff.y)) {
        
if (diff.x >0) {
            playerPos.x 
+= _tileMap.tileSize.width;
        } 
else {
            playerPos.x 
-= _tileMap.tileSize.width;
        }    
    } 
else {
        
if (diff.y >0) {
            playerPos.y 
+= _tileMap.tileSize.height;
        } 
else {
            playerPos.y 
-= _tileMap.tileSize.height;
        }
    }
 
    
if (playerPos.x <= (_tileMap.mapSize.width * _tileMap.tileSize.width) &&
        playerPos.y 
<= (_tileMap.mapSize.height * _tileMap.tileSize.height) &&
        playerPos.y 
>=0&&
        playerPos.x 
>=0 )
    {
            [self setPlayerPosition:playerPos];
    }
 
    [self setViewpointCenter:_player.position];
 
}

         首先,我們在init方法裡設定螢幕接受觸控事件.接下來,覆蓋registerWithTouchDispatcher方法來註冊我們自己的觸控事件控制代碼.
這樣,ccTouchBegan/ccTouchEnded方法會在觸控發生時回撥(單點觸控),並且遮蔽掉ccTouchesBegan/ccTouchesEnded方法的回撥(多點觸控)

        你可能奇怪,為什麼不能使用ccTouchesBegan/ccTouchesEnded方法呢?是的,我們的確可以使用,但是不建議這麼做,有兩點原因:
  • 你不需要再處理NSSets,事件分發器會幫你處理它們,你會在每次觸控得到獨立的回撥.
  • 你可以在ccTouchBegan事件返回YES來告知delegate這事你想要的事件,這樣你可以在move/ended/cancelled等後續的事件裡方便的處理.這比起使用多點觸控要省去很多的工作.
         通常,我們會將觸控的位置轉換為view座標系,然後再轉換為GL座標系.這個例子裡的小變化,只是呼叫了一下 [self convertToNodeSpace:touchLocation].

         這是因為觸控點給我們的是顯示區的座標,而我們其實已經移動過地圖的位置.所以,呼叫這個方法來得到便宜後的座標.

         接下來,我們要搞清楚觸控點與主角位置的相對關係.然後根據向量的正負關係,決定主角的移動方向.我們相應的調節主角的位置,然後設定螢幕中心到主角上. 

         注意: 我們需要做一個安全檢查,不要讓我們的主角移出了地圖. 
         
          好了,現在可以編譯運行了,嘗試觸控式螢幕幕來移動一下小忍者吧.
         

       這裡是根據這篇教程完成的程式碼:猛擊這裡下載

        接下來,我們將學習如何在地圖裡建立可碰撞(不可穿越)區域,如何使用tile屬性,如何使用可碰撞物體和動態修改地圖,如何確定你的主角沒有產生穿越。

Tiled Maps和碰撞

        你可能注意到了,上一篇裡完成的遊戲,小忍者可以穿過各種障礙。它是忍者,不是上帝!所以,我們要想辦法讓地圖裡的障礙物產生碰撞(不可穿越)。
有很多辦法可以解決這個問題(包括使用物件層objects layers),但是我準備告訴你種新技術,我認為這種技術更有效,同時也是作為學習課程的好素材。使用meta layer和層屬性。廢話少說,我們開始吧。

        用Tiled Map Editor開啟之前建立的地圖,點選Layer選單的Add TileLayer取名Meta。我們會在這一層上放置一些假的Tile指示特殊的tile元件。點選Map選單的NewTileset,選擇meta_tile.png圖片。將Margin和Spacing設定為1。
你會在Tilesets視窗看到meta_tiles的標籤。
       

        這些tiles元件其實沒什麼特別的,只是帶有透明特性的紅色和綠色方塊。我們擬定紅色表示“可碰撞”的(綠色的後面會用到)。選中Meta層,選擇印章(stamp)工具,選擇紅色tile元件。把它繪製到忍者不能穿越的地方。繪製好之後,看起來應該是這樣的:
       

       接下來,我們要給這些Tile元件設定一些標記屬性,這樣在程式碼裡我們可以確定哪些tile元件是不可穿越的。在Tilesets窗口裡右鍵點選紅色tile元件。新增一個新的屬性Collidable”,設定值為true。
     
      儲存地圖,回到xcode。修改HelloWorldScene.h檔案。
// Inside the HelloWorld class declarationCCTMXLayer *_meta;
 
// After the class declaration@property (nonatomic, retain) CCTMXLayer *meta;
[\cc]
修改HelloWorldScene.m檔案
[cc lang
="objc"]
// Right after the implementation section@synthesize meta = _meta;
 
// In deallocself.meta = nil;
 
// In init, right after loading backgroundself.meta = [_tileMap layerNamed:@"Meta"];
_meta.visible 
= NO;
 
// Add new method- (CGPoint)tileCoordForPosition:(CGPoint)position {
    
int x = position.x / _tileMap.tileSize.width;
    
int y = ((_tileMap.mapSize.height * _tileMap.tileSize.height) - position.y) / _tileMap.tileSize.height;
    
return ccp(x, y);
}

        簡單的對上面的程式碼做一些解釋。我們定義了一個CCTMXLayer物件meta作為類成員。注意,我們將這個層設定為不可見,因為它只是用來處理碰撞的。
       接下來我們編寫了一個tileCoordForPosition方法,用來將x,y座標轉換為地圖網格座標。地圖左上角為(0,0)右下角為(49,49)。

       上面帶有座標顯示的截圖來自java版本的編輯器。順便說一聲,我覺得在Qt版本里這個功能可能不再會被移植了。
        不管怎麼樣,用地圖網格座標要比用x,y座標方便。得到x座標比較方便,但是y座標有點麻煩,因為在cocos2d裡,是以左下作為原點的。也就是說,y座標的向量與地圖網格座標是相反的。
       接下來,我們要修改一下setPlayerPosition方法。
CGPoint tileCoord = [self tileCoordForPosition:position];
int tileGid = [_meta tileGIDAt:tileCoord];
if (tileGid) {
    NSDictionary 
*properties = [_tileMap propertiesForGID:tileGid];
    
if (properties) {
        NSString 
*collision = [properties valueForKey:@"Collidable"];
        
if (collision && [collision compare:@"True"== NSOrderedSame) {
            
return;
        }
    }
}
_player.position 
= position;
        這裡,我們將主角的座標系從x,y座標(左下原點)系轉換為tile座標系(左上原點)。接下來,我們使用meta layer裡的tileGIDAt函式獲取tile座標系裡的GID。噢?什麼是GID? GID應該是“全域性唯一標識”(我認為).但是在這個例子裡,把它作為tile層的id更貼切。

       我們使用GID來查詢tile層的屬性,返回值是一個包含屬性列表的dictionary。我們檢查“Collidable”屬性是否設定為ture。如果是,則說明不可以穿越。很好,編譯執行工程,你再也不能走入你在tile裡設定為紅色的區域了。
        

動態改變Tiled Maps

       現在,你的小忍者可以在地圖上漫遊了,不過,整個遊戲還是略顯沉悶。
       假設我們的小忍者非常餓,那麼我們設定一些食物,讓小忍者可以找到並吃掉它們。

        為了實現這個想法,我們要建立一個前端層,承載所有用於觸碰(吃掉)的物體。這樣,我們可以在忍者吃掉它們的同時,方便的從層上刪除它。並且背景層不受任何影響。

      開啟Tiled Map Editor,Layer選單的Add Tile Layer。命名新層為Foreground。選中這個層,新增一些可觸碰的物件。我比較喜歡用西瓜。
      

      接下來,要讓西瓜變為可觸碰的。這次我們用綠色方塊來標記。記得要在meta_tiles裡做這件事。
      

      同樣的,給綠色方塊新增屬性“Collectable”設定值為 “True”.
     儲存地圖,回到xcode。修改程式碼: //in HelloWorldScene.h:
// Inside the HelloWorld class declarationCCTMXLayer *_foreground;
 
// After the class declaration@property (nonatomic, retain) CCTMXLayer *foreground; //in HelloWorldScene.m
// Right after the implementation section@synthesize foreground = _foreground;
 
// In deallocself.foreground = nil;
 
// In init, right after loading backgroundself.foreground = [_tileMap layerNamed:@"Foreground"];
 
// Add to setPlayerPosition, right after the if clause with the return in itNSString *collectable = [properties valueForKey:@"Collectable"];
if (collectable && [collectable compare:@"True"== NSOrderedSame) {
    [_meta removeTileAt:tileCoord];
    [_foreground removeTileAt:tileCoord];
}

        這裡有個基本的原則,要同時刪除meta layer 和the foreground layer的匹配物件。編譯執行,小忍者可以吃到美味的甜西瓜了。
       

建立分數計數器
       小忍者現有吃有喝很開心,但是,我們想知道到底他吃了多少個西瓜。
       通常,我們在layer上看著順眼的地方加個label來顯示數量。但是,我們一直在移動層,這樣會給我們帶來很多的困擾。
       這是一個演示在一個場景裡使用多個層的好例子。我們保留HelloWorld層來進行遊戲,同時,增加一個HelloWorldHud層用來顯示label(Hub = heads up display)。
       當然,這兩個層需要一些方法來互相通訊。Hub層需要知道小忍者吃到了西瓜。有很多很多方法實現兩個層之間的通訊,但是我們使用盡量簡單的方法來實現。我們會讓HelloWorld層管理一個HelloworldHub層的引用,在忍者遲到西瓜的時候,可以呼叫一個方法來通知Hub層。修改程式碼:
// HelloWorldScene.h
// Before HelloWorld class declaration@interface HelloWorldHud : CCLayer
{  
    CCLabel 
*label;
}
 
- (void)numCollectedChanged:(int)numCollected;
@end
 
// Inside HelloWorld class declarationint _numCollected;
HelloWorldHud 
*_hud;
 
// After the class declaration@property (nonatomic, assign) int numCollected;
@property (nonatomic, retain) HelloWorldHud 
*hud;
// HelloWorldScene.m
// At top of file@implementation HelloWorldHud
 
-(id) init
{
    
if ((self = [super init])) {
        CGSize winSize 
= [[CCDirector sharedDirector] winSize];
        label 
= [CCLabel labelWithString:@"0" dimensions:CGSizeMake(5020)
            alignment:UITextAlignmentRight fontName:
@"Verdana-Bold"
            fontSize:
18.0];
        label.color 
= ccc3(0,0,0);
        
int margin =10;
        label.position 
= ccp(winSize.width - (label.contentSize.width/2)
            
- margin, label.contentSize.height/2+ margin);
        [self addChild:label];
    }
    
return self;
}
 
- (void)numCollectedChanged:(int)numCollected {
    [label setString:[NSString stringWithFormat:
@"%d", numCollected]];
}
 
@end
 
// Right after the HelloWorld implementation section@synthesize numCollected = _numCollected;
@synthesize hud 
= _hud;
 
// In deallocself.hud = nil;
 
// Add to the +(id) scene method, right before the returnHelloWorldHud *hud = [HelloWorldHud node];    
[scene addChild: hud];
 
layer.hud 
= hud;
 
// Add inside setPlayerPosition, in the case where a tile is collectableself.numCollected++;
[_hud numCollectedChanged:_numCollected];

        沒什麼稀奇的,第二個層繼承CCLayer,並且在右下角添加了一個label。我們將第二個層新增到場景(Scene)裡並且把hub層的引用傳遞給HelloWorld層。然後修改HelloWorld層呼叫通知計數改變的方法。
編譯執行,應該可以在右下角看到吃瓜計數器了。

音效和音樂
       眾所周知,沒有音效和音樂的遊戲,稱不上是個完整的遊戲。接下來,我們做一些簡單的修改,讓我們的遊戲帶有音效和背景音。

// HelloWorldScene.m
// At top of file#import "SimpleAudioEngine.h"// At top of init for HelloWorld layer[[SimpleAudioEngine sharedEngine] preloadEffect:@"pickup.caf"];
[[SimpleAudioEngine sharedEngine] preloadEffect:
@"hit.caf"];
[[SimpleAudioEngine sharedEngine] preloadEffect:
@"move.caf"];
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:
@"TileMap.caf"];
 
// In case for collidable tile[[SimpleAudioEngine sharedEngine] playEffect:@"hit.caf"];
 
// In case of collectable tile[[SimpleAudioEngine sharedEngine] playEffect:@"pickup.caf"];
 
// Right before setting player position[[SimpleAudioEngine sharedEngine] playEffect:@"move.caf"];
接下來做點什麼呢?
       通過這篇教程,你應該對coco2d有了一些基本的瞭解。
       這裡是按照整篇教程完成的工程檔案,猛擊這裡下載
       如果你感興趣,我的好朋友Geek和Dad編寫了一篇後續教程:Enemies and Combat: How To Make a Tile-Based Game with Cocos2D Part 3! 。這篇教程將告訴你,如何在遊戲裡新增敵人,武器,勝負場景等。