昨天在iOS上测试清宫Q传,玩了几把突然报错:
[LUA-print] ASSERT FAILED ON LUA EXECUTE: Invalid spriteFrameName :spsheet_1/img_004
当时一副懵逼( ⊙ o ⊙ ),合图spsheet_1肯定是在进入游戏的时候加载了,而且合图内其他的图片都正常显示了,怎么会突然找不到呢?
赶紧翻翻日志,在报错前果然找到了罪魁祸首:
2016-05-03 16:09:34.053 game[24503:15980923] Received memory warning.
让我们看看收到内存警告时都做了什么。
打开AppController.mm
:
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
cocos2d::Director::getInstance()->purgeCachedData();
}
再进入CCDirector.cpp
:
void Director::purgeCachedData(void)
{
FontFNT::purgeCachedData();
FontAtlasCache::purgeCachedData();
if (s_SharedDirector->getOpenGLView())
{
// 就是这里了
SpriteFrameCache::getInstance()->removeUnusedSpriteFrames();
_textureCache->removeUnusedTextures();
// Note: some tests such as ActionsTest are leaking refcounted textures
// There should be no test textures left in the cache
log("%s\n", _textureCache->getCachedTextureInfo().c_str());
}
FileUtils::getInstance()->purgeCachedEntries();
}
嗯,在内存警告时cocos2d-x会清理缓存数据,包括字体、纹理、spriteFrame等。那么问题来了,在游戏进行到一半的时候,突然缓存被清理了,该怎么进行呢?显然cocos2d-x并没有自动恢复机制。
只好自己写一个凑合用一下了。(>﹏<)
原理是这样的:
- 调用
cc.SpriteFrameCache:getInstance():addSpriteFrames(plist)
时,记录一下plist里framename和plist的关系,伪代码如下:
local _map = {}
function cacheSpritePlist(plist)
-- avoid muliple loading of the same plist
if tableValuesContain(_map, plist) then
logi("Frames Already added:", plist)
return
end
-- read plist data
local data = __readPList(plist)
-- record framename -> plistname
for fname, _ in pairs(data.frames) do
self.map[fname] = plist
end
end
- 在任何设置sprite frame的地方,比如:
-- 设置sprite的spriteframe
sprite:setSpriteFrame(framename)
-- 或用spriteframe生成sprite
cc.Sprite:createWithSpriteFrameName(framename)
-- 等等
都需要事先检查一下spriteFrame是否存在,如果不存在,则去查找对应的plist,重新加载一遍,伪代码如下:
function reload(framename)
local plist = _map[framename]
cc.SpriteFrameCache:getInstance():addSpriteFrames(plist)
end
local SpCache = cc.SpriteFrameCache:getInstance()
function checkFrame(framename)
if not SpCache:getSpriteFrame(framename) then
reload(framename)
end
end
恩,大概就这样了,可以再加一个cleanup
函数,当某个合图不再使用,就把_map
里有关这个合图的数据都清理掉,节约内存空间,这块伪代码就不写了。
测试了一下,不会再报错了。
这种问题之前应该也有人遇到过,不知道有没有更好的解决方案。我总感觉这是Cocos2d-x应该背的锅。╮(╯_╰)╭