首先介绍下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平台下可能报无法找到该路径的错误。 接下来需要写一个管理器来下载资源图片以及用一个表来对缓存资源进行维护,代码如下: 1 --[[ 2 下载图片的缓存管理器 3 @author xujh 4 ]] 5 6 ImageCacheManager = {} 7 8 local gameState = require(cc.PACKAGE_NAME .. ".api.GameState") 9 10 -- 图片缓存信息表,包括下载图片URL对应的md5值和最后更新时间 11 local cacheData = {} 12 13 -- 初始化GameState,存储缓存图片相关信息 14 function ImageCacheManager:init() 15 gameState.init(function(param) 16 -- local returnValue = nil 17 if param.errorCode then 18 print("error") 19 else 20 if param.name == "save" then 21 22 elseif param.name == "load" then 23 24 end 25 end 26 return param.values 27 end, "image_cache.txt", nil) 28 if io.exists(gameState.getGameStatePath()) then 29 cacheData = gameState.load() 30 end 31 end 32 33 --[[ 34 根据图片的md5值判断是否存在在缓存表中 35 @param 图片的md5值 36 @return 存在:true以及所在的位置,不存在:false 37 ]] 38 function ImageCacheManager:exist(md5) 39 for i = 1, #cacheData do 40 if cacheData[i].md5 == md5 then 41 return true, i 42 end 43 end 44 return false 45 end 46 47 --[[ 48 修改图片在缓存表中的最后更新时间 49 @param md5:图片的md5值, position:图片在缓存表中的位置 50 ]] 51 function ImageCacheManager:updateCacheTime(md5, position) 52 if cacheData[position].md5 == md5 then 53 table.remove(cacheData, position) 54 self:insertCacheData(md5) 55 -- dump(cacheData, "update") 56 else 57 print("ImageCacheManager updateCacheTime ERROR!") 58 end 59 end 60 61 --[[ 62 根据缓存目录里的图片来创建精灵 63 @param url 缓存图片的URL地址 64 x:精灵横向坐标值,y:精灵纵向坐标值 65 @return 若缓存表中存在对应的md5值,返回创建的精灵对象 66 ]] 67 function ImageCacheManager:newCacheSprite(url, x, y) 68 local md5 = crypto.md5(url, false) 69 local isExist, position = self:exist(md5) 70 if isExist then 71 self:updateCacheTime(md5, position) 72 local filename = md5 .. ".png" 73 return display.newSprite(filename, x, y) 74 end 75 end 76 77 --[[ 78 向图片缓存表中插入数据 79 @param 图片的md5值 80 ]] 81 function ImageCacheManager:insertCacheData(md5) 82 local data = {} 83 data.time = getCurrentMillis() 84 data.md5 = md5 85 if table.nums(cacheData) > 100 then 86 -- 超过缓存上限,清除第一个元素(通常最久未更新时间戳) 87 table.remove(cacheData, 1) 88 end 89 table.insert(cacheData, data) 90 gameState.save(cacheData) 91 end 92 93 --[[ 94 下载缓存图片 95 @param url 下载图片的URL地址 96 callback 调用下载处的回调函数地址 97 ]] 98 function ImageCacheManager:downloadImage(url, callback) 99 local md5 = crypto.md5(url, false) 100 if not self:exist(md5) then 101 local request = network.createHTTPRequest(function (event) 102 local ok = (event.name == "completed") 103 local request = event.request 104 if not ok then 105 print(request:getErrorCode(), request:getErrorMessage()) 106 return 107 end 108 local code = request:getResponseStatusCode() 109 if code ~= 200 then 110 -- 请求结束,但没有返回 200 响应代码 111 print(code) 112 return 113 end 114 local filename = md5 .. ".png" 115 request:saveResponseData(device.writablePath .. "cache/" .. filename) 116 local item = {} 117 item.time = getCurrentMillis() 118 item.md5 = md5 119 table.insert(cacheData, item) 120 gameState.save(cacheData) 121 if callback then callback(url) end 122 end, url, "GET") 123 request:start() 124 else 125 echoInfo("The %s has downloaded.", url) 126 end 127 end 128 129 130 --[[ 131 根据需要删除缓存图片,释放存储空间 132 ]] 133 function ImageCacheManager:gcCache() 134 for i = #cacheData, 1, -1 do 135 local recordTime = cacheData[i].time 136 local currentTime = getCurrentMillis() 137 if currentTime - recordTime > 7*24*3600 then 138 local cmd 139 if (device.platform == "windows") then 140 cmd = "DEL /Q " .. device.writablePath .. "cache\\" .. cacheData[i].md5 .. ".png" 141 else 142 cmd = "rm -r " .. device.writablePath .. "cache/" .. cacheData[i].md5 .. ".png" 143 end 144 os.execute(cmd) 145 table.remove(cacheData, i) 146 end 147 end 148 gameState.save(cacheData) 149 end 下面来详细说明下代码的具体作用,首先需要一个配置文件来管理缓存目录下图片资源的一些信息,这里并没有使用cocos2d-x的CCUserDefault,而是采用了quick-cocos2d-x提供的GameState(具体用法参见http://www./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> #endif long 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; }
|
|