缓存机制
- Cocos2d-x纹理缓存
- Cocos2d-x精灵帧缓存
- Cocos2d-x动画缓存
纹理缓存
事实上,当我们创建精灵时,引擎已经帮我们做了缓存,因而我们下次调用的图片可以从缓存获得,减少了内存的消耗,下面我们从源码入手,大致的了解创建精灵时,如何做纹理缓存。
实质上,纹理缓存类似一个字典库,而文件名就是索引的条件,我们可以根据文件名把图片缓存起来,也可以根据文件名获取缓存中的图片。
Sprite *grossini = Sprite::create("grossini_dance_01.png");<span style="white-space:pre"> </span>// 用图片创建精灵对象
接下来,转向精灵的create()函数的实现:
Sprite* Sprite::create(const std::string& filename)
{
Sprite *sprite = new (std::nothrow) Sprite();<span style="white-space:pre"> </span>// 用C++的方式,创建一个精灵
if (sprite && sprite->initWithFile(filename))<span style="white-space:pre"> </span>// 检查精灵对象,并进行文件初始化
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);<span style="white-space:pre"> </span>// 安全释放精灵对象
return nullptr;
}
转向精灵文件初始化:
bool Sprite::initWithFile(const std::string& filename)
{
CCASSERT(filename.size()>0,"Invalid filename for sprite");
// 生成纹理图片
Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename);
if (texture)
{
Rect rect = Rect::ZERO;
rect.size = texture->getContentSize();
return initWithTexture(texture,rect);<span style="white-space:pre"> </span>// 初始化纹理,将纹理图片进行添加
}
// don't release here.
// when load texture Failed,it's better to get a "transparent" sprite then a crashed program
// this->release();
return false;
}
bool Sprite::initWithTexture(Texture2D *texture,const Rect& rect)
{
return initWithTexture(texture,rect,false);<span style="white-space:pre"> </span>// 初始化纹理
}
转向初始化纹理initWithTexture(texture,rect):
<pre name="code" class="cpp">bool Sprite::initWithTexture(Texture2D *texture,const Rect& rect,bool rotated)
{
bool result;
if (Node::init())
{
............
............
// 这里是关键点,将纹理图片设置添加到纹理缓存
setTexture(texture);
// 设置纹理矩形
setTextureRect(rect,rotated,rect.size);
_polyInfo.setQuad(&_quad);
// by default use "Self Render".
// if the sprite is added to a batchnode,then it will automatically switch to "batchnode Render"
setBatchNode(nullptr);
result = true;
}
else
{
result = false;
}
_recursiveDirty = true;
setDirty(true);
return result;
}
继而查看将纹理图片设置添加到纹理缓存setTexture(texture);,其他的我们不需要注意,只需看如何将图片添加到纹理缓存:
<pre name="code" class="cpp">void Sprite::setTexture(Texture2D *texture)
{
// If batchnode,then texture id should be the same
CCASSERT(! _batchNode || texture->getName() == _batchNode->getTexture()->getName(),"CCSprite: Batched sprites should use the same texture as the batchnode");
// accept texture==nil as argument
CCASSERT( !texture || dynamic_cast<Texture2D*>(texture),"setTexture expects a Texture2D. Invalid argument");
if (texture == nullptr)
{
// 根据图片文件名,从纹理缓存中获取纹理图片
texture = Director::getInstance()->getTextureCache()->getTextureForKey(CC_2x2_WHITE_IMAGE_KEY);
// 如果获取内容为NULL,说明为缓存至纹理缓存
if (texture == nullptr)
{
Image* image = new (std::nothrow) Image();
bool isOK = image->initWithRawData(cc_2x2_white_image,sizeof(cc_2x2_white_image),2,8);
CC_UNUSED_ParaM(isOK);
CCASSERT(isOK,"The 2x2 empty texture was created unsuccessfully.");
// 根据图片文件名,将图片添加到纹理缓存
texture = Director::getInstance()->getTextureCache()->addImage(image,CC_2x2_WHITE_IMAGE_KEY);
CC_SAFE_RELEASE(image);
}
}
if (!_batchNode && _texture != texture)
{
CC_SAFE_RETAIN(texture);
CC_SAFE_RELEASE(_texture);
_texture = texture;
updateBlendFunc();
}
}
至此,我们就将图片添加到纹理缓存并创建了一个精灵对象。
接下来,我们看一下如何添加纹理图片,转回
Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename);
<pre name="code" class="cpp">Texture2D * TextureCache::addImage(const std::string &path)
{
Texture2D * texture = nullptr;
Image* image = nullptr;
// Split up directory and filename
// MUTEX:
// Needed since addImageAsync calls this method from a different thread
// 通过FileUtils::getInstance()->fullPathForFilename(path);获取完整的路径
std::string fullpath = FileUtils::getInstance()->fullPathForFilename(path);
if (fullpath.size() == 0)
{
return nullptr;
}
// 通过路径寻找纹理缓存中是否存在
auto it = _textures.find(fullpath);
if( it != _textures.end() )
texture = it->second;
// 如若不存在
if (! texture)
{
// all images are handled by UIImage except PVR extension that is handled by our own handler
do
{
image = new (std::nothrow) Image();
CC_BREAK_IF(nullptr == image);
bool bRet = image->initWithImageFile(fullpath);
CC_BREAK_IF(!bRet);
texture = new (std::nothrow) Texture2D();
// 将图片添加转换成纹理
if( texture && texture->initWithImage(image) )
{
#if CC_ENABLE_CACHE_TEXTURE_DATA
// 缓存纹理及文件名
VolatileTextureMgr::addImageTexture(texture,fullpath);
#endif
// _textures为纹理缓存字典,将纹理及路径插入到字典
_textures.insert( std::make_pair(fullpath,texture) );
//parse 9-patch info
this->parseNinePatchImage(image,texture,path);
}
else
{
cclOG("cocos2d: Couldn't create texture for file:%s in TextureCache",path.c_str());
}
} while (0);
}
CC_SAFE_RELEASE(image);
return texture;
}
精灵帧缓存