针对如何在cocos2d中使用tilemap来加载地图的步骤网上基本都有教程,比如怎么使用Tiled创建tilemap,以及如何在cocos2d中加载,网上都能搜索到,这里只简单说一下,不列出具体步骤。
这篇文章主要是对tilemap文件的格式以及cocos2d如何加载tilemap做了一个简单的分析,以备日后查看。
在cocos2d中创建并加载tilemap
使用Tiled创建好tilemap后,接下来需要用代码在cocos2d中加载它,代码如下:
TMXTiledMap* tilemap = TMXTiledMap::create("Map/tilemap.tmx");
this->addChild(tilemap);
这样便很简单地创建了tilemap。
不过这里有几点要注意一下,一是使用Tiled创建tilemap的时候,添加了tileset之类资源的话,一定要把资源放到与tmx文件同一个目录下,避免无法加载的情况出现;二是新建tilemap时,格式应选择Base64(zlib compressed),不然cocos2d可能会出现加载失败的情况。
tmx文件的结构
cocos2d可以通过tmx文件加载tilemap,而tmx文件其实就是xml格式的文件,其具体格式在这里可以看到。
例如如下tmx文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="orthogonal" renderorder="right-down" width="60" height="40" tilewidth="32" tileheight="32" nextobjectid="13">
<tileset firstgid="1" name="tiles-hd" tilewidth="32" tileheight="32" tilecount="256" columns="16">
<image source="tiles-hd.png" width="512" height="512"/>
</tileset>
<layer name="Tile Layer 1" width="60" height="40">
<data encoding="base64" compression="zlib">
eJzt0YEJAEAMg8DS/YfuFv+g3gSR7IRsfw94zNZrY/u33pDY/q2XzdZrY/u3XrZ6Q2L7t142W6+N7d96Q2L719Zr079stn/rZauXzdZ7shwAPw==
</data>
</layer>
<objectgroup name="Objects">
<object id="1" type="1" x="53.6875" y="1200.9">
<polyline points="0,0 1426.96,-8.47697 1850.81,8.47697"/>
</object>
<object id="6" type="2" x="771.404" y="180.842">
<polygon points="0,0 127.155,418.197 508.618,573.608 599.039,319.299 401.243,73.4671"/>
</object>
<object id="7" type="4" x="262.786" y="576.434" width="192.145" height="200.622"/>
<object id="9" type="3" x="1491.95" y="243.006" width="121.503" height="161.062">
<ellipse/>
</object>
</objectgroup>
</map>
map 标签:储存了此tilemap的主要信息,例如朝向,宽高等等。
tileset 标签:是此tilemap中导入的tileset资源的信息,例如图片源
layer 标签:层相关的信息,如果地图中有多个层,则也会有多个layer标签
data 标签:出现在layer里,其实定义的就是地图信息,如果加密方式选择csv,就可以看到其中的内容例如:
<data encoding="csv">
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0
</data>
这是一个10行10列的地图,0代表没有图块,如果有数字,例如1,就代表tileset中第一个图块,2就代表第二个,以此类推。
objectgroup 这个是object层的信息,其中会包括多个 object 标签,记录了每个object的信息,obejct有多种类型:
- 四边形:四边形没有特殊标签,直接用object标签即可表示:
<object id="7" type="4" x="262.786" y="576.434" width="192.145" height="200.622"/>
其中x、y为四边形左下角点的坐标,width、height即为宽、长。
- 椭圆 使用 ellipse 标签。
<object id="9" type="3" x="1491.95" y="243.006" width="121.503" height="161.062">
<ellipse/>
</object>
- 多边形 使用 polygon 标签,object中的x、y为多边形的起始点,polygon中的points记录了多边形各个顶点的坐标,其中第一个始终为(0,0),其余点都是相对第一个点的位移。
<object id="6" type="2" x="771.404" y="180.842">
<polygon points="0,0 127.155,418.197 508.618,573.608 599.039,319.299 401.243,73.4671"/>
</object>
- 折线 使用 polyline 标签,表示方式类似于polygon,其实折线可以看做不封口的多边形。
<object id="1" type="1" x="53.6875" y="1200.9">
<polyline points="0,0 1426.96,-8.47697 1850.81,8.47697"/>
</object>
在cocos2d中解析tilemap的数据
虽然在cocos2d中加载tilemap非常简单,但是实际使用中经常不仅仅要加载tilemap,实际上还需要通过tilemap传入地图的一些信息,例如使用物理引擎时,需要获知地图中有哪些碰撞物;怪物会在哪里生成;在哪些地方会触发事件等等。信息足够的话,其实可以将Tiled当作关卡编辑器使用,减轻编码负担。
tilemap中常用的层有地图层和object层,下面简单介绍一下两者信息的获取方法:
- 地图层
使用TMXTiledMap类的getLayer方法可以获取到地图层,如果获取成功,会返回一个TMXLayer对象,通过TMXLayer对象可以获取地图层的信息,具体提供的方法可以访问官网查看api:TMXLayer。
TMXLayer* layer = tilemap->getLayer("Layer");
log("%s", layer->getDescription().c_str());
Sprite* sp = layer->getTileAt(Vec2(0, 15));
sp->setPosition(visibleSize/2);
注意一下,以上代码中getTileAt获取到的是已经作为layer的字节点的sprite对象,改变其位置后,原来地图上对应的图块就改变了位置。
- object层
通过TMXTiledMap的getObjectGroup方法可以获取到object层对象,该方法返回的是一个TMXObjectGroup对象,其api查看TMXObjectGroup,示例代码如下:
tilemap = TMXTiledMap::create("Map/tilemap.tmx");
this->addChild(tilemap);
TMXObjectGroup *objectGroup = tilemap->getObjectGroup("Objects");
for (auto& object : objectGroup->getObjects()) {
ValueMap obj = object.asValueMap();
switch (obj["type"].asInt()) {
case 1: { // polyline
log("Polyline--------");
log("x:%.2f, y:%.2f", obj["x"].asFloat(), obj["y"].asFloat());
ValueVector pointsVector = obj["polylinePoints"].asValueVector();
for (auto& pointMap : pointsVector) {
auto point = pointMap.asValueMap();
log("polyline point: %.2f, %.2f", point["x"].asFloat(), point["y"].asFloat());
}
break;
}
case 2: { // polygon
log("Polygon---------");
log("x:%.2f, y:%.2f", obj["x"].asFloat(), obj["y"].asFloat());
ValueVector pointsVector = obj["points"].asValueVector();
for (auto& pointMap : pointsVector) {
auto point = pointMap.asValueMap();
log("polygon point: %.2f, %.2f", point["x"].asFloat(), point["y"].asFloat());
}
break;
}
case 3: { // ellipse
log("Ellipse---------");
log("x:%.2f, y:%.2f", obj["x"].asFloat(), obj["y"].asFloat());
log("width:%.2f, height:%.2f", obj["width"].asFloat(), obj["height"].asFloat());
break;
}
case 4: { // rectangle
log("Rectangle-------");
log("x:%.2f, y:%.2f", obj["x"].asFloat(), obj["y"].asFloat());
log("width:%.2f, height:%.2f", obj["width"].asFloat(), obj["height"].asFloat());
break;
}
default: {
CCASSERT(false, "object must has a type!!!");
break;
}
}
log("");
}
为了做示范,在创建tilemap时,添加了四种object,都放置在名为Objects的层中,且四种object都添加了type属性以示区别,其中折线为1,多边形为2,椭圆为3,四边形为4。
这里可能要注意一下Value的用法,这是cocos2d中存储数据的类,与其相关的还有ValueVector、ValueMap等等,具体使用方法以后再介绍。
以上代码中,TMXObjectGroup即tilemap的object层,通过其getObjects方法可以获取其中存储的所有object;之后遍历所有object,判断其type,做相关处理即可。