在我们的游戏开发中,在线升级是必须要解决的需求,你不可能每出一个版本,就让用户去官网下载吧。 特别是资源的更新。
假设我们的游戏由两个东西组成 game.exe res.zip
见名知意,game.exe是游戏主程序,res.zip是资源包
那,我们如何面对更新呢。
首先想到的就是,当我们的game.exe启动后,我们会去下载PATCH服务器取得更新列表,比如game.exe是否有更新,res_patch.zip包大小等信息。
拿到后,我们就进行下载,下载后的文件可以保存到 patches/目录下 (名字自己定) 比如
patches/game_v001.exe
patches/res_v001.zip
有了这个以后,首先,我们要解决的是game.exe自更新问题。由于game.exe在运行过程中,是不能进行自修改的。所以,当我们发现有game_xxx.exe等字样的时候,我们需要唤起另一个进程,这个进程可以是SHELL,也可以是写的一个 _patch.exe什么的东西。 它的作用,就是将game_v001.exe覆盖原来的game.exe,并启动game.exe
大概过程如下
game.exe检查更新
game.exe下载文件
game.exe发现自己有新版本,启动_patch.exe进程,并结束自己
_patch.exe使用game_v001.exe覆盖game.exe,并删掉game_v001.exe
_patch.exe启动game.exe,并结束自己
这样game.exe就完成了。
由于整个过程比较绕,许多游戏都是做了一个launcher.exe来专门负责这个事情。
下面来说说资源的更新
资源的更新也较为简单
直接根据新版本,强制修改res.zip内容就可以了,这个过程由launcher来负责。
上面是一个端游粗略的更新过程……。
同样的方案,我们用到手游上如何呢? 这就要求我们对手游的局限要了解
手机中,安装目录是没有写权限的,不管是IOS还是ANDROID。 其它系统不知道
因此,我们无法做到应用程序代码的自更新,也无法直接修改安装包中的资源
动态库的方案也无法做到代码自更新,因为IOS审核不过。 我们就没有必要为一个游戏搞两套方案了。
因此,如果代码出现了更新,就只能让用户去APPSTORE上重新下载了。
但是,我们依然要面临资源的更新,逻辑的更新问题。 如果小改一个BUG,或者小修一个图片,都要让用户重新下载。 这流失率估计就能上100%了。
面对逻辑更新问题,大部分团队选择了脚本作为纯逻辑开发,普通的C++,JAVA,OC代码,仅是做一些层底支持。这样一来,所有的问题,都折射到了资源更新上。
刚刚说了,我们无法修改安装包中的数据。 那,我们自己新开一个拥有可写权限的目录不就可以了么。
在IOS和ANDROID下面,都可以取得writablePath,或者cachePath来使用。
随之而来的问题,就是资源加载。比如,在安装包中,有一个 res/logo.jpg 现在,我在更新目录下也有res/logo.jpg文件。
如何加载呢。最直接的方法,就是记录一下,哪个资源,在哪个路径下。但这个功能,如果做在上层的话,那每一次取资源,都要用 getRealPath等字样来包装。 如果做到底层去的话,又觉得这个功能确实不太适合放到底层。
像cocos2dx这个引擎,你就得手工修改资源加载处的代码了。
对于这样的方案,我们可以使用引擎中较为常见的一个功能,就是引擎的路径系统。
路径系统允许用户设置多个路径,当加载一个资源时,它会按对应路径逐个匹配,直到找到它为止。 因此,如果你加载 一个图片 1.jpg 如果多个目录下有,且这些目录都被添加到路径系统中了的话,那处于最前面的路径会优先匹配,后面的文件夹永远没有机会被访问到。除非之前的路径被删除……
基于这一特性,我们可以制定出手游上的资源更新方案
在引擎中,我们可以规划两个路径,一个是UPDATE的存放路径,一个是安装目录的路径
每次加载资源,优先搜索UPDATE
像cocos2dx,irrlicht等引擎,都有这样的路径搜索机制,只需添加好就可以了。
至于具体的资源更新,就是下载一个列表,然后根据列表进行文件下载和替换就可以了。
对于手机游戏的资源要不要ZIP,这个根据个人需求。
值得一说的是,目前手机存储卡均采用闪存或者SSD,读写速度比PC硬盘快多了。文件分离,做累加更新,是非常方便的。 当然,如果你坚持使用端游的逐版本更新机制,也是没有任何问题的。