接上一章《Cocos2d-x源碼解析(1)——地圖模塊(1)》
首先TMX文件本身就是XML格式,我們可以隨手做一個來分析TM自身的結構。
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="orthogonal" width="100" height="100" tilewidth="32" tileheight="32">
<tileset firstgid="1" name="210201333565" tilewidth="32" tileheight="32">
<image source="D:/project/games/cocos2d-x-2.2.2/cocos2d-x-2.2.2/template/multi-platform-cpp/Resources/210201333565.png" width="256" height="256"/>
</tileset>
<layer name="塊層 1" width="100" height="100">
<data encoding="base64" compression="zlib">
eJztwwEJAAAMBKEL8P3zDpZDwVVTVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVX/AcA31NA=
</data>
</layer>
</map>
我們可以發現,大部分的標籤和屬性都在每個節點的開始節點(</xxx>是結束節點)
那麼我們就可以去看看 代碼
void CCTMXMapInfo::startElement(void *ctx, const char *name, const char **atts)
{
CC_UNUSED_PARAM(ctx);
CCTMXMapInfo *pTMXMapInfo = this;
std::string elementName = (char*)name;
std::map<std::string, std::string> *attributeDict = new std::map<std::string, std::string>();
if (atts && atts[0])
{
for(int i = 0; atts[i]; i += 2)
{
std::string key = (char*)atts[i];
std::string value = (char*)atts[i+1];
attributeDict->insert(pair<std::string, std::string>(key, value));
}
}
if (elementName == "map")
{
我們發現cocos將xml的屬性預處理到一個Map中,然後根據不同的標籤名來做對應的處理。
那麼我們拿layer進行舉例
else if (elementName == "layer")
{
CCTMXLayerInfo *layer = new CCTMXLayerInfo();
layer->m_sName = valueForKey("name", attributeDict);
CCSize s;
s.width = (float)atof(valueForKey("width", attributeDict));
s.height = (float)atof(valueForKey("height", attributeDict));
layer->m_tLayerSize = s;
std::string visible = valueForKey("visible", attributeDict);
layer->m_bVisible = !(visible == "0");
std::string opacity = valueForKey("opacity", attributeDict);
if( opacity != "" )
{
layer->m_cOpacity = (unsigned char)(255 * atof(opacity.c_str()));
}
else
{
layer->m_cOpacity = 255;
}
float x = (float)atof(valueForKey("x", attributeDict));
float y = (float)atof(valueForKey("y", attributeDict));
layer->m_tOffset = ccp(x,y);
pTMXMapInfo->getLayers()->addObject(layer);
layer->release();
// The parent element is now "layer"
pTMXMapInfo->setParentElement(TMXPropertyLayer);
}
我們發現他將layer的信息都裝進了CCTMXLayerInfo,這個類中,因此我們可以知道CCTMXLayerInfo是存儲圖層信息,CCTMXTilesetInfo是存儲瓦片信息,CCTMXMapInfo是存儲地圖級別的信息。
另外,我們還注意到 pTMXMapInfo->setParentElement(TMXPropertyLayer);這句,cocos通過這樣的方式來告訴下一次找到元素時,他的父節點是誰。
但是,就有一個問題,就是這些信息cocos都將他存儲到CCArray中,如何能找到每個元素對應的瓦片信息呢。我們在endElement(void *ctx, const char *name)函數中找到了答案:
if(elementName == "data" && pTMXMapInfo->getLayerAttribs()&TMXLayerAttribBase64)
{
pTMXMapInfo->setStoringCharacters(false);
CCTMXLayerInfo* layer = (CCTMXLayerInfo*)pTMXMapInfo->getLayers()->lastObject();
std::string currentString = pTMXMapInfo->getCurrentString();
unsigned char *buffer;
len = base64Decode((unsigned char*)currentString.c_str(), (unsigned int)currentString.length(), &buffer);
if( ! buffer )
{
CCLOG("cocos2d: TiledMap: decode data error");
return;
}
if( pTMXMapInfo->getLayerAttribs() & (TMXLayerAttribGzip | TMXLayerAttribZlib) )
{
unsigned char *deflated;
CCSize s = layer->m_tLayerSize;
// int sizeHint = s.width * s.height * sizeof(uint32_t);
int sizeHint = (int)(s.width * s.height * sizeof(unsigned int));
int inflatedLen = ZipUtils::ccInflateMemoryWithHint(buffer, len, &deflated, sizeHint);
CCAssert(inflatedLen == sizeHint, "");
inflatedLen = (size_t)&inflatedLen; // XXX: to avoid warnings in compiler
delete [] buffer;
buffer = NULL;
if( ! deflated )
{
CCLOG("cocos2d: TiledMap: inflate data error");
return;
}
layer->m_pTiles = (unsigned int*) deflated;
}
else
{
layer->m_pTiles = (unsigned int*) buffer;
}
pTMXMapInfo->setCurrentString("");
}