参考cocos论坛:http://forum.cocos.com/t/1-5-2-demo/48200
demo: https://github.com/zhangjiangyi/HallAndChild
主要的是实现下载子游戏、跳转到子游戏,然后由子游戏返回到大厅。

我们知道、在启动cocos工程的时候,首先要加载main.js文件,加载准备工作,执行一些配置操作。而由大厅跳转到子游戏的话我们是否需要知道子游戏的配置文件setting.js跟main.js。然后由大厅跳转到子游戏的话其实就是获取子游戏的main.js文件就行了。

首先就是要用热更新的方式下载子游戏。但是热更新下载子游戏的话需要project.manifest文件跟远程文件做对比,但是一开始的时候是子游戏是空空如也的,那就只能用远程的方式获取project.manifest文件,然后进行热更新了。

    checkUpdate: function () {let UIRLFILE = "http://192.168.92.59/update/remote-assets";let remoteManifestUrl = this._storagePath + "/project.manifest";this.manifestUrl = remoteManifestUrl;let customManifestStr = JSON.stringify({"packageUrl": UIRLFILE,"remoteManifestUrl": UIRLFILE + "/project.manifest","remoteVersionUrl": UIRLFILE + "/version.manifest","version": "1.0.0.0","assets": {},"searchPaths": []});this._checkListener = new jsb.EventListenerAssetsManager(this._am, this.checkCb.bind(this));cc.eventManager.addListener(this._checkListener, 1);if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {if (jsb.fileUtils.isFileExist(remoteManifestUrl)) {console.log('加载本地Manifest');this._am.loadLocalManifest(this.manifestUrl);} else {console.log('加载网络Manifest');let manifest = new jsb.Manifest(customManifestStr, this._storagePath);this._am.loadLocalManifest(manifest, this._storagePath);}}this.prmopt.string = '正在检查版本信息';this._am.checkUpdate();},

大厅的主要逻辑HotUpdate代码如下(主要负责下载子游戏,并跳转到子游戏):

