quick-cocos2d-x下有关缓存图片的管理策略

来源:互联网 发布:程序员考试报名时间 编辑:程序博客网 时间:2024/05/18 01:49
       首先介绍下quick-cocos2d-x这款引擎,quick-cocos2d-x 是在官方 cocos2d-x + Lua 版本的基础上修改起来的增强版(目前的稳定版基于 cocos2d-x 2.2)。在底层 API 上,quick 和 cocos2d-x 保持一致,而 quick 扩展的 API 主要分为两个部分:
1. quick 里提供了一个 Lua framework,封装了大部分的 C++ API,简化了使用。在大多数情况下,只需要熟悉 quick 的 API 就可以完成开发工作。
2. quick 中包含了不少游戏开发中必须的扩展,这些扩展也具有相应的 API。
       在使用Lua开发移动网络游戏的时候,通常一些图片资源需要在线下载然后缓存下来使用,为了节约存储空间,需要制定一个策略来对缓存图片资源进行回收处理。       对于下载的图片资源我们需要设定好存储路径,quick中使用全局变量device.writablePath即可获取到设备的可读写路径,它实际上就是调用cocos2d-x的CCFileUtils::sharedFileUtils()->getWritablePath()函数。当然我们也可以在这个路径下新建立一个cache目录。在游戏项目的入口lua文件可以添加CCFileUtils:sharedFileUtils():addSearchPath(device.writablePath .. "cache/")这句话,这样在加载资源的时候,会搜索该目录下的资源文件。当然cache目录是要预先创建的,否则在Android平台下可能报无法找到该路径的错误。       接下来需要写一个管理器来下载资源图片以及用一个表来对缓存资源进行维护,代码如下:
--[[下载图片的缓存管理器@author xujh]]ImageCacheManager = {}local gameState = require(cc.PACKAGE_NAME .. ".api.GameState")-- 图片缓存信息表,包括下载图片URL对应的md5值和最后更新时间local cacheData = {}-- 初始化GameState,存储缓存图片相关信息function ImageCacheManager:init()gameState.init(function(param)-- local returnValue = nilif param.errorCode thenprint("error")elseif param.name == "save" thenelseif param.name == "load" thenendendreturn param.valuesend, "image_cache.txt", nil)if io.exists(gameState.getGameStatePath()) thencacheData = gameState.load()endend--[[根据图片的md5值判断是否存在在缓存表中@param 图片的md5值@return 存在:true以及所在的位置,不存在:false]]function ImageCacheManager:exist(md5)for i = 1, #cacheData doif cacheData[i].md5 == md5 thenreturn true, iendendreturn falseend--[[修改图片在缓存表中的最后更新时间@param md5:图片的md5值, position:图片在缓存表中的位置]]function ImageCacheManager:updateCacheTime(md5, position)if cacheData[position].md5 == md5 thentable.remove(cacheData, position)self:insertCacheData(md5)-- dump(cacheData, "update")elseprint("ImageCacheManager updateCacheTime ERROR!")endend--[[根据缓存目录里的图片来创建精灵@param url 缓存图片的URL地址   x:精灵横向坐标值,y:精灵纵向坐标值@return 若缓存表中存在对应的md5值,返回创建的精灵对象]]function ImageCacheManager:newCacheSprite(url, x, y)local md5 = crypto.md5(url, false)local isExist, position = self:exist(md5)if isExist thenself:updateCacheTime(md5, position)local filename = md5 .. ".png"return display.newSprite(filename, x, y)endend--[[向图片缓存表中插入数据@param 图片的md5值]]function ImageCacheManager:insertCacheData(md5)local data = {}data.time = getCurrentMillis()data.md5 = md5if table.nums(cacheData) > 100 then-- 超过缓存上限,清除第一个元素(通常最久未更新时间戳)table.remove(cacheData, 1)endtable.insert(cacheData, data)gameState.save(cacheData)end--[[下载缓存图片@param url 下载图片的URL地址   callback 调用下载处的回调函数地址]]function ImageCacheManager:downloadImage(url, callback)local md5 = crypto.md5(url, false)if not self:exist(md5) thenlocal request = network.createHTTPRequest(function (event)local ok = (event.name == "completed")local request = event.requestif not ok thenprint(request:getErrorCode(), request:getErrorMessage())        returnendlocal code = request:getResponseStatusCode()    if code ~= 200 then        -- 请求结束,但没有返回 200 响应代码        print(code)        return    end    local filename = md5 .. ".png"    request:saveResponseData(device.writablePath .. "cache/" .. filename)    local item = {}    item.time = getCurrentMillis()    item.md5 = md5    table.insert(cacheData, item)gameState.save(cacheData)if callback then callback(url) endend, url, "GET")request:start()elseechoInfo("The %s has downloaded.", url)endend--[[根据需要删除缓存图片,释放存储空间]]function ImageCacheManager:gcCache()for i = #cacheData, 1, -1 dolocal recordTime = cacheData[i].timelocal currentTime = getCurrentMillis()if currentTime - recordTime > 7*24*3600 thenlocal cmdif (device.platform == "windows") thencmd = "DEL /Q " .. device.writablePath .. "cache\\" .. cacheData[i].md5 .. ".png"elsecmd = "rm -r " .. device.writablePath .. "cache/" .. cacheData[i].md5 .. ".png"endos.execute(cmd)table.remove(cacheData, i)endendgameState.save(cacheData)end

       下面来详细说明下代码的具体作用,首先需要一个配置文件来管理缓存目录下图片资源的一些信息,这里并没有使用cocos2d-x的CCUserDefault,而是采用了quick-cocos2d-x提供的GameState(具体用法参见http://www.kankanews.com/ICkengine/archives/69049.shtml)。使用GameState需要先进行初始化,分别传入回调函数地址、文件名称和密匙,在回调函数中我们可以根据需要对要save或是load的数据进行加密解密操作。如果已经存在配置文件,我们则将里面的内容赋给表cacheData。在cacheData表中,线性存放了每张缓存图片相关信息的表集合,主要是下载URL对应的md5值和最后更新时间。       
       ImageCacheManager:newCacheSprite函数中,会根据传入的url转换成对应的md5值(crypto.md5为quick封装好的函数),然后遍历查找cacheData表中是否存在该md5值,存在则更新该图片在cacheData表中的最后更新时间,然后调用quick-cocos2d-x中的display.newSprite来创建精灵并返回(缓存在存储空间中的图片名称即“md5值.png”),不存在即返回nil。       
       ImageCacheManager:downloadImage函数中,会根据传入的url通过CCHTTPRequest来进行下载操作。下载的图片以“md5值.png”的文件名存储在cache目录下,并获取当前时间戳连同md5值一同插入cacheData表的尾端,记得要调用GameState的sava函数进行保存操作。       
       ImageCacheManager:gcCache函数中,会倒序遍历cacheData表,当发现与当前时间戳之差超过7天时,则删除该文件,并在cacheData中remove该图片的信息。       
       在代码中获取当前时间的接口函数getCurretMillis是通过C++实现的,通过tolua++绑定到lua中,使之可以在lua代码中直接调用,具体实现代码如下:
#ifdef WIN32#include <time.h>#else#include <sys/time.h>#endiflong getCurrentMillis(){    long cur_time = 0;#ifdef WIN32    time_t now;    time(&now);    cur_time = now*1000;#else    struct timeval tv;    gettimeofday(&tv, NULL);    cur_time = tv.tv_sec*1000 + tv.tv_usec/1000;#endif    return cur_time;}


原创粉丝点击