您好,登錄后才能下訂單哦!
【嘮叨】
還記得我們小時候玩的小霸王里面的游戲嗎?大部分都是基于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/2; int y = (mapSize.height - tileCoord.y) * tileSize.height - tileSize.height/2; return Vec2(x, y); } //
6、遮罩關系
瓦片地圖可以包含許多個地圖層,那么地圖層的遮罩關系是怎么確定的呢?
(1)地圖層之間的遮罩關系
如下圖所示,每個地圖層的 zOrder(渲染順序)會根據在地圖編輯器中設置的前后關系進行設置。由下往上設置 zOrder 值,最靠后的 zOrder = 0,隨后每個圖層zOrder+1。
(2)瓦片之間的遮罩關系
其 zOrder(渲染順序)的值如下所示。
也就是說渲染順序為:從左往右,從上到下。
即:下邊的瓦片可以遮住上邊的瓦片,右邊的瓦片可以遮住左邊的瓦片。
【函數使用舉例】
1、瓦片地圖類(TMXTiledMap)
// // TMXTiledMap::create() // 加載TMX瓦片地圖 tileMap = TMXTiledMap::create("TileMap.tmx"); this->addChild(tileMap, -1); // tileMap->getMapSize()、getTileSize() // 獲取一個瓦片的尺寸 tileSize = tileMap->getTileSize(); // 獲取地圖的尺寸大小(轉為像素點大小) // tileMap->getMapSize() 為獲取地圖寬高的瓦片數量 tileMapSize = Size(tileMap->getMapSize().width * tileSize.width, tileMap->getMapSize().height * tileSize.height); // tileMap->getPropertiesForGID() // 獲取圖塊素材的 GID=49 的所有自定義屬性 auto properties = tileMap->getPropertiesForGID(49).asValueMap(); for(auto& value : properties) { CCLOG("Properties:%s, %s", value.first.c_str(), value.second.asString().c_str()); } // tileMap->getLayer() // 獲取背景層、前景層、元層 backGround = tileMap->getLayer("Background"); foreGround = tileMap->getLayer("Foreground"); meta = tileMap->getLayer("Meta"); // tileMap->getObjectGroup() // 獲取對象層 objects = tileMap->getObjectGroup("Objects"); //
2、地圖層類(TMXLayer)
// // backGround->getTileAt() // 獲取瓦片(Sprite),進行放縮 Sprite* sp = backGround->getTileAt(Vec2(2, 19)); sp->setScale(2.0f); // backGround->setTileGID // 將(5,17)位置的瓦片,圖片設置為 GID=46 的圖塊素材 unsigned int gid = 46; backGround->setTileGID(gid, Vec2(5, 17)); // backGround->getTileGIDAt // 獲取(2,19)位置的瓦片,所使用的圖塊素材的GID gid = backGround->getTileGIDAt(Vec2(2, 19)); CCLOG("gid = %d", gid); //
3、對象層類(TMXObjectGroup)
// // 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() == 1) { // 自定義屬性“Enemy” x = dict["x"].asFloat(); // x坐標 y = dict["y"].asFloat(); // y坐標 this->addEnemyAtPos(Vec2(x, y)); } } //
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。