CocosCreator热更新介绍
  Gl3kUIttbPjD 2023年11月02日 60 0

当提到CocosCreator的热更新功能时,我们可以看到这是一个非常有用且强大的特性。热更新允许开发者在游戏发布后,通过网络下载和应用更新,而无需重新发布整个游戏。这使得开发者可以快速修复漏洞、添加新功能和改进游戏性,而无需用户重新下载和安装游戏。

CocosCreator的热更新功能基于资源管理器和版本控制系统,它提供了一个灵活的机制来管理和更新游戏资源。下面是一些关于CocosCreator热更新的重要概念和工作流程:

  1. 版本管理:热更新的核心是版本管理。每次发布新的游戏版本时,开发者需要为该版本创建一个唯一的版本号或标识符。这有助于确保每个用户都可以获取到正确的更新。
  2. 资源打包:在发布新版本之前,开发者需要将游戏资源打包成一个可下载的包。这个包通常是一个压缩文件,包含了需要更新的游戏资源,如脚本、图片、音频等。
  3. 服务器端:开发者需要设置一个服务器来存储和分发游戏更新。服务器端负责存储不同版本的资源包,并提供一个接口供游戏客户端下载和应用更新。
  4. 游戏客户端:游戏客户端在启动时会检查服务器上的最新版本,并与本地版本进行比较。如果有新版本可用,客户端会下载相应的资源包,并将其解压到本地文件系统中。
  5. 资源管理器:CocosCreator提供了一个资源管理器来管理游戏资源的加载和使用。通过资源管理器,开发者可以动态加载和卸载游戏资源,包括从服务器下载的更新资源。
  6. 更新检查和应用:在游戏运行过程中,开发者可以定期检查服务器上的更新,并下载新的资源包。一旦下载完成,开发者可以使用资源管理器来加载和应用这些更新的资源。

通过使用CocosCreator的热更新功能,开发者可以实现以下优势:

  1. 快速修复漏洞:如果在发布后发现了游戏中的漏洞或错误,开发者可以快速修复并通过热更新将修复后的版本推送给用户,而无需等待整个游戏重新下载。
  2. 添加新功能:开发者可以通过热更新向游戏中添加新的功能、关卡或角色,而无需用户重新下载和安装游戏。
  3. 优化游戏性能:如果发现游戏中的性能问题,开发者可以通过热更新来优化资源文件,减少加载时间,提高游戏性能。
  4. 分阶段发布:使用热更新,开发者可以将游戏的不同阶段作为不同的版本进行发布。这样可以控制用户在不同时间点上的游戏体验,逐步引入新的内容和功能。

总的来说,CocosCreator的热更新功能为游戏开发者提供了一种灵活而高效的方式来管理和更新游戏资源。它使得游戏开发和维护更加便捷,同时为玩家提供了更好的游戏体验。

以上巴拉巴拉一堆简单来说就是好,非常好! 没有啥都不能没有他。 哈哈。。开玩笑了,大家最好还是仔细看下他的工作流程,能帮助小白能更好的理解热更的流程。下面咱们就直接开始教程吧。

1.第一步就用cocoscreator官网的热更插件,安装上,我就不详细说明了,能够出现下面的就是安装成功了

CocosCreator热更新介绍_开发者

2.然后就可以构建发布项目了,先构建项目不要编译。注意:这个MD5 Cache一定不要点开,他是给资源加上md5的如果点开每次文件都不一样,肯定就无法成功了。

CocosCreator热更新介绍_热更新_02

3.构建完成后就可以打开热更界面了,然后配置好自己的资源地址。如图:

CocosCreator热更新介绍_sed_03

4.生成热更包后解压出来,将project.manifest文件和version.manifest文件拉到工程里,可以直接放到assets目录下

5.好了 剩下的就是代码了,我把我的全部贴出来。其实用官网的也行 大致逻辑都是一样的。


