代码地址: https://github.com/mversace/CrossGateRemastered
地图文件头:
#pragma pack(1)
struct tMapHead
{
char cFlag[12];
unsigned int w;
unsigned int h;
}; // 后续紧跟w*h
#pragma pack()
后边紧跟 w*h*2
的3组数据,分别是地表、物件、未知
tiled map支持很多格式。这里为了方便转成了json格式。
tiled map,一张地图有一个例如map.json,其中的图块集也会存储为 xx.json
官方文档:https://doc.mapeditor.org/en/stable/reference/json-map-format/
魔力地图本身是45度的。所以tiled map中要设置地图属性为45度
我在这里是自己随便拼了一张地图,然后查看生成的json格式,对比着做的。跟官网的字段不太一样。官网的其实是比较老的。
因为写json,采用了一个第三方库:https://github.com/nlohmann/json
unsigned short n = 0;
int i = 0;
while (2 == fread_s(&n, 2, 1, 2, pFile))
{
if (i < dataLen)
{
// 获取地表信息
_vTileData.push_back((int)n);
if (n > 0)
_mapTileMap[n] = 0;
}
else if (i < dataLen * 2)
{
// 物件信息
_vObjectData.push_back((int)n);
if (n > 0)
_mapObjectMap[n] = 0;
}
else
{
// 未知信息
break;
}
++i;
}
拷贝图片到想要的目录, 并且声称图片集
考虑到方便以后单张地图修改,这里每张地图建立了一个文件夹,把涉及到的所有tile、object拷贝进来并生成图块集json
代码就不贴了。
生成tiled map需要的json子项–地表层
对于最终的tiled map地图来说,该json中存储有所有的地表数据以及物件数据。
接下来就是生成对应的地表数据。
这里需要注意的是。魔力地图存数据的格式为左下到右上,tiled map中为右上到右下。所以需要对vec进行一次顺时针90度的转换。同时宽高也要转换下
// 地表基础数据
_tileJsonData["width"] = _mapHead.h; // 注意这里是反的
_tileJsonData["height"] = _mapHead.w;
_tileJsonData["name"] = "layer"; // 如果写中文要写成utf-8格式
_tileJsonData["id"] = 1;
_tileJsonData["opacity"] = 1;
_tileJsonData["type"] = "tilelayer";
_tileJsonData["visible"] = true;
_tileJsonData["x"] = 0;
_tileJsonData["y"] = 0;
_tileJsonData["data"] = nlohmann::json::array();
// 把魔力地图转为w*h的二维数组,需要顺时针旋转90度以适配tiled map
int len = _mapHead.w * _mapHead.h;
for (int i = 0; i < len; ++i)
{
int row = i % _mapHead.h;
int col = _mapHead.w - i / _mapHead.h - 1;
int idx = row * _mapHead.w + col;
_tileJsonData["data"].push_back(_mapTileMap[_vTileData[idx]]);
}
注意:这里有个魔数。按照规则来看,这个值应该是47/2=23,但是效果不对,最终调整为魔数13完美契合。
/**
* 原始地图中,会拿出当前坐标的中心点为锚点,图片左上角放到锚点,然后x和y加上对应的偏移开始绘制
在tiled map中,把物件直接放到对应位置,则这张图片相对于该坐标中心点(锚点)的偏移为 -w/2, 23-h
而偏移应该为xOffset以及yOffset,做出对应的处理
横向方向还需要的偏移xTemp = xOffset-(-w/2)
因为地图tile大小为64*47。
如果xTemp = -64,则x += -47, y -= -47
如果xTemp = 64,则x += 47, y -= 47
最终也就是 x += (xOffset + w / 2) / 64 * 47, y -= x += (xOffset + w / 2) / 64 * 47
竖向方向还需要的偏移yTemp = yOffset-(23-h)
yTemp为正,则 (x,y) += |yTemp|,为负,则(x,y) += |yTemp| 最终也就是(x,y) += (yOffset-(23-h))
*/
double xOffset = (jsonItem["xOffset"].get() + jsonItem["width"].get() / 2.0) / 64.0 * 47.0;
double yOffset = (jsonItem["yOffset"].get() + jsonItem["height"].get() - 13); // 13 magic number...
_objJsonData["objects"].push_back({
{"gid", _mapObjectMap[objId] + idxBegin},
{"id", ++id},
{"name", ""},
{"rotation", 0},
{"type", ""},
{"visibale", true},
{"width", jsonItem["width"]},
{"height", jsonItem["height"]},
{"x", (row + 1) * 47 + yOffset + xOffset },
{"y", (_mapHead.w - col) * 47 + yOffset - xOffset }
});
void CGetCGMap::buildTiledMap()
{
std::cout << "build tiled Map json" << std::endl;
nlohmann::json tiledMapJson;
tiledMapJson["width"] = _mapHead.h; // 注意这里是反的
tiledMapJson["height"] = _mapHead.w;
tiledMapJson["infinite"] = false;
tiledMapJson["orientation"] = "isometric";
tiledMapJson["renderorder"] = "left-up";
tiledMapJson["tileversion"] = "1.2.2";
tiledMapJson["tilewidth"] = 64; // 这里写死,特殊的地图图块很大,自己拼就可以了
tiledMapJson["tileheight"] = 47;
tiledMapJson["type"] = "map";
tiledMapJson["version"] = 1.2;
tiledMapJson["tilesets"] = nlohmann::json::array();
tiledMapJson["tilesets"].push_back({
{"firstgid", 1},
{"source", _strTileJsonName}
});
tiledMapJson["tilesets"].push_back({
{"firstgid", (_mapTileMap.size() / 1000 + 1) * 1000},
{"source", _strObjJsonName}
});
tiledMapJson["layers"] = nlohmann::json::array();
tiledMapJson["layers"].push_back(_tileJsonData);
tiledMapJson["layers"].push_back(_objJsonData);
std::ofstream ofs;
ofs.open((_strTiledMapPath + _strMapOnlyName + "_map.json").c_str());
if (ofs.good())
{
ofs << std::setw(4) << tiledMapJson << std::endl;
ofs.close();
}
}
本次工作仅仅生成了map/0下的地图。因为一些新地图地表大小变化了。而且在代码中实际上写死了地表tile的宽高。
对于新地图可以自行生成,直接拼接也很简单,因为图块很大。
法兰城预览: