Cocos2d-x源碼解析(1)——地圖模塊(2)

接上一章《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("");

    } 


在地圖生成的時候,就已經定義好了這個數值,因此在生成cclayer的時候快速地定位到哪個tile進行貼圖。



發佈了31 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章