` 轉
cocos2d-x 學習筆記——瓦片地圖TiledMap
2016年08月07日 16:14:08 閱讀數:4804 标簽: cocos2d-x TiledMap 瓦片地圖 更多 個人分類: cocos2d-x
本文出自 “夏天的風” 部落格,轉載時請務必保留此出處:http://shahdza.blog.51cto.com/2410787/1613527
【唠叨】
還記得我們小時候玩的小霸王裡面的遊戲嗎?大部分都是基于Tile地圖的遊戲,如坦克大戰、冒險島、魂鬥羅、吞食天地等。而在手遊中,基于瓦片地圖的遊戲也很常見。如:《保衛蘿蔔》。
瓦片地圖有專門的地圖編輯器:Tiled Map Editor 。
先給大家看個酷炫的圖吧。
此圖來自:http://blog.csdn.net/aa4790139/article/details/8135831
【參考】
http://cn.cocos2d-x.org/tutorial/lists?id=70 (制作基于TileMap的遊戲)
http://cn.cocos2d-x.org/article/index?type=cocos2d-x&url=/doc/cocos-docs-master/manual/framework/native/v3/tiled-map/zh.md (瓦片地圖使用經驗總結)
http://cn.cocos2d-x.org/tutorial/show?id=1516 (使用瓦片地圖詳解)
【代碼實踐】
瓦片地圖的應用十分廣泛,其知識點也非常豐富。
是以我建議在代碼實踐中,邊寫邊學,并掌握其基本的用法。
然後再深入研究,效果更佳。
推薦教程: http://cn.cocos2d-x.org/tutorial/lists?id=70
【瓦片地圖——概念篇】
在看這部分的概念知識之前,首先保證你已經學習過上面代碼實踐中推薦的那篇教程。
因為接下來本文所要介紹的知識是:對瓦片地圖基本概念的總結以及深化。
本文不再贅述地圖編輯器如何使用,或是怎麼将瓦片地圖導入Cocos工程中使用,之類的問題。
1、地圖格式
(1)支援 TMX檔案格式 的瓦片地圖。(這也是推薦使用的檔案格式)
(2)建議瓦片的塊大小為32 * 32的倍數。
2、地圖方向
地圖編輯器可以制作三類地圖:普通地圖(直90°) 、 斜45°地圖 、 斜45°交錯地圖。
除此之外,而Cocos引擎還支援六邊形地圖。
(1)普通地圖(直90°)
(2)斜45°地圖
(3)斜45°交錯地圖
(4)支援六邊形地圖
3、瓦片地圖坐标系
瓦片地圖的坐标系為:
> 原點:在左上角。
> 機關:瓦片數量。
> X軸正方向:從左到右。
> Y軸正方向:從上到下。
例如:對于一個 10*10 的瓦片地圖檔案的坐标系統為:(0, 0)左上角、(9, 9)右下角。
PS:具體坐标表示,已在上面的幾幅圖中标出。
另外,在地圖編輯器中,其實也已經标出了瓦片的坐标。
滑鼠移動到某瓦片格子上,左下角就會顯示格子的坐标,以及所使用的瓦片素材的GID(關于GID,後面會介紹)。
如下如所示,被選中瓦片格子的坐标為(2,3),所使用的瓦片素材GID為29。
4、地圖層(TMXLayer)
瓦片地圖支援地圖層(TMXLayer)、對象層(TMXObjectGroup)。
(1)每一個地圖層可以被表示為TMXLayer類,并設定了名稱。(如下圖有三個地圖層:Meta、Foreground、BackGround)。
(2)每一個單一的瓦片被表示為Sprite類,父節點為TMXLayer。
(3)每一個地圖層隻能由一套瓦片素材組成,否則會出問題。(如下面的右圖所示,有兩套瓦片素材(tile、meta),但是一個地圖層隻能使用一套瓦片素材)。
5、對象層(TMXObjectGroup)
(1)用來添加除背景以外的遊戲元素資訊,如道具、障礙物等對象。
(2)一個對象層可以添加多個對象,每個對象的區域形狀的機關是:像素點。
(3)對象層中的對象在TMX檔案中以鍵值對(key-value)形式存在,是以可以直接在TMX檔案中對其進行修改。
6、瓦片的全局辨別GID
在Cocos遊戲中,每一個瓦片素材都有一個全局唯一辨別GID,而瓦片的GID就是表示該瓦片所使用的是哪個GID的圖塊素材。(如上面第三小節提到的那幅圖)
GID的計數從1開始,按順序編号,一直編号到圖塊的總數量。如下圖的tile圖塊資源中的 ID = 0 的圖塊編号 GID = 1,以此類推…… tile圖塊資源中最後一個 ID = 47 的圖塊對應的GID = 48。
然後對于第二套meta圖塊資源中的 ID = 0 的圖塊,對應的 GID = 49。(是的,繼續編号下去……)
7、瓦片地圖的屬性值(Properties)
瓦片地圖由許多子產品構成(瓦片地圖、地圖層、對象層、瓦片圖塊、瓦片、對象),其結構圖見下面《代碼篇》那張圖。
每一個子產品都可以設定自定義的屬性值(Custom Properties)。我想你在學習《代碼實踐》中那篇教程時,肯定也設定了自定義的屬性。(給瓦片圖塊設定“碰撞檢測”屬性、給對象層的某一對象設定“敵人類型”屬性等等……)
這些自定義的屬性可以在地圖編輯器中進行設定,并且可以在代碼中擷取這些屬性以及對應的屬性值。
隻要點選“目标”,就可以看到它的屬性,并且可以添加自定義屬性(Custom Properties)。
【瓦片地圖——代碼篇】
瓦片地圖的整體結構圖如下:
1、TMXTiledMap
TMXTiledMap類為瓦片地圖類。其中包含了所有的地圖層、對象層、以及瓦片地圖的尺寸資訊。
其中:
> MapSize :瓦片地圖的尺寸。(以瓦片數量為機關)
> TileSize :瓦片的尺寸。(以像素點為機關)
核心函數如下:
- //
- class CC_DLL TMXTiledMap : public Node {
- /**
- * 建立TMX瓦片地圖
- **/
- // 使用 .tmx 格式的檔案建立瓦片地圖
- static TMXTiledMap* create(const std::string& tmxFile);
- /**
- * 擷取瓦片地圖的屬性資訊
- **/
- // 擷取 瓦片地圖的指定名稱的屬性值
- Value getProperty(const std::string& propertyName) const;
- // 擷取 瓦片地圖的所有屬性。(鍵-值對)
- void setProperties(const ValueMap& properties); // 可以修改屬性
- ValueMap& getProperties();
- // 擷取 瓦片地圖的尺寸。(機關:瓦片數量,而不是像素)
- void setMapSize(const Size& mapSize);
- Size& getMapSize() const;
- // 擷取 單個瓦片的尺寸。(機關:像素)
- void setTileSize(const Size& tileSize);
- Size& getTileSize() const;
- // 通過GID擷取圖塊的屬性,傳回Value字典。
- // 其實傳回的是:ValueMap,即(鍵-值對)。
- Value getPropertiesForGID(int GID) const;
- /**
- * 擷取地圖層、對象層
- **/
- // 擷取 指定名稱的地圖層 TMXLayer
- TMXLayer* getLayer(const std::string& layerName) const;
- // 擷取 指定名稱的對象層 TMXObjectGroup
- TMXObjectGroup* getObjectGroup(const std::string& groupName) const;
- // 擷取 瓦片地圖的所有對象層。傳回對象數組 Vector<TMXObjectGroup*>
- void setObjectGroups(const Vector<TMXObjectGroup*>& groups);
- Vector<TMXObjectGroup*>& getObjectGroups() const;
- };
- //
2、TMXLayer
TMXLayer類為地圖層類。包含了該地圖層中,每個瓦片格子的資訊。
其中:
> 每一個瓦片(Tile):都被表示為Sprite類。
核心函數如下:
- //
- class CC_DLL TMXLayer : public SpriteBatchNode {
- /**
- * 擷取地圖層的屬性資訊
- **/
- // 擷取 地圖層的名字
- void setLayerName(const std::string& layerName); // 可以重新設定地圖層名字
- std:: string& getLayerName();
- // 擷取 地圖層的propertyName屬性值
- Value getProperty(const std::string& propertyName) const;
- // 擷取 地圖層的所有自定義屬性字典。(鍵-值對)
- void setProperties(const ValueMap& properties);
- ValueMap& getProperties();
- // 擷取地圖層尺寸。一般等于瓦片地圖的尺寸。(機關:瓦片數量)
- void setLayerSize(const Size& size);
- Size& getLayerSize() const;
- // 設定瓦片尺寸的大小。一般與瓦片地圖的瓦片尺寸是一樣的。(機關:像素)
- void setMapTileSize(const Size& size);
- Size& getMapTileSize() const;
- /**
- * 對地圖層的瓦片進行操作
- **/
- // 擷取 指定tile坐标的瓦片(Sprite)
- Sprite* getTileAt(const Vec2& tileCoordinate);
- // 可通過調用如下對其進行删除:
- // layer->removeTileAt(Vec2(x,y));
- // 或 layer->removeChild(sprite, cleanup);
- void removeTileAt(const Vec2& tileCoordinate);
- void removeChild(Node* child, bool cleanup) override;
- // 擷取 指定tile坐标的瓦片對應的OpenGL坐标位置
- Vec2 getPositionAt(const Vec2& tileCoordinate);
- // 設定 指定tile坐标的瓦片,将其圖檔變為GID的圖塊。
- void setTileGID(uint32_t gid, const Vec2& tileCoordinate);
- // 擷取 指定tile坐标的瓦片,所使用的圖塊的GID。
- uint32_t getTileGIDAt( const Vec2& tileCoordinate);
- };
- //
3、TMXObjectGroup
TMXObjectGroup類是對象層類。包含了該對象層中,每個對象的資訊。
其中:
> 每一個對象:其所有屬性,被存儲為ValueMap,即鍵-值對 的映射。
核心函數如下:
- //
- class CC_DLL TMXObjectGroup : public Ref {
- /**
- * 擷取對象層的屬性資訊
- **/
- // 擷取 對象層的名稱
- void setGroupName(const std::string& groupName); // 可以重新設定對象層名稱
- std:: string& getGroupName();
- // 擷取 對象層的propertyName屬性值
- Value getProperty(const std::string& propertyName) const;
- // 擷取 對象層所有屬性。(鍵-值對)
- void setProperties(const ValueMap& properties);
- ValueMap& getProperties();
- /**
- * 擷取對象層的 對象
- **/
- // 擷取對象層指定的objectName對象,其所有屬性被存儲為ValueMap(鍵-值對)
- ValueMap getObject(const std::string& objectName) const;
- // 擷取對象層的所有對象
- void setObjects(const ValueVector& objects);
- ValueVector& getObjects();
- };
- //
4、關于瓦片地圖的錨點位置
瓦片地圖的錨點預設為( 0,0),每個瓦片的錨點預設也為(0,0)。
PS:錨點是可以設定的,因為它不是繼承于Layer,而是直接繼承于Node。
下面講解一下預設錨點的位置資訊。
(1)普通瓦片錨點資訊
(2)斜45°瓦片錨點資訊
(3)斜45°交錯瓦片錨點資訊
5、Tile坐标 與 OpenGL坐标 互相轉換
這裡介紹一下普通瓦片(直90°)的坐标轉換。
至于,斜45°的瓦片地圖,自己推公式把。。。
- //
- // OpenGL坐标:原點為螢幕左下角(機關:像素)
- // tile坐标:原點為瓦片地圖的左上角(機關:瓦片)
- // OpenGL坐标 轉成 格子坐标
- Vec2 tileCoordForPosition(const Vec2& position) {
- Size mapSize = tiledMap->getMapSize();
- Size tileSize = tiledMap->getTileSize();
- int x = position.x / tileSize.width;
- int y = (mapSize.height * tileSize.height - position.y) / tileSize.height;
- return Vec2(x, y);
- }
- // tile坐标 轉成 瓦片格子中心的OpenGL坐标
- Vec2 positionForTileCoord(const Vec2& tileCoord) {
- Size mapSize = tiledMap->getMapSize();
- Size tileSize = tiledMap->getTileSize();
- int x = tileCoord.x * tileSize.width + tileSize.width/ ;
- int y = (mapSize.height - tileCoord.y) * tileSize.height - tileSize.height/ ;
- return Vec2(x, y);
- }
- //
6、遮罩關系
瓦片地圖可以包含許多個地圖層,那麼地圖層的遮罩關系是怎麼确定的呢?
(1)地圖層之間的遮罩關系
如下圖所示,每個地圖層的 zOrder(渲染順序)會根據在地圖編輯器中設定的前後關系進行設定。由下往上設定 zOrder 值,最靠後的 zOrder = 0,随後每個圖層zOrder+1。
(2)瓦片之間的遮罩關系
其 zOrder(渲染順序)的值如下所示。
也就是說渲染順序為:從左往右,從上到下。
即:下邊的瓦片可以遮住上邊的瓦片,右邊的瓦片可以遮住左邊的瓦片。
【函數使用舉例】
1、瓦片地圖類(TMXTiledMap)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | |
2、地圖層類(TMXLayer)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
3、對象層類(TMXObjectGroup)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
- //
- // objects->getObject()
- // 擷取HeroInfo對象
- ValueMap heroInfo = objects->getObject( “HeroInfo”);
- // 擷取坐标 x,y 屬性
- float x = heroInfo[ “x”].asFloat();
- float y = heroInfo[ “y”].asFloat();
- // 建立主角
- hero = Sprite::create( “Player.png”);
- hero->setPosition(x, y);
- tileMap->addChild(hero);
- // objects->getObjects()
- // 添加敵人
- // getObjects:擷取對象數組 ValueVector
- for ( auto&enemy : objects->getObjects()) {
- // 擷取對象的屬性
- ValueMap& dict = enemy.asValueMap();
- if (dict[ “Enemy”].asInt() == ) { // 自定義屬性“Enemy”
- x = dict[ “x”].asFloat(); // x坐标
- y = dict[ “y”].asFloat(); // y坐标
- this->addEnemyAtPos(Vec2(x, y));
- }
- }
- //