Cocos2d-x 3.x基础学习:瓦片地图TiledMap

2015年03月23日 11:49 1 点赞 0 评论 更新于 2025-11-21 18:15

你是否还记得小时候玩过的小霸王游戏,像坦克大战、冒险岛、魂斗罗、吞食天地等?这些游戏大部分都是基于Tile地图开发的。在如今的手游领域,基于瓦片地图的游戏也十分常见,例如《保卫萝卜》。

瓦片地图有专门的地图编辑器——Tiled Map Editor。下面先给大家展示一张酷炫的图,此图来自:Cocos2d-x初入学堂(13)-->Tiled Map Editor地图编辑器

代码实践

瓦片地图的应用极为广泛,涉及的知识点也非常丰富。因此,建议在代码实践过程中,边编写代码边学习,先掌握其基本用法,再进行深入研究,这样能取得更佳的学习效果。这里推荐一篇教程:如何使用Cocos2d-x 3.0制作基于tilemap的游戏

瓦片地图——概念篇

在学习这部分概念知识之前,请确保你已经学习了上面代码实践中推荐的那篇教程。接下来,本文将对瓦片地图的基本概念进行总结和深化。对于地图编辑器的使用方法,以及如何将瓦片地图导入Cocos工程中使用等问题,本文不再赘述。

1. 地图格式

  • 支持的文件格式:支持TMX文件格式的瓦片地图,这也是推荐使用的文件格式。
  • 瓦片块大小建议:建议瓦片的块大小为32 * 32的倍数。

2. 地图方向

地图编辑器可以制作三类常见地图:普通地图(直90°)、斜45°地图、斜45°交错地图。此外,Cocos引擎还支持六边形地图。

  • 普通地图(直90°):地图呈标准的直角布局。
  • 斜45°地图:地图以45°倾斜角度布局。
  • 斜45°交错地图:在斜45°的基础上采用交错排列方式。
  • 六边形地图:由六边形瓦片组成的地图。

3. 瓦片地图坐标系

瓦片地图的坐标系具有以下特点:

  • 原点:位于左上角。
  • 单位:以瓦片数量为单位。
  • X轴正方向:从左到右。
  • Y轴正方向:从上到下。

例如,对于一个10 * 10的瓦片地图文件,其坐标系统为:左上角坐标是(0, 0),右下角坐标是(9, 9)。具体坐标表示已在相关图中标出,同时在地图编辑器中,当鼠标移动到某瓦片格子上时,左下角会显示该格子的坐标,以及所使用的瓦片素材的GID(关于GID,后面会详细介绍)。如下图所示,被选中瓦片格子的坐标为(2, 3),所使用的瓦片素材GID为29。

4. 地图层(TMXLayer)

瓦片地图支持地图层(TMXLayer)和对象层(TMXObjectGroup)。

  • 地图层的表示:每一个地图层可以用TMXLayer类表示,并设置相应的名称。例如,可能存在三个地图层:Meta、Foreground、BackGround。
  • 瓦片的表示:每一个单一的瓦片被表示为Sprite类,其父节点为TMXLayer。
  • 瓦片素材的使用规则:每一个地图层只能由一套瓦片素材组成,否则可能会出现问题。例如,若有两套瓦片素材(tile、meta),一个地图层只能选用其中一套。

5. 对象层(TMXObjectGroup)

  • 用途:用于添加除背景以外的游戏元素信息,如道具、障碍物等对象。
  • 对象添加规则:一个对象层可以添加多个对象,每个对象的区域形状的单位是像素点。
  • 对象的存储形式:对象层中的对象在TMX文件中以键值对(key - value)形式存在,因此可以直接在TMX文件中对其进行修改。

6. 瓦片的全局标识GID

在Cocos游戏中,每一个瓦片素材都有一个全局唯一标识GID,瓦片的GID表示该瓦片所使用的图块素材编号。GID的计数从1开始,按顺序编号,一直到图块的总数量。例如,tile图块资源中ID = 0的图块编号GID = 1,以此类推,该资源中最后一个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
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)。需要注意的是,锚点是可以设置的,因为它直接继承于Node,而非Layer。下面分别介绍不同类型瓦片的默认锚点位置信息:

  • 普通瓦片锚点信息:普通瓦片的锚点位置遵循默认设置。
  • 斜45°瓦片锚点信息:斜45°瓦片的锚点位置有其特定的布局方式。
  • 斜45°交错瓦片锚点信息:斜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. 遮罩关系

瓦片地图可以包含多个地图层,地图层和瓦片之间的遮罩关系确定方式如下:

  • 地图层之间的遮罩关系:每个地图层的zOrder(渲染顺序)会根据在地图编辑器中设置的前后关系进行设置。由下往上设置zOrder值,最靠后的zOrder = 0,随后每个图层zOrder + 1。
  • 瓦片之间的遮罩关系:其zOrder(渲染顺序)的规则是从左往右,从上到下。即下边的瓦片可以遮住上边的瓦片,右边的瓦片可以遮住左边的瓦片。

函数使用举例

1. 瓦片地图类(TMXTiledMap)

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

// 获取一个瓦片的尺寸
Size tileSize = tileMap->getTileSize();

// 获取地图的尺寸大小(转为像素点大小)
// tileMap->getMapSize() 为获取地图宽高的瓦片数量
Size tileMapSize = Size(tileMap->getMapSize().width * tileSize.width,
tileMap->getMapSize().height * tileSize.height);

// 获取图块素材的 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());
}

// 获取背景层、前景层、元层
TMXLayer* backGround = tileMap->getLayer("Background");
TMXLayer* foreGround = tileMap->getLayer("Foreground");
TMXLayer* meta = tileMap->getLayer("Meta");

// 获取对象层
TMXObjectGroup* objects = tileMap->getObjectGroup("Objects");

2. 地图层类(TMXLayer)

// 获取瓦片(Sprite),进行放缩
Sprite* sp = backGround->getTileAt(Vec2(2, 19));
sp->setScale(2.0f);

// 将(5,17)位置的瓦片,图片设置为 GID=46 的图块素材
unsigned int gid = 46;
backGround->setTileGID(gid, Vec2(5, 17));

// 获取(2,19)位置的瓦片,所使用的图块素材的GID
gid = backGround->getTileGIDAt(Vec2(2, 19));
CCLOG("gid = %d", gid);

3. 对象层类(TMXObjectGroup)

// 获取HeroInfo对象
ValueMap heroInfo = objects->getObject("HeroInfo");

// 获取坐标 x,y 属性
float x = heroInfo["x"].asFloat();
float y = heroInfo["y"].asFloat();

// 创建主角
Sprite* hero = Sprite::create("Player.png");
hero->setPosition(x, y);
tileMap->addChild(hero);

// 添加敌人
// 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));
}
}

通过以上内容的学习,你可以深入了解Cocos2d - x 3.x中瓦片地图TiledMap的相关知识,包括概念、代码实现以及函数使用方法,从而在游戏开发中灵活运用瓦片地图。

作者信息

boke

boke

共发布了 3994 篇文章