Cocos2d-lua自动重新加载SpriteFrames

来源:互联网 发布:html标签中使用js变量 编辑:程序博客网 时间:2024/05/18 16:56

昨天在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    endend
  • 在任何设置sprite frame的地方,比如:
-- 设置sprite的spriteframesprite:setSpriteFrame(framename)-- 或用spriteframe生成spritecc.Sprite:createWithSpriteFrameName(framename)-- 等等

都需要事先检查一下spriteFrame是否存在,如果不存在,则去查找对应的plist,重新加载一遍,伪代码如下:

function reload(framename)    local plist = _map[framename]    cc.SpriteFrameCache:getInstance():addSpriteFrames(plist)endlocal SpCache = cc.SpriteFrameCache:getInstance() function checkFrame(framename)    if not SpCache:getSpriteFrame(framename) then        reload(framename)    endend

恩,大概就这样了,可以再加一个cleanup函数,当某个合图不再使用,就把_map里有关这个合图的数据都清理掉,节约内存空间,这块伪代码就不写了。

测试了一下,不会再报错了。

这种问题之前应该也有人遇到过,不知道有没有更好的解决方案。我总感觉这是Cocos2d-x应该背的锅。╮(╯_╰)╭

0 0
原创粉丝点击