• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            聚星亭

            吾笨笨且懶散兮 急須改之而奮進
            posts - 74, comments - 166, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

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

            Posted on 2011-01-20 15:34 besterChen 閱讀(14253) 評論(3)  編輯 收藏 引用 所屬分類: obj-c/cocos2d 相關
            轉載聲明         本文轉載于 冥冥之中 的163博客,地址: http://blog.163.com/fengyi1103@126/blog/static/138356274201081741324532/
                     感謝 毛叔 網友 翻譯。

                    在這篇教程里,我們會講解如何使用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 Map Editor使用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 scene
                return 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 declaration
            CCSprite *_player;
             
            // After the class declaration
            @property (nonatomic, retain) CCSprite *player;

                    修改HelloWorldScene.m
            // Right after the implementation section
            @synthesize player = _player;
             
            // In dealloc
            self.player = nil;
             
            // Inside the init method, after setting self.background
            CCTMXObjectGroup *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 method
            self.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 Tile Layer取名Meta。我們會在這一層上放置一些假的Tile指示特殊的tile元件。點擊Map菜單的New Tileset,選擇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 declaration
            CCTMXLayer *_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 dealloc
            self.meta = nil;
             
            // In init, right after loading background
            self.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 declaration
            CCTMXLayer *_foreground;
             
            // After the class declaration
            @property (nonatomic, retain) CCTMXLayer *foreground;

            //in HelloWorldScene.m
            // Right after the implementation section
            @synthesize foreground = _foreground;
             
            // In dealloc
            self.foreground = nil;
             
            // In init, right after loading background
            self.foreground = [_tileMap layerNamed:@"Foreground"];
             
            // Add to setPlayerPosition, right after the if clause with the return in it
            NSString *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 declaration
            int _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 dealloc
            self.hud = nil;
             
            // Add to the +(id) scene method, right before the return
            HelloWorldHud *hud = [HelloWorldHud node];    
            [scene addChild: hud];
             
            layer.hud 
            = hud;
             
            // Add inside setPlayerPosition, in the case where a tile is collectable
            self.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! 。這篇教程將告訴你,如何在游戲里添加敵人,武器,勝負場景等。



            Feedback

            # HPy4Si , [url=http://oshykvrddhqi.com/]oshykvrddhqi[/url], [link=http://uqxsjxdqwiaw.com/]uqxsjxdqwiaw[/link], http://kbyunqckswea.com/  回復  更多評論   

            2011-05-27 01:38 by kkngqcfgz
            HPy4Si , [url=http://oshykvrddhqi.com/]oshykvrddhqi[/url], [link=http://uqxsjxdqwiaw.com/]uqxsjxdqwiaw[/link], http://kbyunqckswea.com/
            久久久久久国产精品美女| 久久美女网站免费| 日本福利片国产午夜久久| 亚洲国产精品无码久久久秋霞2 | 国产精品久久国产精品99盘| 伊人久久无码精品中文字幕| 亚洲?V乱码久久精品蜜桃| 久久精品成人免费观看97| 成人国内精品久久久久影院VR| 国产精品成人久久久久三级午夜电影 | 久久九色综合九色99伊人| 久久免费线看线看| 久久精品国产亚洲麻豆| 国产综合免费精品久久久| 久久久久久噜噜精品免费直播| 久久一本综合| 久久人爽人人爽人人片AV| 国产精品99久久免费观看| 中文字幕成人精品久久不卡| 国产精品成人久久久久三级午夜电影| 欧美国产精品久久高清| 久久人人添人人爽添人人片牛牛| 奇米综合四色77777久久| 久久91精品国产91久久麻豆| 91精品无码久久久久久五月天| 久久久WWW成人免费精品| 久久人人爽人人爽人人片AV不| 日韩精品无码久久久久久| 亚洲伊人久久大香线蕉苏妲己| 伊人久久国产免费观看视频| 久久精品99久久香蕉国产色戒 | 91秦先生久久久久久久| 亚洲欧洲久久久精品| 精品久久香蕉国产线看观看亚洲| 久久青青国产| 久久久av波多野一区二区| 久久综合亚洲色HEZYO国产| 久久精品国产亚洲AV无码偷窥| 久久久久黑人强伦姧人妻| 2020久久精品国产免费| 久久天天躁夜夜躁狠狠|