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");
//

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