Cocos2d-JS 热更新

前言
工作需要,在空闲时间看了下Cocos2d-JS的热更新。对其进行了一个简单的实现,这里总结分享一下。


Cocos2d-JS 热更新

Cocos2d-JS 热更新是啥?Cocos2d-JS终归还是一个游戏引擎,就以游戏的过程来理解吧。传统游戏需要更新人物动画、地图场景、游戏逻辑、背景音乐怎么办?新出一个APP放到应用商店等用户下载,或者好一点游戏内提示又升级并自行下载完整的新版本APP。

使用Cocos2d-JS的热更新,那就大不一样了。它可以做到进入游戏后下载需要更新的资源甚至是脚本本身,而且更新过程不需要退出游戏。只要用户联网,就能够保证使用到最新的资源。

这些场景就非常适合使用Hot Fix

  • 想在游戏中对春节开放新活动,不能保证应用商店能准时过审核上线

  • 发现一个严重的Bug,需要立即修复

  • 需要经常换游戏资源,提升新鲜感

  • 先放一个中规中矩的版本过市场审核,然后绕过审核自己直接推新内容,哈哈

对于游戏来说,这个特性是比较重量级的。不过因为JavaScript的语言特性能支持这一功能,所以Cocos2d-JS能用此特性,而Cocos2d-x无法使用。


特性

以下是官方提供的特性

  • 多线程并行下载支持

  • 两层进度统计信息:文件级以及字节级

  • Zip压缩文件支持

  • 断点续传

  • 详细的错误报告

  • 文件下载失败重试支持


Simple

1. manifest配置文件

热更新需要用到的配置文件有2种,都是以.manifest结尾。

一种是精简版,一种是完整版。精简版称为version.manifest,完整版称为project.manifest

version.manifest:

1
2
3
4
5
6
7
8
9
10
11
{
"remoteManifestUrl" "http://127.0.0.1:8080/JsUpdateServer/res/project.manifest" "remoteVersionUrl" "http://127.0.0.1:8080/JsUpdateServer/res/version.manifest" "version" "1.0.0" "groupVersions" :{
"1" "1.0.1" "2" "1.0.2"
},
"engineVersion" "3.3"
}

version.manifest是可选的,其中的所有字段也出现在project.manifest中,并且内容一样,如果没有就会从服务端下载完整版。但是如果完整版特别大,那么这个小版本的优势就很明显了。

project.manifest:

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
"3.3" "assets" :{
"update1" :{
"path" "src/app.zip" "md5" "41D8E948052B5B714B14F81612CF534D" "compressed" : true "group" "1"
"update2" :{
"res/HelloWorld.png" "A0FA3FA681D500575012D5E802F74D50" "1"
"update3" :{
"res/Bound.png" "E7D4218B02CD0C5BB35ADC55E133DBA2" "1"
"update4" :{
"src/resource.js" "BA47101EBB65FBFCFB61C4CC57A306CA" "2"
}
"searchPaths" :[
"res/"
]
所有字段具体含义,官方文档的定义还是比较详细,只是少了groupVersions这个新字段:

  • packageUrl : 远程资源的下载根路径。

  • remoteVersionUrl : 远程版本文件的路径,用来判断服务器端是否有新版本的资源。

  • remoteManifestUrl : 远程配置文件的路径,包含版本信息以及所有资源信息。

  • version : 配置文件对应的版本。

  • groupVersions : 是新增的功能字段,用于做增量更新很方便。

  • engineVersion : 配置文件对应的引擎版本。

  • assets : 所有资源信息。

    • key : 升级名称

    • path : 键代表资源的相对路径(相对于packageUrl)。

    • md5 : md5值代表资源文件的版本信息。

    • compressed : [可选项] 如果值为true,文件被下载后会自动被解压,目前仅支持zip压缩格式。

  • searchPaths : 需要添加到Cocos2d引擎中的搜索路径列表。

以我的配置为例,一个完整的更新流程是这样的:

先通过本地的version.manifest和服务端的version.manifest比较,如果本地version低于服务端,那么就会再去获取project.manifest。

如果version相同,那么会比较groupVersions。

如果本地没有下载过groupVersions中的任何更新,那么会依次下载升级包。

如果本地下载过1.0.1版本的升级包,那么就会跳过1.0.1下载属于1.0.2版本的升级内容。

如果下载失败,或者没有网络导致更新失败的,会继续使用未更新前的版本。并且下次启动会继续尝试更新。

2. 创建后台

用一种你喜欢的方式起一个后台服务。我朴实无华的用IDE(Eclipse for JavaEE)建立了一个空的Web工程,用Tomcat起了一个后台。

从刚才的配置文件可以看出,Web工程名为JsUpdateServer。

WebContent的根目录下新建一个index.html文件,随便在里边写些东西,用来验证我的后台已经起来。

Run起来之后,在浏览器里输入http://localhost:8080/JsUpdateServer/index.html看看是不是能够看到你刚才写的内容?

到这里你的后台已经OK了~

3. 创建Cocos2d-JS工程

新建一个Cocos2d-JS工程,可以用专用的IDE(cocosCode IDE),官网有下载,也有如何配置的教程,这里就不多说了。

res目录下,新建一个project.manifest文件。这个是初始版本信息,之后的更新会用到这个文件。内容如下:

"1.0" :{
:[
]
在src目录下,新建一个jsList.js文件,内容如下:

4
varjsList=[
"src/app.js"
]

这个文件里包括的是需要加载的js文件路径,将会在其他地方加载。

src目录下,新建一个assetsManagerScene.js文件,这里就是热更新的主要逻辑了。代码如下:

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
varfailCount=0;
varmaxFailCount=1; //最大错误重试次数
/**
*自动更新js和资源
*/
varAssetsManagerLoaderScene=cc.Scene.extend({
_am:null,
_progress:null,
_percent:0,
run:function(){
if (!cc.sys.isNative){
this .loadGame();
return ;
}
varlayer= new cc.Layer();
.addChild(layer);
._progress= cc.LabelTTF.create( "update0%" "Arial" ._progress.x=cc.winSize.width/2;
._progress.y=cc.winSize.height/2+50;
layer.addChild( ._progress);
varstoragePath=(jsb.fileUtils?jsb.fileUtils.getWritablePath(): "./" );
cc. log ( "storagePathis" +storagePath);
._am= jsb.AssetsManager( "res/project.manifest" ._am.retain();
(! ._am.getLocalManifest().isLoaded())
//if(true)
{
"Failtoupdateassets,stepskipped." );
.loadGame();
}
else
{
varthat= ;
cc.EventListenerAssetsManager
varlistener= jsb.EventListenerAssetsManager( ._am,function(event){
switch (event.getEventCode()){
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:
"Nolocalmanifestfilefound,skipassetsupdate." );
that.loadGame();
break ;
jsb.EventAssetsManager.UPDATE_PROGRESSION:
that._percent=event.getPercent();
(that._percent+ "%" );
varmsg=event.getMessage();
(msg){
(msg);
}
;
jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:
jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:
"Failtodownloadmanifestfile,updateskipped." );
that.loadGame();
;
jsb.EventAssetsManager.ALREADY_UP_TO_DATE:
"ALREADY_UP_TO_DATE." );
that.loadGame();
;
jsb.EventAssetsManager.UPDATE_FINISHED:
"Updatefinished." );
that.loadGame();
;
jsb.EventAssetsManager.UPDATE_FAILED:
"Updatefailed." +event.getMessage());
failCount++;
(failCount<maxFailCount)
{
that._am.downloadFailedAssets();
}
else
{
"Reachmaximumfailcount,exitupdateprocess" );
failCount=0;
that.loadGame();
}
;
jsb.EventAssetsManager.ERROR_UPDATING:
"Assetupdateerror:" +event.getAssetId()+ "," +event.getMessage());
that.loadGame();
;
jsb.EventAssetsManager.ERROR_DECOMPRESS:
(event.getMessage());
that.loadGame();
;
default :
;
}
});
cc.eventManager.addListener(listener,1);
._am.update();
cc.director.runScene( );
}
.schedule( .updateProgress,0.5);
loadGame:function(){
//jsList是jsList.js的变量,记录全部js。
cc.loader.loadJs([ "src/jsList.js" ],function(){
cc.loader.loadJs(jsList,function(){
HelloWorldScene());
});
});
updateProgress:function(dt){
._progress.string= "update" + ._percent+ ;
onExit:function(){
"AssetsManager::onExit" );
._am.release();
._super();
}
});

热更新主要是通过引擎提供的AssetsManager来实现的。

AssetsManagerLoaderScene里,用到了res/project.manifest,是用来对版本对比的。

下载完成后的资源会被解压,然后放在jsb.fileUtils.getWritablePath()的路径下,加到引擎的搜索范围中,并且他们的优先级是高于APP原本的资源路径的。所以相同的资源名称,引擎会优先使用更新路径下的文件,就达到更新的目的。

下载成功后会执行loadGame方法,里边会加载src/jsList.js的所有资源。也就是说通过AssetsManagerLoaderScene来确保热更新完成后,再加载所有资源。

由于资源和脚本的加载顺序发生了改变,所以还要修改根目录下的main.js和“project.json”。

main.js:

9
cc.game.onStart=function(){
cc.view.adjustViewPort( );
cc.view.setDesignResolutionSize(800,450,cc.ResolutionPolicy.SHOW_ALL);
cc.view.resizeWithBrowserSize( );
varscene= AssetsManagerLoaderScene();
scene.run();
};
cc.game.run();

将启动场景改为我的热更新场景AssetsManagerLoaderScene。

project.json:

16
"project_type" "javascript" "debugMode" :1,monospace!important; font-size:1em!important; min-height:inherit!important; color:blue!important">"showFPS" "frameRate" :60,monospace!important; font-size:1em!important; min-height:inherit!important; color:blue!important">"id" "gameCanvas" "renderMode" :0,monospace!important; font-size:1em!important; min-height:inherit!important; color:blue!important">"engineDir" "frameworks/cocos2d-html5" "modules" "cocos2d" "extensions"
"jsList" :[
"src/assetsManagerScene.js"
]
将jsList的值改为src/assetsManagerScene.js,只要加载这个js,其他js会在AssetsManagerLoaderScene中被加载。

到这里你可以跑起来看下,虽然获取不到升级文件,但是可以以最原始的版本跑起来。

4. 在后台配置升级文件

现在到后台工程的WebContent目录下添加升级文件。

从我的manifest配置文件你可以看到,我又建立了一个res文件夹,在其中分别建立src和res分别对应Cocos2d-JS工程中的资源、脚本文件夹。

随意修改一下app.js,将其作为更新内容使用。总结了几个要注意的地方。

升级文件的路径,一定要和配置文件中的path内容一致。

升级文件是.zip,记得compressed改为true。

添加新的资源文件要记得同步更新resource.js

新增js文件也记得同步更新jsList.js

5. 回到Cocos2d-JS工程

核对一下project.manifest文件中的地址是不是和后台一致,内容是否正确。

没问题的话就可以跑起来了,会发现你的升级内容被下载下来并且更新了。


参考

本文工程后台&Cocos2d-JS的简陋源码戳这里,Cocos2d-JS工程中的文件替换你的文件,通用的引擎工程太大没有上传。

其他可以使用到的教程

资源管理器ASSETS MANAGER

Cocos2d-JS热更新

来源网址:http://karelgt.com/Cocos2dJS 热更新/

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


    本文实践自 RayWenderlich、Ali Hafizji 的文章《How To Create Dynamic Textures with CCRenderTexture in Cocos2D 2.X》,文中使用Cocos2D,我在这里使用Cocos2D-x 2.1.4进行学习和移植。在这篇文章,将会学习到如何创建实时纹理、如何用Gimp创建无缝拼接纹
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@163.com微信公众号:HopToad 欢迎转载,转载标注出处:http://blog.csdn.netotbaron/article/details/424343991.  软件准备 下载地址:http://cn.cocos2d-x.org/download 2.  简介2.1         引用C
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从Cocos2D-x官网上下载,进入网页http://www.cocos2d-x.org/download,点击Cocos2d-x以下的Download  v3.0,保存到自定义的文件夹2:从python官网上下载。进入网页https://www.python.org/downloads/,我当前下载的是3.4.0(当前最新
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发引擎,易学易用,支持多种智能移动平台。官网地址:http://cocos2d-x.org/当前版本:2.0    有很多的学习资料,在这里我只做为自己的笔记记录下来,错误之处还请指出。在VisualStudio2008平台的编译:1.下载当前稳
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《最强大脑》娱乐节目。将2048改造成一款挑战玩家对数字记忆的小游戏。邮箱:appdevzw@163.com微信公众号:HopToadAPK下载地址:http://download.csdn.net/detailotbaron/8446223源码下载地址:http://download.csdn.net/
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试以QtCreatorIDE来进行CMake构建。Cocos2d-x3.X地址:https://github.com/cocos2d/cocos2d-x1.打开QtCreator,菜单栏→"打开文件或项目...",打开cocos2d-x目录下的CMakeLists.txt文件;2.弹出CMake向导,如下图所示:设置
 下载地址:链接:https://pan.baidu.com/s/1IkQsMU6NoERAAQLcCUMcXQ提取码:p1pb下载完成后,解压进入build目录使用vs2013打开工程设置平台工具集,打开设置界面设置: 点击开始编译等待编译结束编译成功在build文件下会出现一个新文件夹Debug.win32,里面就是编译
分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!http://www.captainbed.net前言上次用象棋演示了cocos2dx的基本用法,但是对cocos2dx并没有作深入的讨论,这次以超级马里奥的源代码为线索,我们一起来学习超级马里奥的实
1. 圆形音量button事实上作者的本意应该是叫做“电位计button”。可是我觉得它和我们的圆形音量button非常像,所以就这么叫它吧~先看效果:好了,不多解释,本篇到此为止。(旁白: 噗。就这样结束了?)啊才怪~我们来看看代码:[cpp] viewplaincopyprint?CCContro
原文链接:http://www.cnblogs.com/physwf/archive/2013/04/26/3043912.html为了进一步深入学习贯彻Cocos2d,我们将自己写一个场景类,但我们不会走的太远,凡是都要循序渐进,哪怕只前进一点点,那也至少是前进了,总比贪多嚼不烂一头雾水的好。在上一节中我们建
2019独角兽企业重金招聘Python工程师标准>>>cocos2d2.0之后加入了一种九宫格的实现,主要作用是用来拉伸图片,这样的好处在于保留图片四个角不变形的同时,对图片中间部分进行拉伸,来满足一些控件的自适应(PS: 比如包括按钮,对话框,最直观的形象就是ios里的短信气泡了),这就要求图
原文链接:http://www.cnblogs.com/linji/p/3599478.html1.环境和工具准备Win7VS2010/2012,至于2008v2版本之后似乎就不支持了。 2.安装pythonv.2.0版本之前是用vs模板创建工程的,到vs2.2之后就改用python创建了。到python官网下载版本2.7.5的,然后
环境:ubuntu14.04adt-bundle-linux-x86_64android-ndk-r9d-linux-x86_64cocos2d-x-3.0正式版apache-ant1.9.3python2.7(ubuntu自带)加入环境变量exportANDROID_SDK_ROOT=/home/yangming/adt-bundle-linux/sdkexportPATH=${PATH}:/$ANDROID_SDK_ROOTools/export
1开发背景游戏程序设计涉及了学科中的各个方面,鉴于目的在于学习与进步,本游戏《FlappyBird》采用了两个不同的开发方式来开发本款游戏,一类直接采用win32底层API来实现,另一类采用当前火热的cocos2d-x游戏引擎来开发本游戏。2需求分析2.1数据分析本项目要开发的是一款游
原文链接:http://www.cnblogs.com/linji/p/3599912.html//纯色色块控件(锚点默认左下角)CCLayerColor*ccc=CCLayerColor::create(ccc4(255,0,0,128),200,100);//渐变色块控件CCLayerGradient*ccc=CCLayerGradient::create(ccc4(255,0,0,
原文链接:http://www.cnblogs.com/linji/p/3599488.html//载入一张图片CCSprite*leftDoor=CCSprite::create("loading/door.png");leftDoor->setAnchorPoint(ccp(1,0.5));//设置锚点为右边中心点leftDoor->setPosition(ccp(240,160));/
为了答谢广大学员对智捷课堂以及关老师的支持,现购买51CTO学院关老师的Cocos2d-x课程之一可以送智捷课堂编写图书一本(专题可以送3本)。一、Cocos2d-x课程列表:1、Cocos2d-x入门与提高视频教程__Part22、Cocos2d-x数据持久化与网络通信__Part33、Cocos2d-x架构设计与性能优化内存优
Spawn让多个action同时执行。Spawn有多种不同的create方法,最终都调用了createWithTwoActions(FiniteTimeAction*action1,FiniteTimeAction*action2)方法。createWithTwoActions调用initWithTwoActions方法:对两个action变量初始化:_one=action1;_two=action2;如果两个a
需要环境:php,luajit.昨天在cygwin上安装php和luajit环境,这真特么是一个坑。建议不要用虚拟环境安装打包环境,否则可能会出现各种莫名问题。折腾了一下午,最终将环境转向linux。其中,luajit的安装脚本已经在quick-cocos2d-x-develop/bin/中,直接luajit_install.sh即可。我的lin
v3.0相对v2.2来说,最引人注意的。应该是对触摸层级的优化。和lambda回调函数的引入(嗯嗯,不枉我改了那么多类名。话说,每次cocos2dx大更新。总要改掉一堆类名函数名)。这些特性应该有不少人研究了,所以今天说点跟图片有关的东西。v3.0在载入图片方面也有了非常大改变,仅仅只是