一、引擎版本
2.4.0正式版
二、概念简述 详细描述
Bundle即为包,将cc.Asset资源如: Texture, AudioClip, Prefab, Scripts...封装在一个容器里。
三、Bundle的优势
1. 模块划分清晰,一包一世界,具有完善性,独立性,复用性
2. 减少首包大小,之前都是构建在settings里面,bundle模式下,拆分到各bundle下的config.json里
3. 热更处理将更加简单
四、简单演示
加载变迁史:cc.loader -> cc.assetManager
接口关系: cc.loader == cc.resources === cc.assetManager.getBundle(‘resources’)
大厅 + 子游戏,或者 多个功能独立热更的项目结构,升级后不建议将全部资源放置在resources目录下,也不建议使用cc.resources接口进行资源加载(resources是一个内置bundle,在main.js中默认加载不需要的可以修改这个地方),更多的应该是使用:
- 已加载过bundle: cc.getBundle(‘xxx’).load(“资源相对路径”)
- 未加载过bundle: cc.assetManager.loadBundle(“xxx”, (err, bundle)=> bundle.load(“资源相对路径”))
这里简单演示A精灵的spriteFrame应该如赋值,假设资源路径assets/games/xxx/res/image/bg.jpg
//未加过载bundle,勾选了MD5 Cache 这里传入最新版本号:
cc.assetManager.loadBundle("xxxOrRemotexxxl", {version: 'abcdef'}, (err, bundle)=> {
bundle.load("res/image/bg", cc.SpriteFrame, (err, frame) => A.spriteFrame = frame);
});
//已加载过bundle:
A.spriteFrame = cc.assetManager.getBundle("xxx->注意这里只能是名称而不是Remotexxxl").get("res/image/bg", cc.SpriteFrame);
五、注意事项
1. 防止脚本重名,类重名
当重名时,引擎底层将抛出异常。为了防止错误或代码覆盖情况,良好的解决方案是添加脚本前缀,如:XXXMain, XXXGameManager, XXXDefine
2. 类重名
//A包:A.ts
class MyTest { }
window.MyTest = MyTest;
//B包: B.ts
class MyTest { }
//覆盖A的MyTest
window.MyTest = MyTest;
3. 插件脚本不入包
某脚本在属性面板中应用了导入为插件,那么此脚本将不能并入bundle的index.js中,在bundle的加载操作中,除了下载config.json,同时也下载并执行了index.js脚本,此时index.js脚本的中并没有插件脚本,但引用了插件中的脚本,那么将抛出 xxx undefine 异常
解决方案:
- 取消导入为插件,你需要清楚知道插件脚本与普通脚本的区别
- 扩展构建流程,在onBuildFish的回调里将插件脚本并入index.js的头部
'use strict';
var path = require('path');
var fs = require('fs');
const libPath = "assets/games/public/scripts/3rd/lib.js";
function onBeforeBuildFinish (options, callback) {
let bundle = options.bundles.find(t => t.name =="public");
if(!bundle) callback();
let libSrc = path.join(Editor.Project.path,libPath);
let destScript = path.join(bundle.scriptDest, "index.js");
let libContent = fs.readFileSync(libSrc);
let destContent = fs.readFileSync(destScript);
let newContent = libContent + destContent;
fs.writeFileSync(destScript, newContent, {encoding: 'utf-8', flag: 'w'});
callback();
}
module.exports = {
load () {
Editor.Builder.on('before-change-files', onBeforeBuildFinish);
},
unload () {
Editor.Builder.removeListener('before-change-files', onBeforeBuildFinish);
},
};
4. 碰撞分组不入包
解决方案:
- 在构建流程中,将settings里的groupIndex与collisionMatrix追加到index.js中
- 在游戏逻辑中,自行添加碰撞信息, 如下所示:
/**
* 当初始化
*/
protected onInit(): void {
super.onInit();
//碰撞分组目前引擎是在构建时候记录在settings文件夹下,bundle模式下获取不到,需要自行添加处理
cc.game["groupList"] = ["default", "aa", "bb"];
cc.game["collisionMatrix"] = [[false, true],[true, false],[false, false, false]];
}
5. 项目模块裁剪(分工程模式)
当模块裁剪后,子包却用到了裁剪的模块将不能正常运转逻辑
6. 勾选MD5 Cache后,加载时携带最新版本号(分工程)
因为存在多个工程,各工程构建发布时,引擎将bundleVersion记录在各自工程的主
settings里,我们除非将自身工程中settings里的BuildVersion同步到主工程(通用大厅版本的工程)的settings里,才可以不传version,否则需要传版本号,但是这样的操作对热更情况不太友好,我们应该是在服务器上配置bundle对应的版本,使用的时候传入最新的版本号(Hash)。
cc.assetManager.loadBundle("xxx或者fishRemotexxx", {version: 'abcdef'}, (err, bundle)=> {
bundle.load("res/image/bg", cc.SpriteFrame, (err, frame) => A.spriteFrame = frame);
});
六、【分工程】还是【同工程分文件夹】研发
- 同工程下,公共部分能正确、快速同步
- 同工程下,客户端管理人员能便利的review code,review resources
- 同工程下,脚本重名引擎会自动添加序号,TS类重名VSCode会报错提示已存在类
- 分工程下,能确保各bundle之间不会依赖,保证独立性
- 分工程下,公共部分最好使用git,svn来部署单独目录,便于拉取
七、发布流程(Web-Mobile)
- 构建发布
- 将构建后的bundle上传至服务器地址