您好,登錄后才能下訂單哦!
【嘮叨】
Cocos引擎主要有三種緩存類:
> 紋理緩存 : TextureCache
> 精靈幀緩存 : SpriteFrameCache
> 動畫緩存 : AnimationCache
緩存的目的就是:先將所需資源(如紋理圖片)加載到內存中,之后再次使用該資源的時候,就可以直接從內存中取出,而不需要重新加載。從而減少了CPU和GPU的內存占用。
本文對參考文獻的內容進行了整理與整合,并加入一些自己的觀點。
【致謝】
http://www.cocoachina.com/bbs/read.php?tid-200714.html (紋理緩存TextureCache)
http://www.cocoachina.com/bbs/read.php?tid-200359.html (精靈幀緩存SpriteFrameCache)
http://www.cocoachina.com/bbs/read.php?tid-201628.html (動畫緩存AnimationCache)
http://blog.csdn.net/star530/article/details/23612487 (三種緩存類介紹)
【TextureCache】
1、概述
在游戲中需要加載大量的紋理圖片,這些操作都是很耗內存和資源的。
當游戲中有個界面用到的圖片非常多,第一次點進這界面時速度非常慢(因為要加載繪制很多圖片)出現卡頓,我們可以使用TextureCache提前異步加載紋理,等加載結束,進入到這個界面再使用這些圖片速度就會非常快。
> Texture2D(紋理) :即圖片加載入內存后供CPU和GPU操作的貼圖對象。
> TextureCache(紋理緩存):用于加載和管理紋理。一旦紋理加載完成,下次使用時可使用它返回之前加載的紋理,從而減少對GPU和CPU內存的占用。
當你創建一個精靈Sprite,你一般會使用Sprite::create(fileName)。假如你去看Sprite::create(fileName)的實現方式,你將看到它將這個圖片增加到紋理緩存中去了。
// 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; } //
2、獲取TextureCache
在3.x版本中,TextureCache不再作為單例模式使用。而是作為Director的成員變量,通過以下方式獲取。
// // 獲取紋理緩存類 TextureCache Director::getInstance()->getTextureCache(); //
3、紋理的加載與獲取
如果文件名以前沒有被加載時,它會創建一個新的 Texture2D 對象,它會返回它。它將使用文件名作為key否則,它會返回一個引用先前加載的圖像。
> addImage :函數會返回一個紋理Texture2D的引用,可能是新加載到內存的,也可能是之前已經存在的。
> getTextureForKey :獲得這個key所對應的紋理緩存,若這個Key對應的紋理不存在,那么就返回nullptr。
> 支持的圖片格式有: .png,.bmp,.tiff, .jpeg, .pvr 。
// // addImage 加載紋理圖片 // 支持圖片格式: .png, .bmp, .tiff, .jpeg, .pvr Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename); // getTextureForKey 獲取紋理圖片 Texture2D *texture = Director::getInstance()->getTextureCache()->getTextureForKey(textureKeyName); //
4、異步加載紋理
TextureCache類還支持異步加載資源的功能,利用 addImageAsync 方法。你可以很方面地給addImageAsync方法添加一個回調方法,這樣,當紋理異步加載結束的時候,可以得到通知。
> 支持的圖片格式有:.png, .jpg 。
你可以選擇異步加載方式,這樣你就可以為loading場景增加一個進度條。
關鍵代碼如下:
// TextureCacheTest::TextureCacheTest() : _numberOfSprites(20) , _numberOfLoadedSprites(0) { auto size = Director::getInstance()->getWinSize(); _labelLoading = Label::createWithTTF("loading...", "fonts/arial.ttf", 15); _labelPercent = Label::createWithTTF("%0", "fonts/arial.ttf", 15); _labelLoading->setPosition(Point(size.width / 2, size.height / 2 - 20)); _labelPercent->setPosition(Point(size.width / 2, size.height / 2 + 20)); this->addChild(_labelLoading); this->addChild(_labelPercent); // 異步加載紋理圖片 addImageAsync // 加載完紋理后,會執行回調函數 Director::getInstance()->getTextureCache()->addImageAsync("Images/HelloWorld.png", CC_CALLBACK_1(TextureCacheTest::loadingCallBack, this)); Director::getInstance()->getTextureCache()->addImageAsync("Images/grossini.png", CC_CALLBACK_1(TextureCacheTest::loadingCallBack, this)); Director::getInstance()->getTextureCache()->addImageAsync("Images/CloseNormal.png", CC_CALLBACK_1(TextureCacheTest::loadingCallBack, this)); .... } // 異步加載的回調函數 void TextureCacheTest::loadingCallBack(cocos2d::Texture2D *texture) { ++_numberOfLoadedSprites; char tmp[10]; sprintf(tmp,"%%%d", (int)(((float)_numberOfLoadedSprites / _numberOfSprites) * 100)); _labelPercent->setString(tmp); if (_numberOfLoadedSprites == _numberOfSprites) { this->removeChild(_labelLoading, true); this->removeChild(_labelPercent, true); addSprite(); } } //
5、清理緩存
// // 釋放當前所有引用計數為1的紋理,即目前沒有被使用的紋理。 // 比如新場景創建好后,使用此方法釋放沒有使用的紋理非常方便。 Director::getInstance()->getTextureCache()->removeUnusedTextures(); // 通過給定的紋理貼圖(texture)的關鍵名(key name)從緩存中刪除該紋理貼圖 Director::getInstance()->getTextureCache()->removeTextureForKey("Images/grossinis.png"); // 清除加載紋理貼圖的記錄,如果你收到“內存警告”,請調用該方法。 // 在短期內 : 會釋放一些資源文件來防止你的app出現閃退現象 // 在中期內 : 會分配更多資源 // 長遠來看 : 沒有區別 Director::getInstance()->getTextureCache()->removeAllTextures(); //
【SpriteFrameCache】
1、概述
SpriteFrameCache 主要服務于多張碎圖合并出來的紋理圖片。這種紋理在一張大圖中包含了多張小圖,直接通過TextureCache引用會有諸多不便,因而衍生出來精靈框幀的處理方式,即把截取好的紋理信息保存在一個精靈框幀內,精靈通過切換不同的框幀來顯示出不同的圖案。
SpriteFrameCache 內部封裝了一個Map<std::string, SpriteFrame*> _spriteFrames對象。(其中key為幀的名稱)
SpriteFrameCache一般用來 處理 plist文件 (這個文件指定了每個獨立的精靈在這張“大圖”里面的位置和大小),該文件對應一張包含多個精靈的大圖,plist文件可以使用TexturePacker制作。
SpriteFrameCache的常用接口和TextureCache類似,不再贅述了,唯一需要注意的是添加精靈幀的配套文件一個plist文件和一張大的紋理圖。
2、獲取與銷毀SpriteFrameCache
SpriteFrameCache是一個單例對象,所以獲取方法與Director一樣。
// // 獲取單例對象 SpriteFrameCache* cache = SpriteFrameCache::getInstance(); // 銷毀單例對象 SpriteFrameCache::destroyInstance(); //
3、精靈幀的加載與使用
通過 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); //
4、清理緩存
// // 從精靈幀緩存中刪除一個精靈幀. 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(); //
5、SpriteFrameCache VS. TextureCache
SpriteFrameCache精靈框幀緩存。顧名思義,這里緩存的是精靈幀SpriteFrame,它主要服務于多張碎圖合并出來的紋理圖片(plist文件)。這種紋理在一張大圖中包含了多張小圖,直接通過TextureCache引用會有諸多不便,因而衍生出來精靈框幀的處理方式,即把截取好的紋理信息保存在一個精靈框幀內,精靈通過切換不同的框幀來顯示出不同的圖案。
跟TextureCache功能一樣,將SpriteFrame緩存起來,在下次使用的時候直接去取。
不過跟TextureCache不同的是:如果內存池中不存在要查找的圖片,它會提示找不到,而不會去本地加載圖片。
> TextureCache時最底層也是最有效的紋理緩存,緩存的是加載到內存中的紋理資源,也就是圖片資源。
> SpriteFrameCache精靈框幀緩存,緩存的時精靈幀。
> SpriteFrameCache是基于TextureCache上的封裝。緩存的是精靈幀,是紋理指定區域的矩形塊。各精靈幀都在同一紋理中,通過切換不同的框幀來顯示出不同的圖案。
【AnimationCache】
1、概述
通常情況下,對于一個精靈動畫,每次創建時都需要加載精靈幀,然后按順序添加到數組,再用Animation讀取數組創建動畫。這是一個非常煩瑣的計算過程。而對于使用頻率高的動畫,例如角色的走動、跳舞等,可以將其加入到AnimationCache中,每次使用都從這個緩存中調用,這樣可以有效的降低創建動畫的巨大消耗。
所以將創建好的動畫Animation直接放在動畫緩存AnimationCache中,當需要執行動畫動作時,就直接從動畫緩存中拿出來,去創建初始化Animation會非常方便。
2、相關函數
AnimationCache是一個單例對象,所以獲取方法與Director一樣。
通過 AnimationCache::getInstance() 獲取單例對象。
其相關函數如下:
// // 添加一個動畫到緩存,命名為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); //
3、使用舉例
// // //動畫命名為 Explosion,加入到動畫緩存中 Animation* animation = Animation::createWithSpriteFrames(arr, 0.04); AnimationCache::getInstance()->addAnimation(animation, "Explosion"); //直接從動畫緩存中取出 "Explosion" 動畫 Animation* animation = AnimationCache::getInstance()->getAnimation("Explosion"); // //
【清理順序】
值得注意的是清理的順序。
我們推薦 清理順序 如下:
> 首先清理,動畫緩存AnimationCache,
> 然后清理,精靈幀緩存SpriteFrameCache,
> 最后清理,紋理緩存TextureCache。
按照引用層級由高到低,以保證釋放引用有效。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。