cc.Class({
    extends: cc.Component,

    properties: {
        progressBar: cc.ProgressBar,
        loadingInfo: cc.Label,
        effect_loading: cc.Node,
        updateConfirm: cc.Node,
        contentT: cc.Label,
        // titleT: cc.Label,
        T_quit: cc.Label,
        T_hotupdate: cc.Label,
        manifestUrl: {
            type: cc.Asset,
            default: null
        },
        logo: cc.Node,
        companyT: cc.Label,
        refreshT: cc.Label,
        login_jdtg: cc.Node,
        fixBtn: cc.Node,
        bgNode: cc.Node,
        shanping: cc.Node,
        time:null,
        cishu:0,
    },
    onLoad() {

        var config = require("config");
        
        this.companyT.string = this.companyT.string;
        if (this.logo && !config.showlogo) this.logo.active = false;
        this.fixBtn.active = cc.sys.isNative;
        var ajustPhoneXUtil = require("ajustPhoneXUtil")
        ajustPhoneXUtil.checkPhoneX(this.node.parent);
        ajustPhoneXUtil.resetWidget(this.node.parent);

        this.loadingInfo.fontFamily = "Microsoft YaHei";
        this.contentT.fontFamily = "Microsoft YaHei";
        this.T_quit.fontFamily = "Microsoft YaHei";
        this.T_hotupdate.fontFamily = "Microsoft YaHei";
        // this.titleT.fontFamily = "Microsoft YaHei";
        ajustPhoneXUtil.shortHeightWidget(this.progressBar.node);
        this.T_quit.string = "离开游戏";
        this.T_hotupdate.string = "确 定";
        // this.titleT.string = "检查更新";

        this.companyT.fontSize = ajustPhoneXUtil.isShort ? 10 : 14;
        this.companyT.lineHeight = ajustPhoneXUtil.isShort ? 14 : 20;

        if (cc.sys.isNative) this.loadingInfo._isBold = true;
        if (cc.sys.isNative) this.contentT._isBold = true;
        if (cc.sys.isNative) this.T_quit._isBold = true;
        if (cc.sys.isNative) this.T_hotupdate._isBold = true;
        // if (cc.sys.isNative) this.titleT._isBold = true;
        this.refreshT.node.active = cc.sys.platform === cc.sys.WECHAT_GAME ? true : false;
        if (this.refreshT.node.active) {
            this.refreshT.string = "如加载时间过长,请点击此处刷新"
        }
    },

    start() {


    },
    tiemStar() {
        this.cishu = 1;
        var cuLoadPercent = 0;
        var loadAction = cc.sequence(cc.callFunc(() => {
            cuLoadPercent += 1;
            if (cuLoadPercent > 100) {
                cuLoadPercent = 0;
                // this.enterLoginScene()
            }
            this.setProgress(this.progressBar, cuLoadPercent, 100);
        }), cc.delayTime(0.02)).repeatForever()
        this.progressBar.node.runAction(loadAction)
        var config = require("config")
        if (cc.sys.isNative) {
            this.jianchaUpdate()
            if (!CC_DEBUG) {
                console.log("jinru11", CC_DEBUG)
                // this.jianchaUpdate()
            } else {
                console.log("jinru222", CC_DEBUG)
                // this.enterLoginScene()
            }
            // this.enterLoginScene()
        } else {
            //--wp  考虑方法转移 放到这里进行账号登录


            //--wp  进行保留
            require("miniGame").wxLogin(() => {
                // this.loadingInfo.string = "账号登陆中...";
                // require("uiLoader").loadPrefab("module/selectSer/newSelectSerUI", cc.Prefab, null, () => {
                this.enterLoginScene()
                // })
            })
        }
        this.loadBg();
    },
    loadBg() {
        // this.unscheduleAllCallbacks();
        // if (require("config").evn !== require("config").appGame) return;
        // let urls = ["loading01", "loading02", "loading03"];
        // var spriteNode = this.node.getChildByName("loginGame_bg").getComponent(cc.Sprite);
        // this.schedule(function () {
        //     let num = require("uiUtils").randomNum(0, urls.length - 1);
        //     require("gameLoader").loadImg("bg/" + urls[num], spriteNode, true, 0);
        //     spriteNode.type = cc.Sprite.Type.SIMPLE;
        //     spriteNode.sizeMode = cc.Sprite.SizeMode.RAW;
        // }, 4);
    },
    enterLoginScene() {
        console.log('如果打印则没有进入热更')
        this.loadingInfo.string = "账号登陆中...";
        this.loadSubScript("game", () => {
            this.cishu = 0;
            cc.director.loadScene("login");
        })
    },


    loadSubScript(name, callback) {
        if (CC_DEBUG) {
            if (callback) callback();
            return;
        }
        if (require("config").isOnepack) {
            var moduleNames = window.moduleNames;
            if (moduleNames) {
                var intervalId = null;
                intervalId = setInterval(() => {
                    if (moduleNames.length > 0) {
                        var arr = [];
                        for (let i = 0; i < 8; i++) {
                            if (moduleNames.length > 0) arr.push(moduleNames.shift());
                        }
                        __require(allModules, required, arr);
                    } else {
                        clearInterval(intervalId);
                        if (callback) callback();
                    }
                }, 3)
            } else {
                console.log("loadSubScript: 'isOnepack'")
                if (callback) callback();
            }
        } else {
            cc.loader.downloader.loadSubpackage(name, (err) => {
                if (err) {
                    this.loadSubScript(name, callback);
                } else {
                    if (callback) callback();
                }
            });
        }
    },
    setProgress(progressBar, curLoadCount, totalCount) {
        var progress = curLoadCount / totalCount;
        progressBar.progress = progress;
        // if (progress > 0 && progress <= 1) {
        this.login_jdtg.active = 1;
        // } else {
        //     this.login_jdtg.active = 0;
        // };
        this.login_jdtg.x = progressBar.progress * progressBar.node.width;

        this.effect_loading.position = cc.v2(progressBar.barSprite.node.x + progressBar.barSprite.node.width * progress, this.effect_loading.position.y);
    },


    jianchaUpdate() {
        if (!cc.sys.isNative) {
            return;
        }
        this.loadingInfo.string = "检查更新...";
        this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'remote-asset');
        console.log('Storage path for remote asset : ' + this._storagePath);
        var self = this;
        var versionCompareHandle = function (versionA, versionB) {
            console.log("JS Custom Version Compare: version A is " + versionA + ', version B is ' + versionB);
            var vA = versionA.split('.');
            var vB = versionB.split('.');
            // if (parseInt(vB[1]) > parseInt(vA[1])) {//强制更新app
            //     console.log("isNeedForceUpdate:true")
            //     self.isNeedForceUpdate = true;
            //     return -1;
            // } else {
            console.log("isNeedForceUpdate:false")
            for (var i = 0; i < vA.length; ++i) {
                var a = parseInt(vA[i]);
                var b = parseInt(vB[i] || 0);
                if (a === b) {
                    continue;
                }
                else {
                    return a - b;
                }
            }
            if (vB.length > vA.length) {
                return -1;
            }
            else {
                return 0;
            }
            // }
        }
        this._am = new jsb.AssetsManager(this.manifestUrl, this._storagePath, versionCompareHandle);
        console.log(this._am)
        this._am.setVerifyCallback(function (path, asset) {
            var compressed = asset.compressed;
            var expectedMD5 = asset.md5;
            var relativePath = asset.path;
            if (compressed) {
                // self.label.string = "Verification passed : " + relativePath;
                return true;
            }
            else {
                // self.label.string = "Verification passed : " + relativePath + ' (' + expectedMD5 + ')';
                return true;
            }
        });


        if (cc.sys.os === cc.sys.OS_ANDROID) {
            //当并发任务太多时,一些Android设备可能会减慢下载速度。
            //数值可能不准确,请多做测试,找出最适合你的游戏。
            this._am.setMaxConcurrentTask(2);
            console.log("最大并发任务数被限制为2");
        }

        if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {//0
            var url = this.manifestUrl.nativeUrl;
            if (cc.loader.md5Pipe) {
                url = cc.loader.md5Pipe.transformURL(url);
            }
            this._am.loadLocalManifest(url);
        }
        if (!this._am.getLocalManifest() || !this._am.getLocalManifest().isLoaded()) {
            this.checkFail();
            console.log("加载本地清单失败 ...")
            this.enterLoginScene();
            return;
        }
        this._am.setEventCallback(this.checkCb.bind(this));
        this._am.checkUpdate()
        this._updating = true;

        this.updateConfirm.active = true;
    },

    checkFail() {
        this.loadingInfo.string = "更新失败,请检查您的网络退出游戏重试";
        this.progressBar.node.active = true;
        this.updateConfirm.active = false;
        this.progressBar.node.stopAllActions();
    },

    checkCb(event) {
        if (this.isNeedForceUpdate) {
            this.progressBar.node.active = false;
            this.updateConfirm.active = true;
            this.contentT.string = "检查到有新的APP版本更新,请前往下载更新";
            this.T_hotupdate.string = "继续游戏";
            return;
        }
        console.log("checkCb:", event.getEventCode())
        switch (event.getEventCode()) {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST://0
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST://1
                this.enterLoginScene();
                break;
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST://2
                this.checkFail();
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE://4
                this.enterLoginScene();
                break;
            case jsb.EventAssetsManager.NEW_VERSION_FOUND://3
                this.progressBar.node.active = false;
                this.updateConfirm.active = true;
                // console.log("NEW_VERSION_FOUND", this.isNeedForceUpdate)
                // if (this.isNeedForceUpdate) {
                //     this.contentT.string = "检查到有新的APP版本更新,请前往下载更新";
                //     this.T_hotupdate.string = "前往";
                // } else {
                // this._am.prepareUpdate()----注释掉不知道为什么
                var bytes = this._am.getTotalBytes()
                console.log("bytes:", bytes, this._am.getDownloadedFiles(), this._am.getState(), this._am.getTotalFiles())
                var totalSize = (bytes / 1024 / 1024).toFixed(2)
                this.contentT.string = "检查到新版本,是否更新?";// cc.js.formatStr("需更新部分内容才可进入游戏,更新包\n大小为%sMB,是否更新?", totalSize)
                // }
                break;
            default:
                return;
        }
        this._am.setEventCallback(null);
        this._checkListener = null;
        this._updating = false;
    },


    hotUpdate() {
        // if (this.updateConfirm.isFix) {
        //     this.updateConfirm.isFix = false;
        //     require("config").fixGame();
        //     cc.game.restart();
        //     return;
        // }
        console.log("hotUpdate:")
        console.log(this.isNeedForceUpdate)
        // 新版本 跳转链接
        if (false) {
            // var url = "";
            // if (cc.sys.os === cc.sys.OS_IOS) {
            //     url = "https://www.baidu.com/";
            // } else {
            //     url = "https://www.baidu.com/";
            // }
            // cc.sys.openURL(url)
            // this.enterLoginScene();
        } else {
            this.updateConfirm.active = false;
            this.progressBar.node.active = true;
            this.progressBar.node.stopAllActions();
            if (this._am && !this._updating) {
                console.log('开始更新了' + this._am.getState())
                this._am.setEventCallback(this.updateCb.bind(this));

                if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {
                    // Resolve md5 url
                    var url = this.manifestUrl.nativeUrl;
                    console.log('开始更新了2' + url)
                    if (cc.loader.md5Pipe) {
                        url = cc.loader.md5Pipe.transformURL(url);
                    }
                    console.log(url)
                    this._am.loadLocalManifest(url);
                }

                console.log('开始更新了3')

                this._failCount = 0;
                this._am.update();
                this._updating = true;
            }
        }
    },
    updateCb(event) {
        console.log("updateCb:" + event.getEventCode());
        var needRestart = false;
        var failed = false;

        switch (event.getEventCode()) {
            case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST://0
                this.checkFail();
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_PROGRESSION://5

                let showst = "正在更新(" + (event.getDownloadedBytes() / 1024 / 1024).toFixed(2) + 'M/' + (event.getTotalBytes() / 1024 / 1024).toFixed(2) + 'M)'
                console.log("" + showst);
                this.progressBar.progress = event.getPercent();
                this.loadingInfo.string = "正在更新(" + (event.getDownloadedBytes() / 1024 / 1024).toFixed(2) + 'M/' + (event.getTotalBytes() / 1024 / 1024).toFixed(2) + 'M)';
                break;
            case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST://1
                console.log(" 'Fail to download manifest file, 1.'");
                break;
            case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST://2
                console.log(" 'Fail to download manifest file, hot update skipped.'");
                this.checkFail()
                failed = true;
                break;
            case jsb.EventAssetsManager.ALREADY_UP_TO_DATE://4
                // this.checkFail()
                console.log(" 'Already up to date with the latest remote version.'");
                failed = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FINISHED://8
                this.loadingInfo.string = "更新成功,正在进入游戏";
                needRestart = true;
                break;
            case jsb.EventAssetsManager.UPDATE_FAILED://9
                console.log("Update failed." + event.getMessage());
                this.checkFail();
                this._updating = false;
                this._canRetry = true;
                break;
            case jsb.EventAssetsManager.ERROR_UPDATING://7
                console.log(" 'Asset update error: ' + event.getAssetId() + ', ' + event.getMessage()");
                this.checkFail()
                break;
            case jsb.EventAssetsManager.ERROR_DECOMPRESS://10
                console.log(" event.getMessage()");
                this.checkFail()
                break;
            default:
                break;
        }

        if (failed) {
            this._am.setEventCallback(null);
            this._updateListener = null;
            this._updating = false;
            this.checkFail()
        }

        if (needRestart) {
            this._am.setEventCallback(null);
            this._updateListener = null;
            var searchPaths = jsb.fileUtils.getSearchPaths();
            var newPaths = this._am.getLocalManifest().getSearchPaths();

            Array.prototype.unshift(searchPaths, newPaths);
            cc.sys.localStorage.setItem('HotUpdateSearchPaths', JSON.stringify(searchPaths));
            jsb.fileUtils.setSearchPaths(searchPaths);
            cc.audioEngine.pauseAll();
            cc.game.restart();
        }
    },

    existGame() {
        if (this.updateConfirm.isFix) {
            this.updateConfirm.active = false;
            this.updateConfirm.isFix = false;
        } else {
            cc.game.end()
        }
    },

    fixGame() {
        this.progressBar.node.active = false;
        // this.updateConfirm.active = true;
        this.updateConfirm.isFix = true;
        this.contentT.string = "该操作会清除本地的补丁并重新下载补丁,\n请在良好的环境下进行";
        this.T_hotupdate.string = "确定";
        this.T_quit.string = "取消";
    },

    clearCache() {
        if (cc.sys.platform === cc.sys.WECHAT_GAME) {
            wxDownloader.cleanAllCaches(null, function () { require("miniGame").logout(); });
        }
    },

});

6.然后将project.manifest文件在IDE中拖入到该脚本中。

7.弄完后就可以编译出包了。出完包后测试热更的话,可以在场景中加入一个按钮,然后再构建(不要编译)一次,然后打开热更面板将版本号调高一下生成热更包。将热更包解压到自己的地址中,就大功告成啦!




【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  4iyZ3fvD49OU   2023年12月10日   31   0   0 sedciide
Gl3kUIttbPjD
作者其他文章 更多