热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CocosCreator大厅+子游戏模式

一、前言根据上一篇(CocosCreator热更新),可以看出以下几点:build-default目录下的main

一、前言

根据上一篇(Cocos Creator热更新),可以看出以下几点:

  • build-default目录下的main.js,为cocos creator项目的入口;
  • 热更新一文中,放置在服务器上的,仅有资源,脚本,配置等,没有入口程序,因此本文中,我们需要创造一个入口程序。
还是解释一下什么叫大厅+子游戏模式:

1. 将大厅单独作为一个完整的项目,不同的子游戏,则为不同的项目
  2. 然后要实现不同项目之间的互调,即大厅调子游戏,或者子游戏调大厅
  3. 资源共享,共用的资源放在大厅项目中,并且子游戏中可以调用

这样做的好处:

1. 减小上架包的体积
  2. 提高热更新的效率(打开指定子游戏,才会更新子游戏)
  3. 降低项目的耦合性(如果不共享资源,子游戏完全可以随时抽取出来作为一个单独的包使用)

二、修改子游戏

1. 添加version_generato.js
2. 构建项目
3. 在原生src下,添加 main.js 入口文件
3.1 每次构建完项目,拷贝main.js到原生目录的src中

main.js的内容如下:

(function () { 'use strict'; if (window.jsb) { /// 1.初始化资源Lib路径Root. var subgameSearchPath = (jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/')+'ALLGame/subgame/'; /// 2.subgame资源未映射,则初始化资源映射表,否则略过映射. if(!cc.HallAndSubGameGlobal.subgameGlobal){ cc.HallAndSubGameGlobal.subgameGlobal = {}; /// 加载settings.js require(subgameSearchPath + 'src/settings.js'); var settings = window._CCSettings; window._CCSettings = undefined; if ( !settings.debug ) { var uuids = settings.uuids; var rawAssets = settings.rawAssets; var assetTypes = settings.assetTypes; var realRawAssets = settings.rawAssets = {}; for (var mount in rawAssets) { var entries = rawAssets[mount]; var realEntries = realRawAssets[mount] = {}; for (var id in entries) { var entry = entries[id]; var type = entry[1]; // retrieve minified raw asset if (typeof type === 'number') { entry[1] = assetTypes[type]; } // retrieve uuid realEntries[uuids[id] || id] = entry; } } var scenes = settings.scenes; for (var i = 0; i

ps: 不用管src外部的main.js文件

3.2 或者 添加build-templates目录,自动在每次构建项目后生成main.js文件
Cocos Creator大厅+子游戏模式

这里的main.js内容和上面的内容一致

4. 执行version_generator.js文件

生成version.manifest 和 project.mainfest。这个在上一篇中已经讲过,就不细说了。

三、拷贝res,src,version.manifest 和 project.mainfest到服务器目录下

Cocos Creator大厅+子游戏模式

很明显,现在我们只是把子游戏生成了资源包,但是没有做任何热更新的操作。
接下来,就需要在大厅项目中,添加下载,更新的逻辑了。

四、在大厅项目中,添加相应逻辑

负责下载,检测更新,更新子游戏的工具库文件内容如下:

const SubgameManager = { _storagePath: [], _getfiles: function(name, type, downloadCallback, finishCallback) { this._storagePath[name] = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'ALLGame/' + name); this._downloadCallback = downloadCallback; this._finishCallback = finishCallback; this._fileName = name; /// 替换该地址 var UIRLFILE = "http://192.168.200.117:8000/" + name + "/remote-assets"; var filees = this._storagePath[name] + '/project.manifest'; var customManifestStr = JSON.stringify({ 'packageUrl': UIRLFILE, 'remoteManifestUrl': UIRLFILE + '/project.manifest', 'remoteVersionUrl': UIRLFILE + '/version.manifest', 'version': '0.0.1', 'assets': {}, 'searchPaths': [] }); var versiOnCompareHandle= function(versionA, versionB) { var vA = versionA.split('.'); var vB = versionB.split('.'); for (var i = 0; i vA.length) { return -1; } else { return 0; } }; this._am = new jsb.AssetsManager('', this._storagePath[name], versionCompareHandle); if (!cc.sys.ENABLE_GC_FOR_NATIVE_OBJECTS) { this._am.retain(); } this._am.setVerifyCallback(function(path, asset) { var compressed = asset.compressed; if (compressed) { return true; } else { return true; } }); if (cc.sys.os === cc.sys.OS_ANDROID) { this._am.setMaxConcurrentTask(2); } if (type === 1) { this._updateListener = new jsb.EventListenerAssetsManager(this._am, this._updateCb.bind(this)); } else if (type == 2) { this._updateListener = new jsb.EventListenerAssetsManager(this._am, this._checkCb.bind(this)); } else { this._updateListener = new jsb.EventListenerAssetsManager(this._am, this._needUpdate.bind(this)); } cc.eventManager.addListener(this._updateListener, 1); if (this._am.getState() === jsb.AssetsManager.State.UNINITED) { var manifest = new jsb.Manifest(customManifestStr, this._storagePath[name]); this._am.loadLocalManifest(manifest, this._storagePath[name]); } if (type === 1) { this._am.update(); this._failCount = 0; } else { this._am.checkUpdate(); } this._updating = true; cc.log('更新文件:' + filees); }, // type = 1 _updateCb: function(event) { var failed = false; let self = this; switch (event.getEventCode()) { case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST: /*0 本地没有配置文件*/ cc.log('updateCb本地没有配置文件'); failed = true; break; case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST: /*1下载配置文件错误*/ cc.log('updateCb下载配置文件错误'); failed = true; break; case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST: /*2 解析文件错误*/ cc.log('updateCb解析文件错误'); failed = true; break; case jsb.EventAssetsManager.NEW_VERSION_FOUND: /*3发现新的更新*/ cc.log('updateCb发现新的更新'); break; case jsb.EventAssetsManager.ALREADY_UP_TO_DATE: /*4 已经是最新的*/ cc.log('updateCb已经是最新的'); failed = true; break; case jsb.EventAssetsManager.UPDATE_PROGRESSION: /*5 最新进展 */ self._downloadCallback && self._downloadCallback(event.getPercentByFile()); break; case jsb.EventAssetsManager.ASSET_UPDATED: /*6需要更新*/ break; case jsb.EventAssetsManager.ERROR_UPDATING: /*7更新错误*/ cc.log('updateCb更新错误'); break; case jsb.EventAssetsManager.UPDATE_FINISHED: /*8更新完成*/ self._finishCallback && self._finishCallback(true); break; case jsb.EventAssetsManager.UPDATE_FAILED: /*9更新失败*/ self._failCount++; if (self._failCount

调用的过程如下:
    1. 判断子游戏是否已下载
    2. 已下载,判断是否需要更新
    3.1 下载游戏
    3.2 更新游戏
    4. 进入子游戏

const SubgameManager = require('SubgameManager'); cc.Class({ extends: cc.Component, properties: { downloadBtn: { default: null, type: cc.Node }, downloadLabel: { default: null, type: cc.Label } }, onLoad: function () { const name = 'subgame'; //判断子游戏有没有下载 if (SubgameManager.isSubgameDownLoad(name)) { //已下载,判断是否需要更新 SubgameManager.needUpdateSubgame(name, (success) => { if (success) { this.downloadLabel.string = "子游戏需要更新"; } else { this.downloadLabel.string = "子游戏不需要更新"; } }, () => { cc.log('出错了'); }); } else { this.downloadLabel.string = "子游戏未下载"; } this.downloadBtn.on('click', () => { //下载子游戏/更新子游戏 SubgameManager.downloadSubgame(name, (progress) => { if (isNaN(progress)) { progress = 0; } this.downloadLabel.string = "资源下载中 " + parseInt(progress * 100) + "%"; }, function(success) { if (success) { SubgameManager.enterSubgame('subgame'); } else { cc.log('下载失败'); } }); }, this); }, });

说到这呢,就得提一下,
如果界面设计时,从大厅点击子游戏,中间有loading的界面的话,
loading界面就应该放在大厅的工程中了。

五、测试

打开服务——>编译大厅目录——>安装运行
注意:
    一定要生成原生apk,在真机(也可以是类似于夜神的模拟器啦)上运行测试。
结果:
    1. 第一次,本地没有子游戏,提示“游戏未下载”,下载后,无需重启,可直接进入子游戏;
    2. 修改version_generator.js中的版本号,将步骤二,再走一遍,能检测到更新,同样无需重启;
    3. 在大厅中,使用cc.sys.localStorage存储的值,在子游戏中可以获取到;

本人的一点小思考:

在研究之前,想着一定要研究一下资源共享的问题;
现在想来,既然要将子游戏独立出一个项目,自然也期望以后子游戏可以作为一个单独的apk来运行,如果共用大厅的资源,以后想抽取出来,又是一项艰巨的任务。但是这样必然会造成一定的重复资源。具体取舍,等到项目后期再协调。


推荐阅读
  • Webpack5内置处理图片资源的配置方法
    本文介绍了在Webpack5中处理图片资源的配置方法。在Webpack4中,我们需要使用file-loader和url-loader来处理图片资源,但是在Webpack5中,这两个Loader的功能已经被内置到Webpack中,我们只需要简单配置即可实现图片资源的处理。本文还介绍了一些常用的配置方法,如匹配不同类型的图片文件、设置输出路径等。通过本文的学习,读者可以快速掌握Webpack5处理图片资源的方法。 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了如何使用Express App提供静态文件,同时提到了一些不需要使用的文件,如package.json和/.ssh/known_hosts,并解释了为什么app.get('*')无法捕获所有请求以及为什么app.use(express.static(__dirname))可能会提供不需要的文件。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • 如何优化Webpack打包后的代码分割
    本文介绍了如何通过优化Webpack的代码分割来减小打包后的文件大小。主要包括拆分业务逻辑代码和引入第三方包的代码、配置Webpack插件、异步代码的处理、代码分割重命名、配置vendors和cacheGroups等方面的内容。通过合理配置和优化,可以有效减小打包后的文件大小,提高应用的加载速度。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • 本文介绍了Sencha Touch的学习使用心得,主要包括搭建项目框架的过程。作者强调了使用MVC模式的重要性,并提供了一个干净的引用示例。文章还介绍了Index.html页面的作用,以及如何通过链接样式表来改变全局风格。 ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
  • Node.js学习笔记(一)package.json及cnpm
    本文介绍了Node.js中包的概念,以及如何使用包来统一管理具有相互依赖关系的模块。同时还介绍了NPM(Node Package Manager)的基本介绍和使用方法,以及如何通过NPM下载第三方模块。 ... [详细]
  • 本文介绍了解决mysql 5.1启动问题的方法,通过修改my.ini文件中的相关配置,包括innodb_data_home_dir和skip-innodb等,可以解决启动问题。同时还介绍了如何调整内存池来存储metadata信息。 ... [详细]
  • {moduleinfo:{card_count:[{count_phone:1,count:1}],search_count:[{count_phone:4 ... [详细]
author-avatar
nilue1_203
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有