cc.Class({extends: cc.Component,properties: {_am: null,_updating: false,_canRetry: true,_storagePath: '',_version: -1,},// use this for initializationonLoad: function () {this.initView();this.initAssetsManage();},initView() {this.percentLabel = cc.find('Canvas/percent').getComponent(cc.Label);this.prmopt = cc.find('Canvas/prompt').getComponent(cc.Label);},initAssetsManage() {if (cc.sys.isBrowser) {return;}this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'ALLGame/subgame');console.log('SubGame path ' + this._storagePath);let versionCompareHandle = function (versionA, versionB) {let vA = versionA.split('.');let vB = versionB.split('.');for (let i = 0; i < vA.length; ++i) {let a = parseInt(vA[i]);let b = parseInt(vB[i] || 0);if (a !== b) {return a - b;}}return vB.length > vA.length ? -1 : 0;};this._am = new jsb.AssetsManager('', this._storagePath, versionCompareHandle);if (!cc.sys.ENABLE_GC_FOR_NATIVE_OBJECTS) {this._am.retain();}if (cc.sys.os === cc.sys.OS_ANDROID) {this._am.setMaxConcurrentTask(2);}},checkCb: function (event) {let delayTime = 2000;switch (event.getEventCode()) {case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:this.prmopt.string = "本地Manifest文件未找到";break;case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:this.prmopt.string = "加载Manifest文件失败";break;case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:this.prmopt.string = "已经是最新版本";delayTime = 1000;break;case jsb.EventAssetsManager.NEW_VERSION_FOUND:this.prmopt.string = '找到新版本';cc.eventManager.removeListener(this._checkListener);this._checkListener = null;this._updating = false;setTimeout(() =>  this.hotUpdate(), 1000);return;default:return;}cc.eventManager.removeListener(this._checkListener);this._checkListener = null;this._updating = false;},updateCb: function (event) {console.log('update eventCode = ' + event.getEventCode(), 'update msg = ' + event.getMessage());switch (event.getEventCode()) {case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST:this.prmopt.string = '未找到本地Manifest文件';break;case jsb.EventAssetsManager.UPDATE_PROGRESSION:let percent = event.getPercent().toFixed(2);this.percentLabel.string = parseInt(percent * 100) + '%';break;case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST:case jsb.EventAssetsManager.ERROR_PARSE_MANIFEST:this.prmopt.string = '下载Manifest文件失败';break;case jsb.EventAssetsManager.ALREADY_UP_TO_DATE:this.prmopt.string = '已更新到最新版本';break;case jsb.EventAssetsManager.UPDATE_FINISHED:this.prmopt.string = '更新成功,正在重启游戏...';cc.eventManager.removeListener(this._updateListener);this._updateListener = null;this._updating = false;break;case jsb.EventAssetsManager.UPDATE_FAILED:this._updating = false;this.prmopt.string = '更新失败';break;case jsb.EventAssetsManager.ERROR_UPDATING:this.prmopt.string = '更新文件错误 ' + event.getAssetId() + ', ' + event.getMessage();break;case jsb.EventAssetsManager.ERROR_DECOMPRESS:this.prmopt.string = event.getMessage();break;default:break;}},retry: function () {if (!this._updating && this._canRetry) {this._canRetry = false;this.prmopt.string = '更新失败,再次更新';this._am.downloadFailedAssets();}},checkUpdate: function () {let UIRLFILE = "http://192.168.92.59/update/remote-assets";let remoteManifestUrl = this._storagePath + "/project.manifest";this.manifestUrl = remoteManifestUrl;let customManifestStr = JSON.stringify({"packageUrl": UIRLFILE,"remoteManifestUrl": UIRLFILE + "/project.manifest","remoteVersionUrl": UIRLFILE + "/version.manifest","version": "1.0.0.0","assets": {},"searchPaths": []});this._checkListener = new jsb.EventListenerAssetsManager(this._am, this.checkCb.bind(this));cc.eventManager.addListener(this._checkListener, 1);if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {if (jsb.fileUtils.isFileExist(remoteManifestUrl)) {console.log('加载本地Manifest');this._am.loadLocalManifest(this.manifestUrl);} else {console.log('加载网络Manifest');let manifest = new jsb.Manifest(customManifestStr, this._storagePath);this._am.loadLocalManifest(manifest, this._storagePath);}}this.prmopt.string = '正在检查版本信息';this._am.checkUpdate();this._updating = true;},hotUpdate: function () {if (this._am) {this._updateListener = new jsb.EventListenerAssetsManager(this._am, this.updateCb.bind(this));cc.eventManager.addListener(this._updateListener, 1);if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {console.log('load local manifest');this._am.loadLocalManifest(this.manifestUrl);}console.log('update');this._am.update();}},getVersion: function () {   //获取版本信息if (cc.sys.isBrowser) {return;}if (this._am.getState() === jsb.AssetsManager.State.UNINITED) {this._am.loadLocalManifest(this.manifestUrl);}return this._am.getLocalManifest().getVersion();},enter_sub_game: function() {if (!this._storagePath) {this.prompt.string = "请先点击下载游戏,检查版本是否更新!!!";return;}console.log('subgame path = '+ this._storagePath);require(this._storagePath + "/src/main.js");},});

如果子游戏下载成功的话就要开始跳转到子游戏了,首先要知道子游戏下载完成后的目录

this._storagePath = ((jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + 'ALLGame/subgame');

然后require子游戏的main.js

require(this._storagePath + "/src/main.js");

但是这个时候会报错,因为在子游戏的src目录下面根本没有main.js文件。那我们这个时候就要把main.js文件加入到src当中,并且是要在生成project.manifest文件前加进去,不然main.js跟setting.js文件不会随着热更新下载到子游戏项目下的。所以在项目构建完成的时候就要把main.js跟setting.js文件放在build/jsb-default/src目录下,然后生成project.manifest文件,放到服务器上面,这样的话热更新子游戏就会把main.js文件下载下来。

接着看一瞎main.js文件的内容:

(function () {// if (cc && cc.sys.isNative) {//     var hotUpdateSearchPaths = cc.sys.localStorage.getItem('HotUpdateSearchPaths');//     if (hotUpdateSearchPaths) {//         jsb.fileUtils.setSearchPaths(JSON.parse(hotUpdateSearchPaths));//         console.log('[main.js] 热更新SearchPath: ' + JSON.parse(hotUpdateSearchPaths));//     }// }// 这是为了解决一个重启的 bug 而添加的cc.director.startAnimation();'use strict';cc.INGAME = (jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + "ALLGame/subgame";console.log('cc.INGAME========子游戏============================'+cc.INGAME);var _CCSettings = null;function boot() {console.log('setteing配置+'+_CCSettings);var settings = _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 < scenes.length; ++i) { var scene = scenes[i]; if (typeof scene.uuid === 'number') { scene.uuid = uuids[scene.uuid]; } } var packedAssets = settings.packedAssets; for (var packId in packedAssets) { var packedIds = packedAssets[packId]; for (var j = 0; j < packedIds.length; ++j) { if (typeof packedIds[j] === 'number') { packedIds[j] = uuids[packedIds[j]]; } } } } // init engine var canvas; if (cc.sys.isBrowser) { canvas = document.getElementById('GameCanvas'); } function setLoadingDisplay() { // Loading splash scene var splash = document.getElementById('splash'); var progressBar = splash.querySelector('.progress-bar span'); cc.loader.onProgress = function (completedCount, totalCount, item) { var percent = 100 * completedCount / totalCount; if (progressBar) { progressBar.style.width = percent.toFixed(2) + '%'; } }; splash.style.display = 'block'; progressBar.style.width = '0%'; cc.director.once(cc.Director.EVENT_AFTER_SCENE_LAUNCH, function () { splash.style.display = 'none'; }); } var onStart = function () { cc.view.resizeWithBrowserSize(true); // UC browser on many android devices have performance issue with retina display if (cc.sys.os !== cc.sys.OS_ANDROID || cc.sys.browserType !== cc.sys.BROWSER_TYPE_UC) { cc.view.enableRetina(true); } //cc.view.setDesignResolutionSize(settings.designWidth, settings.designHeight, cc.ResolutionPolicy.SHOW_ALL); if (cc.sys.isBrowser) { setLoadingDisplay(); } if (cc.sys.isMobile) { if (settings.orientation === 'landscape') { cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE); } else if (settings.orientation === 'portrait') { cc.view.setOrientation(cc.macro.ORIENTATION_PORTRAIT); } // qq, wechat, baidu cc.view.enableAutoFullScreen( cc.sys.browserType !== cc.sys.BROWSER_TYPE_BAIDU && cc.sys.browserType !== cc.sys.BROWSER_TYPE_WECHAT && cc.sys.browserType !== cc.sys.BROWSER_TYPE_MOBILE_QQ ); } // Limit downloading max concurrent task to 2, // more tasks simultaneously may cause performance draw back on some android system / brwosers. // You can adjust the number based on your own test result, you have to set it before any loading process to take effect. if (cc.sys.isBrowser && cc.sys.os === cc.sys.OS_ANDROID) { cc.macro.DOWNLOAD_MAX_CONCURRENT = 2; } // init assets cc.AssetLibrary.init({ libraryPath: 'res/import', rawAssetsBase: 'res/raw-', rawAssets: settings.rawAssets, packedAssets: settings.packedAssets, md5AssetsMap: settings.md5AssetsMap }); var launchScene = settings.launchScene; // load scene if (cc.runtime) { cc.director.setRuntimeLaunchScene(launchScene); } cc.director.loadScene(launchScene, null, function () { if (cc.sys.isBrowser) { // show canvas canvas.style.visibility = ''; var div = document.getElementById('GameDiv'); if (div) { div.style.backgroundImage = ''; } } cc.loader.onProgress = null; // play game // cc.game.resume(); console.log('Success to load scene: ' + launchScene); } ); }; // jsList var jsList = settings.jsList; var bundledScript = settings.debug ? 'project.dev.js' : 'project.js'; if (jsList) { jsList.push(bundledScript); } else { jsList = [bundledScript]; } // anysdk scripts if (cc.sys.isNative && cc.sys.isMobile) { // jsList = jsList.concat(['jsb_anysdk.js', 'jsb_anysdk_constants.js']); } jsList = jsList.map(function (x) { return cc.INGAME + 'src/' + x; }); var option = { //width: width, //height: height, id: 'GameCanvas', scenes: settings.scenes, debugMode: settings.debug ? cc.DebugMode.INFO : cc.DebugMode.ERROR, showFPS: settings.debug, frameRate: 60, jsList: jsList, groupList: settings.groupList, collisionMatrix: settings.collisionMatrix, renderMode: 0 }; cc.game.run(option, onStart); } if (window.document) { var splash = document.getElementById('splash'); splash.style.display = 'block'; var cocos2d = document.createElement('script'); cocos2d.async = true; cocos2d.src = window._CCSettings.debug ? 'cocos2d-js.js' : 'cocos2d-js-min.js'; var engineLoaded = function () { document.body.removeChild(cocos2d); cocos2d.removeEventListener('load', engineLoaded, false); window.eruda && eruda.init(); boot(); }; cocos2d.addEventListener('load', engineLoaded, false); document.body.appendChild(cocos2d); } else if (window.jsb) { console.log('返回大厅======================================='); if (!cc.chilgame) { cc.chilgame = _CCSettings = require(cc.INGAME + '/src/settings.js'); console.log('加载settings.js成功 cc.chilgame'+cc.chilgame); require('src/project.js'); console.log('加载project.js成功'); } else { _CCSettings = cc.chilgame; } boot(); } })(); 

这个main.js跟jsb-default目录下的main.js就改变了两个地方,一个是增加了一个cc.INGAME的全局变量,也就是子游戏目录:

cc.INGAME = (jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + "ALLGame/subgame";

第二个地方就是改变了window.jsb原生的配置函数,把原先的

        require('src/settings.js');require('src/jsb_polyfill.js');boot();

改变成

        if (!cc.chilgame) {cc.chilgame = _CCSettings = require(cc.INGAME + '/src/settings.js');console.log('加载settings.js成功   cc.chilgame'+cc.chilgame);require('src/project.js');console.log('加载project.js成功');} else {_CCSettings = cc.chilgame;}boot();

上面的修改就是让引擎执行子游戏的逻辑代码,setting.js的配置函数,跟project.js都执行的是子函数的,这样的话就相当于跳转到子游戏的逻辑了。

接下来就是从子游戏返回到大厅。根据大厅跳转到子游戏的逻辑来看的话,返回到大厅的话其实就是再次执行大厅的游戏逻辑,所以只要执行大厅的main.js文件就可以了。返回大厅的逻辑很简单,就是一个require大厅的js配置文件代码,

cc.INGAME = (jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/') + "ALLGame/subgame";
require(cc.INGAME+"/src/dating.js");

dating.js文件如下:

(function () {// if (cc && cc.sys.isNative) {//     var hotUpdateSearchPaths = cc.sys.localStorage.getItem('HotUpdateSearchPaths');//     if (hotUpdateSearchPaths) {//         jsb.fileUtils.setSearchPaths(JSON.parse(hotUpdateSearchPaths));//         console.log('[main.js] 热更新SearchPath: ' + JSON.parse(hotUpdateSearchPaths));//     }// }// 这是为了解决一个重启的 bug 而添加的cc.director.startAnimation();'use strict';cc.INGAME = '';//(jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/');console.log('cc.INGAME========dating.js============================'+cc.INGAME);var _CCSettings = null;function boot() {var settings = _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 < scenes.length; ++i) { var scene = scenes[i]; if (typeof scene.uuid === 'number') { scene.uuid = uuids[scene.uuid]; } } var packedAssets = settings.packedAssets; for (var packId in packedAssets) { var packedIds = packedAssets[packId]; for (var j = 0; j < packedIds.length; ++j) { if (typeof packedIds[j] === 'number') { packedIds[j] = uuids[packedIds[j]]; } } } } // init engine var canvas; if (cc.sys.isBrowser) { canvas = document.getElementById('GameCanvas'); } function setLoadingDisplay() { // Loading splash scene var splash = document.getElementById('splash'); var progressBar = splash.querySelector('.progress-bar span'); cc.loader.onProgress = function (completedCount, totalCount, item) { var percent = 100 * completedCount / totalCount; if (progressBar) { progressBar.style.width = percent.toFixed(2) + '%'; } }; splash.style.display = 'block'; progressBar.style.width = '0%'; cc.director.once(cc.Director.EVENT_AFTER_SCENE_LAUNCH, function () { splash.style.display = 'none'; }); } var onStart = function () { cc.view.resizeWithBrowserSize(true); // UC browser on many android devices have performance issue with retina display if (cc.sys.os !== cc.sys.OS_ANDROID || cc.sys.browserType !== cc.sys.BROWSER_TYPE_UC) { cc.view.enableRetina(true); } //cc.view.setDesignResolutionSize(settings.designWidth, settings.designHeight, cc.ResolutionPolicy.SHOW_ALL); if (cc.sys.isBrowser) { setLoadingDisplay(); } if (cc.sys.isMobile) { if (settings.orientation === 'landscape') { cc.view.setOrientation(cc.macro.ORIENTATION_LANDSCAPE); } else if (settings.orientation === 'portrait') { cc.view.setOrientation(cc.macro.ORIENTATION_PORTRAIT); } // qq, wechat, baidu cc.view.enableAutoFullScreen( cc.sys.browserType !== cc.sys.BROWSER_TYPE_BAIDU && cc.sys.browserType !== cc.sys.BROWSER_TYPE_WECHAT && cc.sys.browserType !== cc.sys.BROWSER_TYPE_MOBILE_QQ ); } // Limit downloading max concurrent task to 2, // more tasks simultaneously may cause performance draw back on some android system / brwosers. // You can adjust the number based on your own test result, you have to set it before any loading process to take effect. if (cc.sys.isBrowser && cc.sys.os === cc.sys.OS_ANDROID) { cc.macro.DOWNLOAD_MAX_CONCURRENT = 2; } // init assets cc.AssetLibrary.init({ libraryPath: 'res/import', rawAssetsBase: 'res/raw-', rawAssets: settings.rawAssets, packedAssets: settings.packedAssets, md5AssetsMap: settings.md5AssetsMap }); var launchScene = settings.launchScene; // load scene if (cc.runtime) { cc.director.setRuntimeLaunchScene(launchScene); } cc.director.loadScene(launchScene, null, function () { if (cc.sys.isBrowser) { // show canvas canvas.style.visibility = ''; var div = document.getElementById('GameDiv'); if (div) { div.style.backgroundImage = ''; } } cc.loader.onProgress = null; // play game // cc.game.resume(); console.log('Success to load scene: ' + launchScene); } ); }; // jsList var jsList = settings.jsList; var bundledScript = settings.debug ? 'project.dev.js' : 'project.js'; if (jsList) { jsList.push(bundledScript); } else { jsList = [bundledScript]; } // anysdk scripts if (cc.sys.isNative && cc.sys.isMobile) { // jsList = jsList.concat(['jsb_anysdk.js', 'jsb_anysdk_constants.js']); } jsList = jsList.map(function (x) { return cc.INGAME + 'src/' + x; }); var option = { //width: width, //height: height, id: 'GameCanvas', scenes: settings.scenes, debugMode: settings.debug ? cc.DebugMode.INFO : cc.DebugMode.ERROR, showFPS: settings.debug, frameRate: 60, jsList: jsList, groupList: settings.groupList, collisionMatrix: settings.collisionMatrix, renderMode: 0 }; cc.game.run(option, onStart); } if (window.document) { var splash = document.getElementById('splash'); splash.style.display = 'block'; var cocos2d = document.createElement('script'); cocos2d.async = true; cocos2d.src = window._CCSettings.debug ? 'cocos2d-js.js' : 'cocos2d-js-min.js'; var engineLoaded = function () { document.body.removeChild(cocos2d); cocos2d.removeEventListener('load', engineLoaded, false); window.eruda && eruda.init(); boot(); }; cocos2d.addEventListener('load', engineLoaded, false); document.body.appendChild(cocos2d); } else if (window.jsb) { console.log('返回大厅======================================='); if (!cc.dating) { cc.dating = _CCSettings = require(cc.INGAME + 'src/settings.js'); require(cc.INGAME + 'src/project.js'); } else { _CCSettings = cc.dating; } boot(); } })(); 

可以看到dating.js的逻辑相比子游戏的main.js的代码只是把路径修改到大厅的目录,然后执行大厅的配置文件。

然后一个非常粗略的大跟子游戏相互跳转的功能就完成了。如果后续需要对子游戏跟大厅分别进行更新跟管理的话需要自行扩展了。。

cocos creator大厅、子游戏实现方案相关推荐

  1. cocos creator 大厅+子游戏模式探讨(creator版本1.8.2)

    之前一直从事android开发,接触cocos creator不久.近期公司安排我研究大厅子游戏模式的热更新,前后花了近一周时间,在论坛上查资料,请教大神,期间得到了一些帮助,在此很感谢cocos中文 ...

  2. cocos creator 大厅 ➕ 子游戏(子游戏作为单独的项目更新)

    先标记上文章的出处,嘿休嘿,感谢这位:https://www.jianshu.com/p/fe54ca980384 cocos creator版本: 1.9.1 首先建立大厅的项目 添加文件  Sub ...

  3. CocosCreator大厅+子游戏+热更新方案

    转载自:https://www.jianshu.com/p/efee9f5937a3 前言 随着游戏的玩法越来越多,也就意味着包体越来越大,对于玩家来说,首次下载的包体就会越来越大,从而也会增加首次启 ...

  4. CocosCreator 2.4.3热更新实现方案(AssetBundle),大厅+子游戏模式快速实现

    _ 实现功能 项目环境 关于 Asset Bundle 实现过程 工程结构 快速使用代码 构建发布 Creator 构建 制作热更新资源 制作随包发布模块 测试功能 模块完整下载 windows下测试 ...

  5. Cocos Creator子游戏动态下载实现(大厅+子游戏模式)

    热更新 在App开发过程中,当一个App发布之后,突然发现了一个严重bug需要进行紧急修复,这时候公司各方就会忙得焦头烂额:重新打包App.测试.向各个应用市场和渠道换包.提示用户升级.用户下载.覆盖 ...

  6. Cocos Creator AssetBundle 游戏分包方案评估

      Cocos Creator 2.0 之后推出了AssetBundle系统,类似于Unity3D的AssetBundle.先简单讲一下AssetBundle的原理作用,不涉及具体引擎的具体细节,各个 ...

  7. 15个 Cocos Creator 技术解决方案免费开源!更多资源持续更新中…

    期望的游戏效果不知该如何实现?被繁琐的操作劝退?想要提升开发效率?应广大开发者的需求,Cocos 技术支持团队将持续为大家整理提供一些实用的技术解决方案,通通免费开源! 这些方案部分来自 Cocos ...

  8. 初识cocos creator,做一款H5小游戏

    分享内容预览 小游戏体验. cocos creator 前世今生. 基本开发环境的了解. 小游戏场景制作相关知识. 基础语法讲析. sunlands-cow demo的讲解. 构建,发布.(h5, 微 ...

  9. Cocos Creator 的 web/原生多平台 Spine 换装方案解析,附 Demo 源码

    引言:Spine 换装是游戏开发中的一种常见实现方案,本次,羽毛先生将介绍自己对整体换装和局部换装实现方案的探索与选择. 运行环境 Cocos Creator 3.5.2 web/native 需求 ...

最新文章

  1. 电力巡检智能管控主站平台性能优化(一):数据采集及用户行为分析
  2. SharedPreferences的使用
  3. jdbc版本怎么看_Jmeter(十三)-JDBC脚本开发
  4. 小强系列之大话移动测试
  5. 步步为营:Asp.Net序列化Json格式的两种方法
  6. /usr/include/sys/types.h基本系统数据类型
  7. Highcharts使用表格数据绘制图表
  8. python数据库操作sqlite_Python3操作SQLite数据库
  9. php框架tp3.2.3和js写的微信分享功能心得,分享的标题内容图片自定义
  10. texlive for win10宏包更新
  11. c语言自动按键脚本,纯C语言写的按键驱动,将按键逻辑与按键处理事件分离~
  12. 在线web工具pdf转word工具推荐【磁钉pdf转word】
  13. 特殊符号html怎么打出来的,特殊符号怎么打出来
  14. 计算机系统与配置要求,电脑系统以及Adobe Audition的版本配置要求-喜马拉雅
  15. 改变思维(深度学习)
  16. 快手投放:快手电商留存分析
  17. Python中print换行问题
  18. 机器学习(十八)应用实例:照片OCR
  19. OpenStack关键技术系列: 最全OpenStack知识科普
  20. 常用的css特效(一)

热门文章

  1. 2023.1.18单词打卡
  2. fatal: ‘main‘ does not appear to be a git repository fatal: Could not read from remote repository.
  3. 无限火力是哪个服务器2019,LOL2019无限火力国服上线时间 LOL2019无限火力什么时候开?...
  4. java二维数组初始化(java二维数组初始化的三种方式)
  5. vue watch 修改滚动条_vue实现滚动监听,点击瞄点平滑滚动,控制内嵌滚动条滚动...
  6. 学计算机了情话,经典情话_甜言蜜语_表白的话_结婚祝福语_爱情宣言句子_情诗绝句_暧昧短信大全...
  7. 导出简单Excel模板(通用)
  8. 小程序仿微视_微信小程序仿抖音,微视上下滑动整屏切换视频带关注,收藏
  9. [计算机网络笔记06] 集线器和交换机的区别
  10. 软件破解逆向安全(三)初识HOOK