最新文章
Cocos2d-x游戏开发实例详解7:对象释放时机
03-25 13:59
Cocos2d-x游戏开发实例详解6:自动释放池
03-25 13:55
Cocos2d-x游戏开发实例详解5:神奇的自动释放
03-25 13:49
Cocos2d-x游戏开发实例详解4:游戏主循环
03-25 13:44
Cocos2d-x游戏开发实例详解3:无限滚动地图
03-25 13:37
Cocos2d-x游戏开发实例详解2:开始菜单续
03-25 13:32
cocos2d-x update逻辑合理方案
一、方案背景与目标
新项目采用的是Quick - Cocos2d - x,本文将基于Quick - Cocos2d - x - Master( > 2.2.3 rc) 给出更新方案。该方案旨在解决以下几个问题:
- 资源、代码在线更新
- framework、update模块自更新
- 玩家安装新版本后,减少不必要的更新
- 更新中断的处理
- 解决Quick - Cocos2d - x中遇到的问题
完成上述几点后,整个更新方案应能稳定运行。
二、安装包内容
版本号说明
首先,涉及一个大版本号,它代表C++部分的版本号,只有当C++部分有变动时,这个版本号才会更新,用于提示用户去APPSTORE下载新的版本。其余版本号仅作为显示版本号,可根据游戏内容进行区分。
安装包资源
每一个安装包包含了所有游戏资源,即新版本发布后,玩家无需更新,点开即可玩。安装包内部带有一个文件列表,以LUA文件形式存在,内容如下:
local flist = {
core = 1,
version = "1.0.1",
update_md5 = "xxxxxx",
framework_md5 = "xxxxxx",
files = {
{path="ui/shop/shop_close_btn.png", md5="xxxxxx", size="30"},
{path="ui/army/army_tip.png", md5="xxxxxx", size="20"}
}
}
return flist
使用LUA文件的原因是方便在LUA中使用dofile进行读取。files列表中列出了所有包内的文件,core即为前面提到的大版本号。path是相对于res的路径,包含完整目录和文件后缀。
资源服务器上也有一份相同结构的资源列表。服务器和安装包中的结构如下:
res/flist:资源列表res/update.bin:update模块的打包文件res/framework.bin:quick - framework的打包文件res/game.bin:游戏逻辑的打包文件res/.....:其它游戏资源
三、更新流程
- 获取服务器版本列表:从服务器取得版本列表(
flist)。 - 检查update模块:检查
update的md5值,若有更新,则下载update.bin,重新载入,并退到main(退出前需清除某些引用),再次重新进入。 - 检查framework模块:检查
framework的md5值,若有更新,则下载framework.bin,并提示用户重新启动。 - 读取本地版本列表:读取本地安装目录的版本列表文件(
flist)。 - 对比大版本号:比对服务器版本列表和本地安装目录列表中的大版本号,若不一致,则提示用户去APPSTORE上下载。
- 处理upd目录:读取
upd目录的版本列表文件(flist),若flist文件不存在,或者flist中存放的core与安装目录列表中的不一致(表示用户安装了新版本),则清除整个upd目录,并将本地安装目录的flist内容写入upd目录。 - 对比版本号:对比服务器列表与本地列表中的
version,若相同,则认为数据无需更新;若不同,则与服务器的flist进行md5差异对比,得到需要更新的文件。 - 处理更新中断情况:遍历需要更新的文件列表,若
upd目录中存在该文件,则校验其MD5值,若与服务器的相同,则从待更新列表中移除。此步骤用于应对上一次更新过程中玩家中途退出的情况。 - 更新文件:逐个更新文件,每个文件更新完毕后,再次校验其MD5码,若校验失败,则重新下载该文件。
- 更新flist文件:待所有文件更新完毕,重写
upd文件中的flist。 - 进入游戏
四、资源加载路径设置
为了正确更新资源,可通过路径搜索来实现。代码如下:
-- add update path
CCFileUtils:sharedFileUtils():addSearchPath(device.writablePath.."upd/")
-- add res path for install
CCFileUtils:sharedFileUtils():addSearchPath("res/")
假设device.writablePath的目录是/data/data/com.ooxx.game1/,则第一个目录是/data/data/com.ooxx.game1/upd/,第二个目录是res/。
在ANDROID和IOS上,若路径以/开头,则认为是绝对路径,直接与文件名合并生成完整路径;若不是以/开头,在IOS上的工作原理和WINDOWS相同,在ANDROID上,会先检查是否以assets开头,若不是,则会强加上"assets/"并去APK里面搜索。因此,上述两个路径在任何地方都适用。
五、方案来源与效果
以上更新流程是综合了阳光七月、yezehui200、GcvqrNq等人的更新方案得出的,该流程基本解决了本文开头提出的问题。
六、实现过程中遇到的问题及解决方案
1. dofile在ANDROID上的问题
在执行安装目录中的flist时,由于dofile会识别绝对路径,在WINDOWS上正常,但在ANDROID上无法运行,即使硬编码dofile("assets/res/flist")也不行,原因是在ANDROID上,资源是从APK压缩包中读取的。
解决方案是使用CCFileUtils:sharedFileUtils:getFileData(“res/flist”),将得到的数据写入存储卡上,再使用dofile。由于upd目录下没有res文件夹,可确保获取的是安装包下的文件路径,从而解决了dofile在ANDROID上的问题。要获取安装包下的资源,需使用dofile(device.writablePath.."upd/flist")。添加多路径搜索后,使用路径时需格外小心。
2. crypto.md5file在ANDROID上的问题
在测试crypto.md5file时,发现在ANDROID上获取APK中的文件会失败,原因是C++实现里使用了fopen来打开文件,而在ANDROID上无法通过该方式读取APK中文件。好在该需求后续不再需要。
3. 单个文件进度条问题
由于没有使用AssetManager,目前尚未实现单个文件的进度条,后续可能会参考AssetManager的实现。
4. 目录创建问题
直接使用lfs.mkdir(device.writablePath.."upd/ui/shop/)创建目录不会成功,需要一级级向下创建。递归创建目录的方法如下:
- Windows下:
os.execute("mkdir ooxx\\ooxx\\ooxx\\ooxx") - iOS、Android、Mac、Linux下:
os.execute("mkdir -p ooxx/ooxx/ooxx/ooxx")
七、测试资源服务器的方法
测试资源服务器最简单的方法是网上下载一个nginx,解压后找到html目录,将资源放入该目录。点击nginx.exe启动,在浏览器输入127.0.0.1,若显示welcome nginx,则表示启动成功。输入127.0.0.1/1.png(假设html目录下有该图片),若能在浏览器中看到图片,则说明服务器配置正确。如果是手机测试,最好关闭内网的防火墙,否则可能连接不上。