cocos2dx 資源緩存

Cocos中有三種緩存類:

(1):紋理緩存:TextureCache

(2):精靈幀緩存:SpriteFrameCache

(3):動畫緩存:AnimationCache

遊戲最要重要的就是流暢度,如果我們的遊戲經常因爲加載資源出現卡頓的情況,那麼這個遊戲就沒有很好地遊戲體驗。所以,爲了解決這個問題,緩存就應運而生了。

緩存的目的就是:現將所需資源加載到內存中,之後再次使用該資源的時候,就可以直接從內存中讀出,而不需要重新加載,從而減少了CPU和GPU的內存佔用。

TextureCache
在遊戲中需要加載大量的紋理圖片,然而這些都是非常耗內存的,當遊戲中的某一個場景資源非常多的時候,我們第一次進入這個場景的時候會感覺非常卡,但是我們可以使用TextureCache提前異步加載紋理,等到加載結束,在進入這個場景速度會快很多。

Texture2D(紋理):即圖片加載入內存後供CPU和GPU操作的貼圖對象。
TextureCache(紋理緩存):用於加載和管理紋理。一旦紋理加載完成,下次使用它返回之前加載的紋理,從而減少對CPU和GPU的佔用。

我們創建一個精靈時一般都會create一個精靈,我們跟蹤create函數會發現下面的源代碼:

//
    Sprite* Sprite::create(const std::string& filename)
    {
        Sprite *sprite = new Sprite();
        if (sprite && sprite->initWithFile(filename))
        {
            sprite->autorelease();
            return sprite;
        }
        _SAFE_DELETE(sprite);
        return nullptr;
    }
    bool Sprite::initWithFile(const std::string& filename)
    {
        ASSERT(filename.size()>0, "Invalid filename for sprite");
        // 加載filename的紋理圖片
        Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename);
        if (texture)
        {
            Rect rect = Rect::ZERO;
            rect.size = texture->getContentSize();
            return initWithTexture(texture, rect);
        }
        return false;
    }
//
可以看到這個精靈被加載到紋理緩存中了。

第一次加載圖片時,現將圖片加載入TextureCache緩存中,下一步是繪製圖片,從而將其顯示在場景中。
第二次使用時,因爲之前已經被加載到緩存中去了。所以現在我們要做的就是從緩存中取出這個精靈了,下面的代碼做個總結:

//第一種載入精靈的方法
auto sp1 = Sprite::create("boy.png");
this->addChild(sp1,1);
 
//第二種載入精靈的方法
auto sp_cache = Director::getInstance()->addImage("boy.png");
auto sp1 = Sprite::createWithTexture(sp_cache);
this->addChild(sp1,1);

這兩種方法都一樣。他們都是現將圖片加載到緩存中去,然後再從緩存中拿出。但是第二種使用起來更加靈活,特別是當圖片非常多的時候,這個知識點常用的就是遊戲的資源加載界面。

SpriteFrameCache
SpriteFrameCache主要服務於多張對圖合併出來的紋理圖片。這種紋理在一張大圖中包含了多種小圖,直接使用TextureCache引用會非常不方便,因爲出現了精靈框幀的處理方式,即把截取好的紋理保存在一個精靈框幀內。

SpriteFrameCache一般用來處理plist文件(這個文件指定了每個獨立的精靈在這張“大圖”裏面的位置和大小),該文件對應一張包含多個精靈的大圖,plist文件可以使用TexturePacker製作。

SpriteFrameCache是一個單例模式

//
// 獲取單例對象
SpriteFrameCache* cache = SpriteFrameCache::getInstance();
// 銷燬單例對象
SpriteFrameCache::destroyInstance();
//


通過addSpriteFramesWithFile來加載plist文件,將plist文件中的多張小圖加載到精靈幀緩存中。

//
// boy.png 裏集合了boy1.png,boy2.png這些小圖。
// 參數2 可不寫
SpriteFrameCache *frameCache = SpriteFrameCache::getInstance();
frameCache->addSpriteFramesWithFile("boy.plist", "boy.png");
//從SpriteFrameCache緩存中找到boy1.png這張圖片.
auto frame_sp = Sprite::createWithSpriteFrameName("boy1.png");
this->addChild(frame_sp, 2);
//


清理緩存,下面的是一些清理緩存的API:

//
// 從精靈幀緩存中刪除一個精靈幀.
SpriteFrameCache::getInstance()->removeSpriteFrameByName(const std::string &name);
// 清除載入精靈幀的字典。如果接收到“Memory Warning”, 請調用這個方法。
// 就眼前來說 : 它將釋放一些資源來阻止你的應用崩潰掉。
// 中期的角度 : 它將分配更多的資源。
// 從長遠來說 : 它將變成相同的。
SpriteFrameCache::getInstance()->removeSpriteFrames();
// 從一個.plist文件移除多個精靈幀。即:存儲在這個文件的精靈幀將被刪除。
// 當某個特定的紋理需要被刪除時候調用這個方法很方便。
SpriteFrameCache::getInstance()->removeSpriteFramesFromFile(const std::string &plist);
// 移除與特定的紋理結合的所有的精靈幀。
// 當某個特定的紋理需要被刪除時候調用這個方法很方便。
SpriteFrameCache::getInstance()->removeSpriteFramesFromTexture(cocos2d::Texture2D *texture);
// 移除沒用的精靈幀。保留數爲1的精靈幀將被刪除。
// 在開始一個新的場景之後調用這個方法很方便。
SpriteFrameCache::getInstance()->removeUnusedSpriteFrames();
//

跟TextureCache不同的是,如果內存池中不存在要查找的圖片,它會提示找不到,而不會去加載本地圖片。

AnimationCache
這個相對來說就很容易了,是動畫的緩存,對於精靈動畫來說,每次創建的時候都需要記載精靈幀,然後按照順序加載到數組。再用Animation讀取數組創建動畫,這是一個非常繁瑣的過程。

然而對於使用頻率非常高的動畫,例如人物的走動、跳舞等可以將其加入到AnimationCache中們每次使用都從這個緩存中調用,這樣可以大大減少創建動畫的巨大消耗。
下面是相關API:
//
// 添加一個動畫到緩存,命名爲name。
// name - animation : 是一組 鍵-值對(key-value) 的關係。
void addAnimation(Animation *animation, const std::string& name);
// 添加動畫的plist文件到緩存
void addAnimationsWithFile(const std::string& plist);
// 獲得指定名稱爲name的動畫
Animation* getAnimation(const std::string& name);
// 移除一個指定的動畫
void removeAnimation(const std::string& name);
//

舉例:

//
//
//動畫命名爲 Explosion,加入到動畫緩存中
Animation* animation = Animation::createWithSpriteFrames(arr, 0.04);
AnimationCache::getInstance()->addAnimation(animation, "Explosion");
//直接從動畫緩存中取出 "Explosion" 動畫
Animation* animation = AnimationCache::getInstance()->getAnimation("Explosion");
//

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章