溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

cocos2dx[3.4](25)——瓦片地圖TiledMap

發(fā)布時間:2020-06-11 13:53:27 來源:網(wǎng)絡(luò) 閱讀:19380 作者:shahdza 欄目:游戲開發(fā)

【嘮叨】

    還記得我們小時候玩的小霸王里面的游戲嗎?大部分都是基于Tile地圖的游戲,如坦克大戰(zhàn)、冒險島、魂斗羅、吞食天地等。而在手游中,基于瓦片地圖的游戲也很常見。如:《保衛(wèi)蘿卜》。

    瓦片地圖有專門的地圖編輯器:Tiled Map Editor 。

    先給大家看個酷炫的圖吧。

cocos2dx[3.4](25)——瓦片地圖TiledMap

此圖來自: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    (瓦片地圖使用經(jīng)驗總結(jié))

    http://cn.cocos2d-x.org/tutorial/show?id=1516    (使用瓦片地圖詳解)




【代碼實踐】

    瓦片地圖的應(yīng)用十分廣泛,其知識點也非常豐富。

    所以我建議在代碼實踐中,邊寫邊學(xué),并掌握其基本的用法。

    然后再深入研究,效果更佳。

    推薦教程: http://cn.cocos2d-x.org/tutorial/lists?id=70




【瓦片地圖——概念篇】

    在看這部分的概念知識之前,首先保證你已經(jīng)學(xué)習(xí)過上面代碼實踐中推薦的那篇教程。

    因為接下來本文所要介紹的知識是:對瓦片地圖基本概念的總結(jié)以及深化。

    本文不再贅述地圖編輯器如何使用,或是怎么將瓦片地圖導(dǎo)入Cocos工程中使用,之類的問題。


1、地圖格式

    (1)支持 TMX文件格式 的瓦片地圖。(這也是推薦使用的文件格式)

    (2)建議瓦片的塊大小為32 * 32的倍數(shù)

cocos2dx[3.4](25)——瓦片地圖TiledMap


2、地圖方向

    地圖編輯器可以制作三類地圖:普通地圖(直90°) 、 斜45°地圖 、 斜45°交錯地圖。

    除此之外,而Cocos引擎還支持六邊形地圖。

    (1)普通地圖(直90°)

cocos2dx[3.4](25)——瓦片地圖TiledMap

    (2)斜45°地圖

cocos2dx[3.4](25)——瓦片地圖TiledMap

    (3)斜45°交錯地圖

cocos2dx[3.4](25)——瓦片地圖TiledMap

    (4)支持六邊形地圖

cocos2dx[3.4](25)——瓦片地圖TiledMap


3、瓦片地圖坐標(biāo)系

    瓦片地圖的坐標(biāo)系為:

        > 原點:在左上角。

        > 單位:瓦片數(shù)量。

        > X軸正方向:從左到右。

        > Y軸正方向:從上到下。

    例如:對于一個 10*10 的瓦片地圖文件的坐標(biāo)系統(tǒng)為:(0, 0)左上角、(9, 9)右下角。    

    PS:具體坐標(biāo)表示,已在上面的幾幅圖中標(biāo)出。

    另外,在地圖編輯器中,其實也已經(jīng)標(biāo)出了瓦片的坐標(biāo)。

    鼠標(biāo)移動到某瓦片格子上,左下角就會顯示格子的坐標(biāo),以及所使用的瓦片素材的GID(關(guān)于GID,后面會介紹)。

    如下如所示,被選中瓦片格子的坐標(biāo)為(2,3),所使用的瓦片素材GID為29。

cocos2dx[3.4](25)——瓦片地圖TiledMap


4、地圖層(TMXLayer)

    瓦片地圖支持地圖層(TMXLayer)、對象層(TMXObjectGroup)。

    (1)每一個地圖層可以被表示為TMXLayer類,并設(shè)置了名稱。(如下圖有三個地圖層:Meta、Foreground、BackGround)。

    (2)每一個單一的瓦片被表示為Sprite類,父節(jié)點為TMXLayer。

    (3)每一個地圖層只能由一套瓦片素材組成,否則會出問題。(如下面的右圖所示,有兩套瓦片素材(tile、meta),但是一個地圖層只能使用一套瓦片素材)。

cocos2dx[3.4](25)——瓦片地圖TiledMap    cocos2dx[3.4](25)——瓦片地圖TiledMap


5、對象層(TMXObjectGroup)

    (1)用來添加除背景以外的游戲元素信息,如道具、障礙物等對象。

    (2)一個對象層可以添加多個對象,每個對象的區(qū)域形狀的單位是:像素點。

    (3)對象層中的對象在TMX文件中鍵值對(key-value)形式存在,因此可以直接在TMX文件中對其進行修改。

cocos2dx[3.4](25)——瓦片地圖TiledMap


6、瓦片的全局標(biāo)識GID

    在Cocos游戲中,每一個瓦片素材都有一個全局唯一標(biāo)識GID,而瓦片的GID就是表示該瓦片所使用的是哪個GID的圖塊素材。(如上面第三小節(jié)提到的那幅圖)

    GID的計數(shù)從1開始,按順序編號,一直編號到圖塊的總數(shù)量。如下圖的tile圖塊資源中的 ID = 0 的圖塊編號 GID = 1,以此類推…… tile圖塊資源中最后一個 ID = 47 的圖塊對應(yīng)的GID = 48。

    然后對于第二套meta圖塊資源中的 ID = 0 的圖塊,對應(yīng)的 GID = 49。(是的,繼續(xù)編號下去……)

cocos2dx[3.4](25)——瓦片地圖TiledMap        cocos2dx[3.4](25)——瓦片地圖TiledMap        cocos2dx[3.4](25)——瓦片地圖TiledMap


7、瓦片地圖的屬性值(Properties)

    瓦片地圖由許多模塊構(gòu)成(瓦片地圖、地圖層、對象層、瓦片圖塊、瓦片、對象),其結(jié)構(gòu)圖見下面《代碼篇》那張圖。

    每一個模塊都可以設(shè)置自定義的屬性值(Custom Properties)。我想你在學(xué)習(xí)《代碼實踐》中那篇教程時,肯定也設(shè)置了自定義的屬性。(給瓦片圖塊設(shè)置“碰撞檢測”屬性、給對象層的某一對象設(shè)置“敵人類型”屬性等等……)

    這些自定義的屬性可以在地圖編輯器中進行設(shè)置,并且可以在代碼中獲取這些屬性以及對應(yīng)的屬性值。

    只要點擊“目標(biāo)”,就可以看到它的屬性,并且可以添加自定義屬性(Custom Properties)。

cocos2dx[3.4](25)——瓦片地圖TiledMap




【瓦片地圖——代碼篇】


    瓦片地圖的整體結(jié)構(gòu)圖如下:

cocos2dx[3.4](25)——瓦片地圖TiledMap


1、TMXTiledMap

    TMXTiledMap類為瓦片地圖類。其中包含了所有的地圖層、對象層、以及瓦片地圖的尺寸信息。

    其中:

        > MapSize :瓦片地圖的尺寸。(以瓦片數(shù)量為單位)

        > TileSize  :瓦片的尺寸。(以像素點為單位)

    核心函數(shù)如下:

//
	
class CC_DLL TMXTiledMap : public Node {
/**
 *	創(chuàng)建TMX瓦片地圖
 **/
	// 使用 .tmx 格式的文件創(chuàng)建瓦片地圖
	static TMXTiledMap* create(const std::string& tmxFile);


/**
 *	獲取瓦片地圖的屬性信息
 **/
	// 獲取 瓦片地圖的指定名稱的屬性值
	Value getProperty(const std::string& propertyName) const;
	// 獲取 瓦片地圖的所有屬性。(鍵-值對)
	void setProperties(const ValueMap& properties); // 可以修改屬性
	ValueMap& getProperties();

	// 獲取 瓦片地圖的尺寸。(單位:瓦片數(shù)量,而不是像素)
	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;
	// 獲取 瓦片地圖的所有對象層。返回對象數(shù)組 Vector<TMXObjectGroup*>
	void setObjectGroups(const Vector<TMXObjectGroup*>& groups);
	Vector<TMXObjectGroup*>& getObjectGroups() const;	
};
//


2、TMXLayer

    TMXLayer類為地圖層類。包含了該地圖層中,每個瓦片格子的信息。

    其中:

        > 每一個瓦片(Tile):都被表示為Sprite類。

    核心函數(shù)如下:

//
class CC_DLL TMXLayer : public SpriteBatchNode {
/**
 *	獲取地圖層的屬性信息
 **/	
	// 獲取 地圖層的名字
	void setLayerName(const std::string& layerName); // 可以重新設(shè)置地圖層名字
	std::string& getLayerName();

	// 獲取 地圖層的propertyName屬性值
	Value getProperty(const std::string& propertyName) const;
	// 獲取 地圖層的所有自定義屬性字典。(鍵-值對)
	void setProperties(const ValueMap& properties);
	ValueMap& getProperties();

	// 獲取地圖層尺寸。一般等于瓦片地圖的尺寸。(單位:瓦片數(shù)量)
	void setLayerSize(const Size& size);
	Size& getLayerSize() const;
	// 設(shè)置瓦片尺寸的大小。一般與瓦片地圖的瓦片尺寸是一樣的。(單位:像素)
	void setMapTileSize(const Size& size);
	Size& getMapTileSize() const;


/**
 *	對地圖層的瓦片進行操作
 **/
	// 獲取 指定tile坐標(biāo)的瓦片(Sprite)
	Sprite* getTileAt(const Vec2& tileCoordinate);

	// 可通過調(diào)用如下對其進行刪除:
	//		layer->removeTileAt(Vec2(x,y));
	//		或 layer->removeChild(sprite, cleanup);
	void removeTileAt(const Vec2& tileCoordinate);
	void removeChild(Node* child, bool cleanup) override;

	// 獲取 指定tile坐標(biāo)的瓦片對應(yīng)的OpenGL坐標(biāo)位置
	Vec2 getPositionAt(const Vec2& tileCoordinate);

	// 設(shè)置 指定tile坐標(biāo)的瓦片,將其圖片變?yōu)镚ID的圖塊。
	void setTileGID(uint32_t gid, const Vec2& tileCoordinate);

	// 獲取 指定tile坐標(biāo)的瓦片,所使用的圖塊的GID。
	uint32_t getTileGIDAt(const Vec2& tileCoordinate);
};
//


3、TMXObjectGroup

    TMXObjectGroup類是對象層類。包含了該對象層中,每個對象的信息。

    其中:

        > 每一個對象:所有屬性,被存儲為ValueMap,即 鍵-值對 的映射。

    核心函數(shù)如下:

//
class CC_DLL TMXObjectGroup : public Ref {
/**
 *	獲取對象層的屬性信息
 **/	
	// 獲取 對象層的名稱
	void setGroupName(const std::string& groupName); // 可以重新設(shè)置對象層名稱
	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、關(guān)于瓦片地圖的錨點位置

    瓦片地圖的錨點默認為( 0,0),每個瓦片的錨點默認也為(0,0)。

    PS:錨點是可以設(shè)置的,因為它不是繼承于Layer,而是直接繼承于Node。

    下面講解一下默認錨點的位置信息。

    (1)普通瓦片錨點信息

cocos2dx[3.4](25)——瓦片地圖TiledMap

    (2)斜45°瓦片錨點信息

cocos2dx[3.4](25)——瓦片地圖TiledMap

    (3)斜45°交錯瓦片錨點信息

cocos2dx[3.4](25)——瓦片地圖TiledMap


5、Tile坐標(biāo) 與 OpenGL坐標(biāo) 相互轉(zhuǎn)換

    這里介紹一下普通瓦片(直90°)的坐標(biāo)轉(zhuǎn)換。

    至于,斜45°的瓦片地圖,自己推公式把。。。

//
	// OpenGL坐標(biāo):原點為屏幕左下角(單位:像素)
	// tile坐標(biāo):原點為瓦片地圖的左上角(單位:瓦片)

	// OpenGL坐標(biāo) 轉(zhuǎn)成 格子坐標(biāo)
	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坐標(biāo) 轉(zhuǎn)成 瓦片格子中心的OpenGL坐標(biāo)
	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、遮罩關(guān)系

    瓦片地圖可以包含許多個地圖層,那么地圖層的遮罩關(guān)系是怎么確定的呢?

    (1)地圖層之間的遮罩關(guān)系

    如下圖所示,每個地圖層的 zOrder(渲染順序)會根據(jù)在地圖編輯器中設(shè)置的前后關(guān)系進行設(shè)置。由下往上設(shè)置 zOrder 值,最靠后的 zOrder = 0,隨后每個圖層zOrder+1。

    cocos2dx[3.4](25)——瓦片地圖TiledMap

    

    (2)瓦片之間的遮罩關(guān)系

        其 zOrder(渲染順序)的值如下所示。

        也就是說渲染順序為:從左往右,從上到下。

        即:下邊的瓦片可以遮住上邊的瓦片,右邊的瓦片可以遮住左邊的瓦片。

cocos2dx[3.4](25)——瓦片地圖TiledMap




【函數(shù)使用舉例】


1、瓦片地圖類(TMXTiledMap)

//
// TMXTiledMap::create()
	// 加載TMX瓦片地圖
	tileMap = TMXTiledMap::create("TileMap.tmx");
	this->addChild(tileMap, -1);

// tileMap->getMapSize()、getTileSize()
	// 獲取一個瓦片的尺寸
	tileSize = tileMap->getTileSize();
	// 獲取地圖的尺寸大?。ㄞD(zhuǎn)為像素點大?。?	// tileMap->getMapSize() 為獲取地圖寬高的瓦片數(shù)量
	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)位置的瓦片,圖片設(shè)置為 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");

	// 獲取坐標(biāo) x,y 屬性
	float x = heroInfo["x"].asFloat();
	float y = heroInfo["y"].asFloat();
	// 創(chuàng)建主角
	hero = Sprite::create("Player.png");
	hero->setPosition(x, y);
	tileMap->addChild(hero);

// objects->getObjects()
	// 添加敵人
	// getObjects:獲取對象數(shù)組 ValueVector
	for (auto&enemy : objects->getObjects()) {
		// 獲取對象的屬性
		ValueMap& dict = enemy.asValueMap();
		if (dict["Enemy"].asInt() == 1) { // 自定義屬性“Enemy”
			x = dict["x"].asFloat();      // x坐標(biāo)
			y = dict["y"].asFloat();      // y坐標(biāo)
			this->addEnemyAtPos(Vec2(x, y));
		}
	}
//



向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI