轉載至: http://blog.csdn.net/pt_xxj/article/details/68927705javascript
爲何還要再寫一篇關於cocos2d js熱更新的筆記,最單純的想法就是記錄心得,另外也是由於添加了一個記錄熱更新資源大小的小功能,故而想分享一下。java
在cocos2d js引擎中的js是做爲一種特殊的資源文件使用(腳本文件),那麼遊戲運行過程當中經過定製的資源管理器從服務器獲取新的js文件並從新加載運行,那麼也就實現了看似比較玄妙的熱更新功能。固然此資源管理器須要具有資源對比、資源下載、資源處理、資源覆蓋及資源加載等等的一系列功能,幸運的是cocos已經實現了這些功能,咱們須要作的就是學會配置使用而已。json
此熱更新基於cocos2d-js 3.6.1測試使用。設計模式
————————————————樸實無華分割線,以上內容不重要————————————————數組
cocos2d js的熱更新功能主要由jsb.AssetsManager實現,綁定了引擎底層的C++代碼AssetsManager類,具體的邏輯和實現均可以查看此類。具體的熱更新的是經過一個預先配置的project.manifest以及服務器端的project.manifest和version.manifest配合使用來實現的。服務器
初始project.manifest:函數
{
"packageUrl": "http://192.168.0.73:8080/projectName/std/",
"remoteManifestUrl": "http://192.168.0.73:8080/projectName/std/project.manifest",
"remoteVersionUrl": "http://192.168.0.73:8080/projectName/std/version.manifest",
"version": "1.0.0",
"groupVersions" :
{ },
"groupSizes" :
{ },
"engineVersion": "3.6.1",
"assets" :
{ },
"searchPaths":
[ ] }
具備兩個版本增量更新的服務器project.manifest:post
{
"packageUrl": "http://192.168.0.73:8080/projectName/std/",
"remoteManifestUrl": "http://192.168.0.73:8080/projectName/std/project.manifest",
"remoteVersionUrl": "http://192.168.0.73:8080/projectName/std/version.manifest",
"version": "1.1.2",
"groupVersions" :
{ "1":"1.1.1", "2":"1.1.2" },
"groupSizes" :
{ "1":115.0, "2":115.0 },
"engineVersion": "3.6.1",
"assets" :
{ "update1": { "path":"update1.zip", "md5":"", "compressed" : true, "group":"1" }, "update2": { "path":"update2.zip", "md5":"", "compressed" : true, "group":"2" } },
"searchPaths":
[ "update1/", "update2/" ] }
具備兩個版本增量更新的服務器version.manifest:測試
{
"packageUrl": "http://192.168.0.73:8080/projectName/std/",
"remoteManifestUrl": "http://192.168.0.73:8080/projectName/std/project.manifest",
"remoteVersionUrl": "http://192.168.0.73:8080/projectName/std/version.manifest",
"version": "1.1.2",
"groupVersions" :
{ "1":"1.1.1", "2":"1.1.2" },
"groupSizes" :
{ "1":115.0, "2":115.0 } }
此熱更新配置文件我添加了groupSizes字段,用於展現更新資源文件大小,方便用戶玩家自主選擇更新時機。另外配置的時候按照渠道劃分的,這個是std是標準渠道的熱更新文件配置。至於其餘字段網路上已經有太多的講解,就再也不重複。ui
資源文件配置完畢,那麼就是具體的使用了,我使用了一個js的靜態類來實現熱更新的檢測以及更新過程,我看其餘人的實現通常都是直接強制更新,我的感受不太友好,因此個人熱更新實現是分步進行的。
hotfix-manager.js
/** * 熱更新管理器 */
var HotFixManager = HotFixManager || {
// 更新資源管理器
_mAssetsMgr:null,
_mTryCount:0,
// 更新基本配置
_mManiFest:"",
_mWritePath:"",
_mTryTimes:1,
// 更新過程進度回調函數
_mUpdateCall:null,
_mUpdatetarget:null,
// 更新完成回調
_mFinishCall:null,
_mFinishtarget:null,
// 更新已找到標識
_mHadFind:false,
/** * 熱更新系統初始化 * @param call 更新完成回調函數 * @param target 回調函數綁定節點 */
init:function(call,target)
{
this._mFinishCall = call;
this._mFinishtarget = target;
// 這一部分的配置使用也能夠經過傳遞參數進行實現
this._mManiFest = "res/static/project.manifest";
this._mWritePath = jsb.fileUtils?jsb.fileUtils.getWritablePath()+"hotFix/":"./hotFix/";
this._mTryTimes = 1;
this._mAssetsMgr = new jsb.AssetsManager(this._mManiFest, this._mWritePath);
this._mAssetsMgr.retain();
cc.eventManager.addListener(new jsb.EventListenerAssetsManager(this._mAssetsMgr,this._eventListener.bind(this)),1);
},
_eventListener:function(event)
{
cc.log("assetsMgr:state = %s;event:id = %s,code = %s,message = %s",
this._mAssetsMgr.getState(),event.getAssetId(),
event.getEventCode(),JSON.stringify(event.getMessage()));
switch(event.getEventCode())
{
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST: // 0
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST: // 1
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST: // 2
case jsb.EventAssetsManager.ERROR_UPDATING: // 7
case jsb.EventAssetsManager.ERROR_DECOMPRESS: // 10
// 此處能夠另加一個this.onError(event.getEventCode())操做,不過我的感受不必,直接直接作失敗結束處理
this.onFinish(false);
break;
case jsb.EventAssetsManager.UPDATE_FINISHED: // 8
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE: // 4
this.onFinish(true);
break;
// 資源下載完成,進行遊戲內資源更新(包括資源解壓等)
case jsb.EventAssetsManager.ASSET_UPDATED: // 6
break;
// 此處checkUpdate()和 update()都會觸發新版本發現操做(區別在於前者到此處任務已結束,後者會繼續後續資源下載操做)
case jsb.EventAssetsManager.NEW_VERSION_FOUND: // 3
this._onFind();
break;
case jsb.EventAssetsManager.UPDATE_PROGRESSION: // 5
// 狀態值8表明熱更新資源下載中,添加此判斷是篩選更新下載進度
if(this._mAssetsMgr.getState() == 8)
{
cc.log(event.getPercent());
this._onUpdate(event.getPercent());
}
break;
case jsb.EventAssetsManager.UPDATE_FAILED: // 9
this._mTryCount++;
if (this._mTryCount < this._mTryTimes)
{
this._mAssetsMgr.downloadFailedAssets();
}
else
{
this._mTryCount = 0;
this.onFinish(false);
}
break;
default:break;
}
},
/** * 檢測是否有熱更新資源 */
checkUpdate:function()
{
this._mAssetsMgr.checkUpdate();
},
_onFind:function()
{
// 系統在進行正式更新時,在下載project.manifest後仍舊會再次回調此處回調
if(this._mHadFind)
{
return;
}
this._mHadFind = true;
// 計算熱更新資源大小,需在cocos提供的文件配置基礎上自主增長groupSizes字段
var updateSize = 0.0;
try
{
var vSize = 0.0;
var pSize = 0.0;
var versionString = jsb.fileUtils.getStringFromFile(this._mWritePath+"version.manifest");
var projectString = jsb.fileUtils.getStringFromFile(this._mWritePath+"project.manifest");
if(versionString)
{
var vJson = JSON.parse(versionString);
for(var it in vJson.groupSizes)
{
vSize += parseFloat(vJson.groupSizes[it]);
}
}
if(projectString)
{
var pJson = JSON.parse(projectString);
for(var it in pJson.groupSizes)
{
pSize += parseFloat(pJson.groupSizes[it]);
}
}
updateSize = vSize - pSize;
}
catch (e)
{
cc.log(e);
}
var layer = new HotFixFindLayer(updateSize);
cc.director.getRunningScene().addChild(layer);
},
/** * 執行熱更新 */
doUpdate:function()
{
this._mAssetsMgr.update();
},
/** * 設置熱更新下載進度回調 * @param call * @param target */
setUpdateCall:function(call,target)
{
this._mUpdateCall = call;
this._mUpdatetarget = target;
},
_onUpdate:function(percent)
{
this._mUpdateCall&&this._mFinishtarget&&this._mFinishtarget.runAction(cc.callFunc(this._mUpdateCall, this._mFinishtarget, percent));
},
/** * 熱更新結束 * @param success bool更新是否成功 */
onFinish:function(success)
{
this._mFinishCall&&this._mFinishtarget&&this._mFinishtarget.runAction(cc.callFunc(this._mFinishCall, this._mFinishtarget, success));
this._mAssetsMgr.release();
this._mHadFind = false;
}
};
/** * 熱更新找到選擇對話框,主要考慮到資源比較大,又不是強制更新的狀況 */
var HotFixFindLayer = cc.Layer.extend({
ctor:function(updateSize)
{
this._super();
var popBoxBg = new cc.LayerColor(cc.color(0, 0, 0, 200),this.width*0.75, this.height*0.15);
popBoxBg.setPosition(this.width*0.5-popBoxBg.width/2, this.height*0.5-popBoxBg.height/2);
this.addChild(popBoxBg);
var HotUpdateFindDesc = new ccui.Text("從遊戲服務器檢測到有"+updateSize+"M資源更新,是夠當即進行更新操做?", "Arial", 28);
HotUpdateFindDesc.setContentSize(popBoxBg.width*0.85, popBoxBg.height*0.7);
HotUpdateFindDesc.setPosition(popBoxBg.width*0.5, popBoxBg.height*0.5);
HotUpdateFindDesc.ignoreContentAdaptWithSize(false);
popBoxBg.addChild(HotUpdateFindDesc);
var sureItem = new cc.MenuItemLabel(ccui.Text("當即更新", "Arial", 28),function(){
HotFixManager.doUpdate();
popBoxBg.removeAllChildren(true);
var percentDesc = new ccui.Text("更新進度:0%", "Arial", 32);
percentDesc.setAnchorPoint(0,0.5);
percentDesc.setPosition(popBoxBg.width*0.25, popBoxBg.height*0.5);
popBoxBg.addChild(percentDesc);
HotFixManager.setUpdateCall(function(target,data){
percentDesc.setString(cc.formatStr("更新進度:%s%",parseInt(data)));
if(parseInt(data) == 100)
{
this.removeFromParent(true);
HotFixManager.setUpdateCall();
}
},this);
},this);
var sureMenu = new cc.Menu(sureItem);
sureMenu.setPosition(popBoxBg.width*0.25, popBoxBg.height*0.2)
popBoxBg.addChild(sureMenu);
var cancelItem = new cc.MenuItemLabel(ccui.Text("下次更新", "Arial", 28),function(){
this.removeFromParent(true);
HotFixManager.onFinish(false);
},this);
var cancelMenu = new cc.Menu(cancelItem);
cancelMenu.setPosition(popBoxBg.width*0.75, popBoxBg.height*0.2)
popBoxBg.addChild(cancelMenu);
}
});
其實這個更新操做的實現方式不是特別符合設計模式,在HotFixManager的_onFind函數尾部
var layer = new HotFixFindLayer(updateSize);
cc.director.getRunningScene().addChild(layer);
是不應直接實現界面顯示的,應該經過使用時本身定製一個彈窗界面而後再根據玩家選擇調用HotFixManager對應的函數進行操做,不過個人初始想法就是讓使用盡可能方便,因此我儘可能去掉了資源的使用,當成了一個系統內的控件進行了儘可能的封裝操做。
新建一個scene使用便可hotfix-scene.js:
var HotFixScene = cc.Scene.extend({
ctor:function() {
this._super();
var layer = new cc.Layer();
this.addChild(layer);
var loadPoster = new cc.Sprite("res/static/poster.png");
loadPoster.setPosition(layer.width*0.5,layer.height*0.5)
loadPoster.setScale(layer.height/loadPoster.height);
layer.addChild(loadPoster);
// 熱更新系統使用
HotFixManager.init(this._updateFinish,this);
HotFixManager.checkUpdate();
},
_updateFinish:function() {
var delay_func = function() {
// js文件列表文件,此文件在熱更新過程當中應該保持路徑不變
// 由於此處是寫死的,不太好改變,除非你本身在熱更新配置一個字段,用於保存此路徑
var jsFile = "src/dynamic/js-list.js";
// 加載js文件列表
cc.loader.loadJs(jsFile, function(){
// 加載js文件列表中的js文件
cc.loader.loadJs(jsList, function(){
// 跳轉到正式遊戲scene
cc.director.runScene(new GameScene());
});
});
}
// 此操做是爲了避開當前幀跳轉,否則界面會有卡頓感受
this.scheduleOnce(delay_func, 0.05);
}
});
熱更新系統的使用是特別簡單的,只須要在main.js的cc.game.onStart函數執行
cc.director.runScene(new HotFixScene());
就能夠了。固然這兩個文件你要配置在project.json中。
其實我真正想作到的是做爲一個插件使用,對於已經完成的項目,要添加此熱更新插件特別簡單,只須要作幾件事情就能夠了:
一、將原有的project.json中的js文件列表寫進」src/dynamic/js-list.js」文件的var jsList=[]數組中(jsList名字對應於HotFixScene中的jsList)。
二、將上述兩個文件加入遊戲,並將其路徑配置到project.json。
三、配置本身的熱更新文件配置(包括搭建本身的服務器),修改HotFixManager.init()中的讀寫目錄(若跟個人目錄一致則不用改寫)。
四、修改熱更新結束後的scene跳轉爲已實現的文件跳轉。
// 跳轉到正式遊戲scene
cc.director.runScene(new GameScene());
五、測試運行。
————————————————樸實無華分割線,如下內容不重要————————————————
下面是兩張實際運行圖:(背景圖借用皇室戰爭的海報圖)
選擇界面:
資源更新中界面:
結束
爲何還要再寫一篇關於cocos2d js熱更新的筆記,最單純的想法就是記錄心得,另外也是由於添加了一個記錄熱更新資源大小的小功能,故而想分享一下。
在cocos2d js引擎中的js是做爲一種特殊的資源文件使用(腳本文件),那麼遊戲運行過程當中經過定製的資源管理器從服務器獲取新的js文件並從新加載運行,那麼也就實現了看似比較玄妙的熱更新功能。固然此資源管理器須要具有資源對比、資源下載、資源處理、資源覆蓋及資源加載等等的一系列功能,幸運的是cocos已經實現了這些功能,咱們須要作的就是學會配置使用而已。
此熱更新基於cocos2d-js 3.6.1測試使用。
————————————————樸實無華分割線,以上內容不重要————————————————
cocos2d js的熱更新功能主要由jsb.AssetsManager實現,綁定了引擎底層的C++代碼AssetsManager類,具體的邏輯和實現均可以查看此類。具體的熱更新的是經過一個預先配置的project.manifest以及服務器端的project.manifest和version.manifest配合使用來實現的。
初始project.manifest:
{
"packageUrl": "http://192.168.0.73:8080/projectName/std/",
"remoteManifestUrl": "http://192.168.0.73:8080/projectName/std/project.manifest",
"remoteVersionUrl": "http://192.168.0.73:8080/projectName/std/version.manifest",
"version": "1.0.0",
"groupVersions" :
{ },
"groupSizes" :
{ },
"engineVersion": "3.6.1",
"assets" :
{ },
"searchPaths":
[ ] }
具備兩個版本增量更新的服務器project.manifest:
{
"packageUrl": "http://192.168.0.73:8080/projectName/std/",
"remoteManifestUrl": "http://192.168.0.73:8080/projectName/std/project.manifest",
"remoteVersionUrl": "http://192.168.0.73:8080/projectName/std/version.manifest",
"version": "1.1.2",
"groupVersions" :
{ "1":"1.1.1", "2":"1.1.2" },
"groupSizes" :
{ "1":115.0, "2":115.0 },
"engineVersion": "3.6.1",
"assets" :
{ "update1": { "path":"update1.zip", "md5":"", "compressed" : true, "group":"1" }, "update2": { "path":"update2.zip", "md5":"", "compressed" : true, "group":"2" } },
"searchPaths":
[ "update1/", "update2/" ] }
具備兩個版本增量更新的服務器version.manifest:
{
"packageUrl": "http://192.168.0.73:8080/projectName/std/",
"remoteManifestUrl": "http://192.168.0.73:8080/projectName/std/project.manifest",
"remoteVersionUrl": "http://192.168.0.73:8080/projectName/std/version.manifest",
"version": "1.1.2",
"groupVersions" :
{ "1":"1.1.1", "2":"1.1.2" },
"groupSizes" :
{ "1":115.0, "2":115.0 } }
此熱更新配置文件我添加了groupSizes字段,用於展現更新資源文件大小,方便用戶玩家自主選擇更新時機。另外配置的時候按照渠道劃分的,這個是std是標準渠道的熱更新文件配置。至於其餘字段網路上已經有太多的講解,就再也不重複。
資源文件配置完畢,那麼就是具體的使用了,我使用了一個js的靜態類來實現熱更新的檢測以及更新過程,我看其餘人的實現通常都是直接強制更新,我的感受不太友好,因此個人熱更新實現是分步進行的。
hotfix-manager.js
/** * 熱更新管理器 */
var HotFixManager = HotFixManager || {
// 更新資源管理器
_mAssetsMgr:null,
_mTryCount:0,
// 更新基本配置
_mManiFest:"",
_mWritePath:"",
_mTryTimes:1,
// 更新過程進度回調函數
_mUpdateCall:null,
_mUpdatetarget:null,
// 更新完成回調
_mFinishCall:null,
_mFinishtarget:null,
// 更新已找到標識
_mHadFind:false,
/** * 熱更新系統初始化 * @param call 更新完成回調函數 * @param target 回調函數綁定節點 */
init:function(call,target)
{
this._mFinishCall = call;
this._mFinishtarget = target;
// 這一部分的配置使用也能夠經過傳遞參數進行實現
this._mManiFest = "res/static/project.manifest";
this._mWritePath = jsb.fileUtils?jsb.fileUtils.getWritablePath()+"hotFix/":"./hotFix/";
this._mTryTimes = 1;
this._mAssetsMgr = new jsb.AssetsManager(this._mManiFest, this._mWritePath);
this._mAssetsMgr.retain();
cc.eventManager.addListener(new jsb.EventListenerAssetsManager(this._mAssetsMgr,this._eventListener.bind(this)),1);
},
_eventListener:function(event)
{
cc.log("assetsMgr:state = %s;event:id = %s,code = %s,message = %s",
this._mAssetsMgr.getState(),event.getAssetId(),
event.getEventCode(),JSON.stringify(event.getMessage()));
switch(event.getEventCode())
{
case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST: // 0
case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST: // 1
case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST: // 2
case jsb.EventAssetsManager.ERROR_UPDATING: // 7
case jsb.EventAssetsManager.ERROR_DECOMPRESS: // 10
// 此處能夠另加一個this.onError(event.getEventCode())操做,不過我的感受不必,直接直接作失敗結束處理
this.onFinish(false);
break;
case jsb.EventAssetsManager.UPDATE_FINISHED: // 8
case jsb.EventAssetsManager.ALREADY_UP_TO_DATE: // 4
this.onFinish(true);
break;
// 資源下載完成,進行遊戲內資源更新(包括資源解壓等)
case jsb.EventAssetsManager.ASSET_UPDATED: // 6
break;
// 此處checkUpdate()和 update()都會觸發新版本發現操做(區別在於前者到此處任務已結束,後者會繼續後續資源下載操做)
case jsb.EventAssetsManager.NEW_VERSION_FOUND: // 3
this._onFind();
break;
case jsb.EventAssetsManager.UPDATE_PROGRESSION: // 5
// 狀態值8表明熱更新資源下載中,添加此判斷是篩選更新下載進度
if(this._mAssetsMgr.getState() == 8)
{
cc.log(event.getPercent());
this._onUpdate(event.getPercent());
}
break;
case jsb.EventAssetsManager.UPDATE_FAILED: // 9
this._mTryCount++;
if (this._mTryCount < this._mTryTimes)
{
this._mAssetsMgr.downloadFailedAssets();
}
else
{
this._mTryCount = 0;
this.onFinish(false);
}
break;
default:break;
}
},
/** * 檢測是否有熱更新資源 */
checkUpdate:function()
{
this._mAssetsMgr.checkUpdate();
},
_onFind:function()
{
// 系統在進行正式更新時,在下載project.manifest後仍舊會再次回調此處回調
if(this._mHadFind)
{
return;
}
this._mHadFind = true;
// 計算熱更新資源大小,需在cocos提供的文件配置基礎上自主增長groupSizes字段
var updateSize = 0.0;
try
{
var vSize = 0.0;
var pSize = 0.0;
var versionString = jsb.fileUtils.getStringFromFile(this._mWritePath+"version.manifest");
var projectString = jsb.fileUtils.getStringFromFile(this._mWritePath+"project.manifest");
if(versionString)
{
var vJson = JSON.parse(versionString);
for(var it in vJson.groupSizes)
{
vSize += parseFloat(vJson.groupSizes[it]);
}
}
if(projectString)
{
var pJson = JSON.parse(projectString);
for(var it in pJson.groupSizes)
{
pSize += parseFloat(pJson.groupSizes[it]);
}
}
updateSize = vSize - pSize;
}
catch (e)
{
cc.log(e);
}
var layer = new HotFixFindLayer(updateSize);
cc.director.getRunningScene().addChild(layer);
},
/** * 執行熱更新 */
doUpdate:function()
{
this._mAssetsMgr.update();
},
/** * 設置熱更新下載進度回調 * @param call * @param target */
setUpdateCall:function(call,target)
{
this._mUpdateCall = call;
this._mUpdatetarget = target;
},
_onUpdate:function(percent)
{
this._mUpdateCall&&this._mFinishtarget&&this._mFinishtarget.runAction(cc.callFunc(this._mUpdateCall, this._mFinishtarget, percent));
},
/** * 熱更新結束 * @param success bool更新是否成功 */
onFinish:function(success)
{
this._mFinishCall&&this._mFinishtarget&&this._mFinishtarget.runAction(cc.callFunc(this._mFinishCall, this._mFinishtarget, success));
this._mAssetsMgr.release();
this._mHadFind = false;
}
};
/** * 熱更新找到選擇對話框,主要考慮到資源比較大,又不是強制更新的狀況 */
var HotFixFindLayer = cc.Layer.extend({
ctor:function(updateSize)
{
this._super();
var popBoxBg = new cc.LayerColor(cc.color(0, 0, 0, 200),this.width*0.75, this.height*0.15);
popBoxBg.setPosition(this.width*0.5-popBoxBg.width/2, this.height*0.5-popBoxBg.height/2);
this.addChild(popBoxBg);
var HotUpdateFindDesc = new ccui.Text("從遊戲服務器檢測到有"+updateSize+"M資源更新,是夠當即進行更新操做?", "Arial", 28);
HotUpdateFindDesc.setContentSize(popBoxBg.width*0.85, popBoxBg.height*0.7);
HotUpdateFindDesc.setPosition(popBoxBg.width*0.5, popBoxBg.height*0.5);
HotUpdateFindDesc.ignoreContentAdaptWithSize(false);
popBoxBg.addChild(HotUpdateFindDesc);
var sureItem = new cc.MenuItemLabel(ccui.Text("當即更新", "Arial", 28),function(){
HotFixManager.doUpdate();
popBoxBg.removeAllChildren(true);
var percentDesc = new ccui.Text("更新進度:0%", "Arial", 32);
percentDesc.setAnchorPoint(0,0.5);
percentDesc.setPosition(popBoxBg.width*0.25, popBoxBg.height*0.5);
popBoxBg.addChild(percentDesc);
HotFixManager.setUpdateCall(function(target,data){
percentDesc.setString(cc.formatStr("更新進度:%s%",parseInt(data)));
if(parseInt(data) == 100)
{
this.removeFromParent(true);
HotFixManager.setUpdateCall();
}
},this);
},this);
var sureMenu = new cc.Menu(sureItem);
sureMenu.setPosition(popBoxBg.width*0.25, popBoxBg.height*0.2)
popBoxBg.addChild(sureMenu);
var cancelItem = new cc.MenuItemLabel(ccui.Text("下次更新", "Arial", 28),function(){
this.removeFromParent(true);
HotFixManager.onFinish(false);
},this);
var cancelMenu = new cc.Menu(cancelItem);
cancelMenu.setPosition(popBoxBg.width*0.75, popBoxBg.height*0.2)
popBoxBg.addChild(cancelMenu);
}
});
其實這個更新操做的實現方式不是特別符合設計模式,在HotFixManager的_onFind函數尾部
var layer = new HotFixFindLayer(updateSize);
cc.director.getRunningScene().addChild(layer);
是不應直接實現界面顯示的,應該經過使用時本身定製一個彈窗界面而後再根據玩家選擇調用HotFixManager對應的函數進行操做,不過個人初始想法就是讓使用盡可能方便,因此我儘可能去掉了資源的使用,當成了一個系統內的控件進行了儘可能的封裝操做。
新建一個scene使用便可hotfix-scene.js:
var HotFixScene = cc.Scene.extend({
ctor:function() {
this._super();
var layer = new cc.Layer();
this.addChild(layer);
var loadPoster = new cc.Sprite("res/static/poster.png");
loadPoster.setPosition(layer.width*0.5,layer.height*0.5)
loadPoster.setScale(layer.height/loadPoster.height);
layer.addChild(loadPoster);
// 熱更新系統使用
HotFixManager.init(this._updateFinish,this);
HotFixManager.checkUpdate();
},
_updateFinish:function() {
var delay_func = function() {
// js文件列表文件,此文件在熱更新過程當中應該保持路徑不變
// 由於此處是寫死的,不太好改變,除非你本身在熱更新配置一個字段,用於保存此路徑
var jsFile = "src/dynamic/js-list.js";
// 加載js文件列表
cc.loader.loadJs(jsFile, function(){
// 加載js文件列表中的js文件
cc.loader.loadJs(jsList, function(){
// 跳轉到正式遊戲scene
cc.director.runScene(new GameScene());
});
});
}
// 此操做是爲了避開當前幀跳轉,否則界面會有卡頓感受
this.scheduleOnce(delay_func, 0.05);
}
});
熱更新系統的使用是特別簡單的,只須要在main.js的cc.game.onStart函數執行
cc.director.runScene(new HotFixScene());
就能夠了。固然這兩個文件你要配置在project.json中。
其實我真正想作到的是做爲一個插件使用,對於已經完成的項目,要添加此熱更新插件特別簡單,只須要作幾件事情就能夠了:
一、將原有的project.json中的js文件列表寫進」src/dynamic/js-list.js」文件的var jsList=[]數組中(jsList名字對應於HotFixScene中的jsList)。
二、將上述兩個文件加入遊戲,並將其路徑配置到project.json。
三、配置本身的熱更新文件配置(包括搭建本身的服務器),修改HotFixManager.init()中的讀寫目錄(若跟個人目錄一致則不用改寫)。
四、修改熱更新結束後的scene跳轉爲已實現的文件跳轉。
// 跳轉到正式遊戲scene
cc.director.runScene(new GameScene());
五、測試運行。
————————————————樸實無華分割線,如下內容不重要————————————————
下面是兩張實際運行圖:(背景圖借用皇室戰爭的海報圖)
選擇界面:
資源更新中界面:
結束