Cocos2dx游戏教程(十八):三种缓存,TextureCache,SpriteFrameCache,AnimationCache

在前面的章节中,我们介绍了图片常用的加载方式和相关内存优化。这一节中主要介绍下cocos2dx的缓存。

首先致敬大神
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)

一、为什么使用缓存

在前面提到,在游戏中需要加载大量的纹理图片,这些操作都是很耗内存和资源的, 当游戏中有个界面用到的图片非常多,第一次点进这界面时速度非常慢(因为要加载绘制很多图片)出现卡顿的现象,第二次进入这个界面就非常快了,这是为什么呢?

下面就带着这个问题来一起看一下吧

首先,我们通常使用如下方式创建一个精灵Sprite

auto sp = Sprite::create("sprite.png");
sp->setPosition(Vec2::ZERO);
this->addchild(sp);

没错,又是这个(出现了好多次)

我们可以通过源代码了解到,我们创建精灵后,将精灵加入了缓存

Sprite* Sprite::create(const std::string& filename)
{    
    Sprite *sprite = new (std::nothrow) Sprite();
    if (sprite && sprite->initWithFile(filename))    
    {        
         sprite->autorelease();        
         return sprite;    
    }    
    CC_SAFE_DELETE(sprite);    
    return nullptr;
}

我们可以看到,在创建的时候调用了

sprite->initWithFile(filename)) 

那么下面来看一下 initWithFile 这个方法

bool Sprite::initWithFile(const std::string& filename)
{
    if (filename.empty())
    {
        CCLOG("Call Sprite::initWithFile with blank resource filename.");
        return false;
    }   

    _fileName = filename;
    _fileType = 0;

    Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename);
    
    if (texture)
    {
        Rect rect = Rect::ZERO;
        rect.size = texture->getContentSize();
        return initWithTexture(texture, rect);
    }
    
    return false;
}

注意这一行,获取了一个缓存加载了该图并返回一个纹理

Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename);

Texture2D: 纹理,即图片加载入内存后供CPU和GPU操作的贴图对象。
TextureCache(纹理缓存),用于加载和管理纹理。一旦纹理加载完成,下次使用时可使用它返回之前加载的纹理,从而减少对GPU和CPU内存的占用。

现在大家是不是对第二次加载速度变快有所了解了呢。

二、三种缓存

Cocos引擎主要有三种缓存类:纹理缓存:TextureCache,帧缓存:SpriteFrameCache,动画缓存:AnimationCache

这3个缓存类分别维护各自的map容器对象,对于容器,下一张将会单独介绍哦,现在先简单看一下:

TextureCache

std::unordered_map<std::string, Texture2D*> _textures;

SpriteFrameCache

Map<std::string, SpriteFrame*> _spriteFrames;ValueMap _spriteFramesAliases;std::set<std::string>*  _loadedFileNames;

AnimationCache

 Map<std::string, Animation*> _animations;

1、纹理缓存:TextureCache

上面大家已经初步了解了Sprite加载,如果文件名以前没有被加载时,它会创建一个新的Texture2D 对象,它会返回它。它将使用文件名作为key否则,它会返回一个引用先前加载的图像。

TextureCache屏蔽了加载纹理的许多细节;
addImage函数会返回一个纹理Texture2D的引用,可能是新加载到内存的,也可能是之前已经存在的;

Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename);

也可以通过getTextureForKey方法来获得这个key所对应的纹理缓存,如果这个Key对应的纹理不存在,那么就返回NULL

Texture2D *texture = Director::getInstance()->getTextureCache()->getTextureForKey(textureKeyName);

TextureCache类还支持异步加载资源的功能,利用addImageAsync方法。
可以在进度条或者跳转界面预先将资源加载好哦,那么在后面需要使用的时候就不会卡顿啦。

有加载当然有释放,removeUnusedTextures则会释放当前所有引用计数为1的纹理,即目前没有被使用的纹理。

Director::getInstance()->getTextureCache()->removeUnusedTextures();

指定释放

Director::getInstance()->getTextureCache()->removeTextureForKey("sp.png");

全部释放

Director::getInstance()->getTextureCache()->removeAllTextures();

2、帧缓存:SpriteFrameCache

SpriteFrameCache 主要服务于多张碎图合并出来的纹理图片。这种纹理在一张大图中包含了多张小图,直接通过TextureCache引用会有诸多不便,因而衍生出来精灵框帧的处理方式,即把截取好的纹理信息保存在一个精灵框帧内,精灵通过切换不同的框帧来显示出不同的图案。

SpriteFrameCache的常用接口和TextureCache类似,唯一需要注意的是添加精灵帧的配套文件一个plist文件和一张大的纹理图。TexturePacker工具是合成大图的良好选择哈。

使用方法

SpriteFrameCache *frameCache = SpriteFrameCache::getInstance();
frameCache->addSpriteFramesWithFile("boy.plist","boy.png");
auto frame_sp = Sprite::createWithSpriteFrameName("boy1.png");
this->addChild(frame_sp,2);

3、动画缓存:AnimationCache

Cocos2d-x中,动画的具体内容是依靠精灵显示出来的,为了显示动态图片,我们需要不停切换精灵显示的内容,通过把静态的精灵变为动画播放器从而实现动画效果。动画由帧组成,每一帧都是一个纹理,我们可以使用一个纹理序列来创建动画。

我们使用Animation类描述一个动画,而精灵显示动画的动作则是一个Animate对象。动画动作Animate是精灵显示动画的动作,它由一个动画对象创建,并由精灵执行。

有两种创建方法:

(1)手动添加序列帧到Animation类

手动添加的方法需要将每一帧要显示的精灵有序添加到Animation类中,并设置每帧的播放时间,让动画能够匀速播放。另外,还要通过setRestoreOriginalFrame来设置是否在动画播放结束后恢复到第一帧。创建好Animation实例后,需要创建一个Animate实例来播放序列帧动画。

auto animation = Animation::create();    
for( int i=1;i<15;i++)    {        
    char szName[100] = {0};        
    sprintf(szName, "sp_%02d.png", i);      
    animation ->addSpriteFrameWithFile(szName);
}      
animation->setDelayPerUnit(2.8f / 14.0f); 
animation->setRestoreOriginalFrame(true);
auto action = Animate::create(animation);    
_animation->runAction(Sequence::create(action, action->reverse(), NULL));

(2)使用文件初始化Animation类

AnimationCache可以加载xml/plist文件,plist文件里保存了组成动画的相关信息,通过该类获取到plist文件里的动画。

使用文件添加的方法只需将创建好的plist文件添加到动画缓存里面,plist文件里包含了序列帧的相关信息。再用动画缓存初始化Animation实例,用Animate实例来播放序列帧动画。

auto cache = AnimationCache::getInstance();    
cache->addAnimationsWithFile("animations/animations.plist");   
auto animation2 = cache->getAnimation("dance_1");    
auto action2 = Animate::create(animation2);   
_animation->runAction(Sequence::create(action2, action2->reverse(), NULL));
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值