分享

quick

 爱蓝斯 2014-01-06
       首先介绍下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;
}
复制代码

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多