這一節,我們將使用cocos2d-x開發一個有關瓦片地圖的示例。
在這個示例當中,我們需要完成以下功能:
1)TMX地圖的加載與顯示。
2)在地圖中游走。
3)搞點兒小破壞,動態修改地圖。
內部規則
在開始之前,我們還需要了解一些TMX地圖的內部規則。
1)坐標
在TMX地圖中,坐標是從零開始計算的,左上角那一塊的坐標為(0,0),右下角那一塊的坐標為(寬度-1,高度-1)。
看到上面這張截圖時請不要驚慌,Qt版的確不能在每個格子上顯示坐標,這圖是我拼接出來的。
2)“瓦片”值
如果要操作地圖上的元素,我們還需要知道每個瓦片的內容,即瓦片值。
用文本編輯工具打開之前繪制的坦克大戰的地圖,其實就是一個xml文件。
圖中用紅線標記的這個屬性“firstgid”的值為"1",也就是說瓦片集中的瓦片是從一開始編號的。
如果地圖中某一塊的GID等於零,那就說明這個地方沒有使用瓦片填充,即透明的。
下面我們學習如何在cocos2d-x中使用TMX地圖,將涉及到CCTMXLayer和CCTMXTiledMap這兩個類。
顯示地圖
要在cocos2d-x中使用TMX地圖,你只需要調用tiledMapWithTMXFile來創建一個CCTMXTiledMap對象,並把它添加到場景中。
1 // Load level map 2 gameWorld = CCTMXTiledMap::tiledMapWithTMXFile("Level1.tmx"); 3 this->addChild(gameWorld, 0, 9);
是的,就是這么簡單。編譯執行,然后地圖就出現在你面前了。
四處游走
大家都知道,一般來說地圖的尺寸要比游戲窗口(畫面)大一些,就好像是透過窗子在觀察游戲里的世界。這個窗子就是我們常說的視口。
在3D游戲中,我們只需要將角色放置在正確的位置上,然后移動攝像機改變視口就可以了。
在2D游戲中,我們通常的做法是,當顯示區域不在地圖邊緣時,把角色放在畫面的中心,反向移動地圖,達到角色移動的效果。當顯示區域到達地圖邊緣時,因為畫面不能超出地圖范圍,所以這個時候我們就要真的移動角色了。
你還可以繪制一個稍微大一圈的地圖,並設置厚厚的阻擋,這樣角色就永遠不會走到地圖邊緣了。這算是個取巧的方法。
但無論采用上面哪一種方法,我們都需要一個移動地圖的方法。
通過查看CCTMXTiledMap類的聲明,我們知道CCTMXTiledMap其實就是一個CCNode,它也擁有CCNode的setPosition成員方法。調用setPosition就可以達到我們移動地圖的目的。
虛擬按鍵
為了方便控制,我們最好再設計一組虛擬按鍵來獲取玩家的輸入操作。當然,你在這里添加一個CCMenu也能實現類似的效果,但多少會有些限制,不如自己的虛擬按鍵方便。
在第4章中我們介紹過觸摸事件的目標代理,添加虛擬按鍵使用的就是這個方法。
我們新建一個控制層,這個層的主要作用就是處理觸摸事件。為了玩家能直觀的看見虛擬按鍵,這個層還負責虛擬按鍵的顯示,以及切換它們的顯示狀態。畢竟不是系統提供的菜單項,這些都是需要自己處理的。
雖然有點兒繁瑣,但都是以前的知識點,所以就不貼代碼了,如有需要請參考附件。
動態修改地圖
對TMX地圖進行動態修改的操作是針對層的。修改的過程就是先要找到對應的層,然后對指定坐標上的GID進行修改。
1 void GameLayer::ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent) 2 { 3 CCTouch *pTouch = reinterpret_cast<CCTouch *>(pTouches->anyObject()); 4 // 注意,升級到cocos2d-1.0.1-x-0.13.0-beta這個版本后,下面這個locationInView()是沒有參數的。 5 CCPoint touchPoint = CCDirector::sharedDirector()->convertToGL(pTouch->locationInView()); 6 // pt是觸摸點轉換到地圖上的坐標 7 CCPoint pt = this->tileCoordinateFromPos(ccp(touchPoint.x - mapX, touchPoint.y - mapY)); 8 if (pt.x != -1) 9 { 10 // "tile"是我們要操作的層的名字 11 CCTMXLayer *ly = gameWorld->layerNamed("tile"); 12 unsigned int gid = ly->tileGIDAt(pt); 13 if (gid != 1) 14 this->ShowExplodeAt(touchPoint); 15 if (gid == 2) 16 ly->setTileGID(5, pt); 17 if (gid == 4) 18 ly->setTileGID(6, pt); 19 if (gid == 5) 20 ly->setTileGID(4, pt); 21 if (gid == 6) 22 ly->setTileGID(1, pt); 23 } 24 }
上面這段代碼實現了對觸摸點顯示爆炸動畫,並根據地形不同修改爆炸后的地面顯示的功能。
小結
在這一章中,我們學會了如何加載並顯示一張TMX地圖,如果獲取某一坐標的地形信息以及如何動態修改這一屬性。雖然這些只是十分基礎的地圖操作,但我們已經向着開發更復雜更有意思的游戲又邁進了一步。
示例代碼下載:http://dl.dbank.com/c094e7ash7
代碼更新
我以前未能理解到LAYER_NODE_FUNC和SCENE_NODE_FUNC這兩個宏定義的精妙之處,所以按照知易的源代碼那樣為MainScene類加了一個ShowScene靜態成員函數,導致游戲中節點的關系變成了:CCScene根場景下多了一個用層實現的MainScene,然后才是GameLayer和ControlLayer。太羅嗦了,所以這里更新一下。
新的下載地址:http://files.cnblogs.com/cocos2d-x/ZYG005.rar
題外話
大家是不是覺得CCLayer和CCScene里的"bool init(void);"應該改成虛函數"virtual bool init(void);"會更好一些?