Cocos2dx項目--動作類游戲內存優化--Spine結構分析1


SPine數據組織

spAtlas:這個是從.atlas文件中解出來的結構,其中包含了紋理

struct spAtlas {
    spAtlasPage* pages;
    spAtlasRegion* regions;
    void* rendererObject;
    int ref;
};

先不要管,看它的數據組織,spAtlasPage,spAtlasRegion,rendererObject都是什么東西?往下看

struct spAtlasPage {
    const spAtlas* atlas;
    const char* name;
    spAtlasFormat format;
    spAtlasFilter minFilter, magFilter;
    spAtlasWrap uWrap, vWrap;
    void* rendererObject;
    int width, height;
    spAtlasPage* next;
};


spAtalsPage看它的成員,可以很簡單看出,哇哦,這個就是紋理,給你看看真相,哈哈

void _spAtlasPage_createTexture (spAtlasPage* self, const char* path) {
    CCTexture2D* texture = CCTextureCache::sharedTextureCache()->addImage(path);
    texture->retain();
    self->rendererObject = texture;
    self->width = texture->getPixelsWide();
    self->height = texture->getPixelsHigh();
}


看見沒有,真相在這里,里面有了紋理的寬,高。奇葩的是他竟然還有(spAtlasPage* next),很明顯這是一個鏈表結構啊,如果你的一個動作文件,用到了多張紋理,那么這個指針就派上用場了。其他暫時忽略,看上面(_spAtlasPage_createTexture)發現沒有,這里把紋理給持有了。所以紋理不會釋放哦。

 

struct spAtlasRegion {
    const char* name;
    int x, y, width, height;
    float u, v, u2, v2;
    int offsetX, offsetY;
    int originalWidth, originalHeight;
    int index;
    int/*bool*/rotate;
    int/*bool*/flip;
    int* splits;
    int* pads;
    spAtlasPage* page;
    spAtlasRegion* next;
};

這貨一看,就是紋理當中包含的元素,一塊,一塊的描述信息。

看見這張紋理了嗎,它的每一塊都應該對應一個(spAtlasRegion)它。

這就是.atlas文件包含的信息啊!就是這樣圖片怎么怎么分割的,分隔成多少部分。每個部分的坐標是什么。

那個 renderobject是什么東西?我也不清楚,繼續看。

spAtlas* spAtlas_create (const char* begin, int length, const char* dir, void* rendererObject) {
    spAtlas* self;

    int count;
    const char* end = begin + length;
    int dirLength = strlen(dir);
    int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';

    spAtlasPage *page = 0;
    spAtlasPage *lastPage = 0;
    spAtlasRegion *lastRegion = 0;
    Str str;
    Str tuple[4];

    self = NEW(spAtlas);
    self->rendererObject = rendererObject;
        ................  

看見沒有,亮點在最后一句。創建這個對象的時候,需要傳進來一個東西void* rendererObject,然后,這個東西又賦予給了自己
 spAtlas* self;

    .......
    self = NEW(spAtlas);
    self->rendererObject = rendererObject;

然后在外面我的調用是

atlas = spAtlas_createFromFile(atlasFile, 0);  我竟然傳了一個0,哈哈,沒有用,暫時到這里。

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、

.JSON文件放的就是上面這些spAtlasRegion的樹形結構的組織信息,也就是骨架信息,和每個動作信息,每個動作當中每個關鍵幀中各個Region的數據。哈哈。

 

先看看,創建的代碼

SkeletonRenderer::SkeletonRenderer (const char* skeletonDataFile, const char* atlasFile, float scale) {
    initialize();

    if(1)
    {
        CTimeMgr::GetInst()->time_begin("spAtlas_createFromFile");
        atlas = spAtlas_createFromFile(atlasFile, 0);
        CCAssert(atlas, "Error reading atlas file.");
        CTimeMgr::GetInst()->time_end();

        CTimeMgr::GetInst()->time_begin("spSkeletonJson_create");
        spSkeletonJson* json = spSkeletonJson_create(atlas);
        CTimeMgr::GetInst()->time_end();

        json->scale = scale;
        CTimeMgr::GetInst()->time_begin("spSkeletonJson_readSkeletonDataFile");
        spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile);
        CTimeMgr::GetInst()->time_end();
        CCAssert(skeletonData, json->error ? json->error : "Error reading skeleton data file.");
        spSkeletonJson_dispose(json);
        setSkeletonData(skeletonData, true);
    }
    else
    {
        atlas = spAtlas_createFromFile(atlasFile, 0);
        CCAssert(atlas, "Error reading atlas file.");
        spSkeletonJson* json = spSkeletonJson_create(atlas);
        json->scale = scale;
        spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile);
        CCAssert(skeletonData, json->error ? json->error : "Error reading skeleton data file.");
        spSkeletonJson_dispose(json);
        setSkeletonData(skeletonData, true);
    }
    
}

if(1)中的內容,是我改的,else里面的內容是原有的。我改的目的,是為了1次加載多次使用,當然別的地方響應的有引用計數的析構了。還是老實的看else中的內容吧。
      

      atlas = spAtlas_createFromFile(atlasFile, 0); 這個不用說了吧,我們暫且叫創建紋理圖集吧
       spSkeletonJson* json = spSkeletonJson_create(atlas); 根據紋理圖集,創建一個JSON對象,它就像一個漏斗一樣,紋理解析JSON文件准備的,用完就析構了。
       json->scale = scale;
       spSkeletonData* skeletonData = spSkeletonJson_readSkeletonDataFile(json, skeletonDataFile);解析骨架文件
       spSkeletonJson_dispose(json); 漏斗析構了吧
       setSkeletonData(skeletonData, true); (以上代碼在SkeletonRenderer類的構造函數中,所以,看清楚沒有,解析出來的spSkeletonData被SkeletonRenderer持有了吧)

 

spSkeletonData* spSkeletonJson_readSkeletonDataFile (spSkeletonJson* self, const char* path) {
    int length;
    spSkeletonData* skeletonData;
    const char* json = _spUtil_readFile(path, &length);
    if (!json) {
        _spSkeletonJson_setError(self, 0, "Unable to read skeleton file: ", path);
        return 0;
    }
    skeletonData = spSkeletonJson_readSkeletonData(self, json);
    FREE(json);
    return skeletonData;
}

這里干啥了,亮點在這句 skeletonData = spSkeletonJson_readSkeletonData(self, json);
反正大家知道這里面解析了JSON文件就可以了!

行了。我們只要知道JSON文件是要給包含骨架組織和動畫運動的數據就可以了。而ATLAS文件才是與紋理相關就OK了。我們要做的是讓它不持有紋理,想用的時候加載,不想用的時候,把紋理都卸掉就可以了!

假如加載紋理需要40ms,紋理占有內存512*512*4 = 1M,如果我們按照這個目標更改的話。其實是用了40ms換去了1M內存。

速度和內存是需要平衡的。哈哈,我們下面要開始做微創手術了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM