等待大佬更新
动态加载预制体
我们在上节中遇到了一个问题:如何动态加载预制体的问题。
在官方的 API 中,通过代码动态加载预制体的方式是:通过 bundle 提供的加载 API。
参考官方文档 加载资源
我们先使用官方的方案去完成功能,在后面的一节,我再来说一下,为什么我们不要去用官方的 resources 这个 bundle 包,而应该去用一个更通用的解决方案。
首先,我们在 assets 目录下新建 resources 目录,编辑器自动识别文件夹名称后,把它标记为一个 bundle 包,并默认其优先级为 8。
然后我们将预制体 Match3UI.prefab 拖拽到 resources 文件夹中。
然后删除 Canvas 节点的 Boost 组件中关联的预制体:
在 Boost.ts 脚本文件中,我们删除这行:
@property(Prefab) private match3Prefab: Prefab = null;
将 this.scheduleOnce
方法中的内容更改为:
this.scheduleOnce(() => {
resources.load("Match3UI", Prefab, (err, prefab: Prefab) => {
if (err) {
console.error(err);
return;
}
let match3Node = instantiate(prefab);
this.node.addChild(match3Node);
match3Node.getComponent(UITransform).setContentSize(G_VIEW_SIZE.clone());
})
}, 1)
重新运行后,发现预制体被动态加载了。
这样,我们就通过动态加载预制体的方式,移除了启动场景的资源依赖。
但是为什么我仍然说不要去用 resources 包呢?这个观点,我在下一节中会进行阐述。
等有空了再更新吧,写教程比较费时间。争取一天一篇左右的节奏
支持一下!
昨天傍晚的时候,修改历史的文章,经常出现 502 Bad Gateway ,很抓狂。早上起来又不会了。
牛逼mark
牛逼牛逼mark
资源整理
在上节中,我们使用了官方的 resources bundle 包动态加载了 Prefab 资源。
resources 是一个 bundle 包,它既然在 Boost.ts 脚本中可以直接使用,说明其是在启动环节加载的。
想了解引擎是如何加载的,可以自行查看官方的引擎源码: 获取引擎源码
git clone -b v3.8.5 https://github.com/cocos/cocos-engine.git --depth 1
现在的第一个问题是:resources 包里面如果脚本、预制体、json 相关的配置等资源很多的话,它会影响首屏的启动时间。
或者说直接一点, resources 凭什么要在首场景加载?
以下是个人看法:
因为这个官方给新手菜鸟去使用的,新手会遇到很多问题,其中一个就是资源动态加载(尤其是图片资源动态加载),如果不提供 resources 目录,新手要先加载 bundle,然后将这个 bundle 保存在某个地方,使用的时候再去用这个 bundle 去加载。
不要小看多了这一层,直接劝退部分新手:加载个东西还要这么麻烦?垃圾引擎。
所以官方不得不加这层,降低使用门槛。
所以,作为老鸟,可以这么说吧,如果使用 bundle 包有鄙视链,那还在使用 resources 包的开发者,就很容易被鄙视。
继续刚刚的话题,resources 最优的情况下,是不应该在首屏的时候加载好的。它应该是我们业务逻辑层去动态加载的。
所以,这里我们将这个 resources 包替换成另一个包,这里不妨叫【Match3BN】包。
因此,我们在 assets 文件夹下创建一个新的文件夹,命名为 Match3,选中 Match3 文件夹,勾选上【配置为 Bundle】复选框。
Bundle 的名称更改为 Match3BN,优先级我们先保持不变(关于优先级,它影响到一些资源的打包归属,特别是被多个包共用的资源,以及被其它包引用的代码的情况,这个是后话,可参考官方文档 Asset Bundle 优先级)。
接下来我们吧之前的 Match3UI.prefab 预制体移动到这个 Match3BN 包中。
同时也把 yang 文件夹移动到这个 Match3 文件夹中。
删除 resources 文件夹
然而我们的首场景的 BG 节点,引用了 bundle 包 Match3BN 中的资源 bg_2x2,因此。我们的这个资源,需要复制一份出来。
因此我们在 assets 文件夹下,新建 Boost 文件夹,然后点击选中 bg_2x2,Ctrl+C 复制它,然后在 Boost 文件夹中 Ctrl + V 创建一个副本。最后,将这个新的bg_2x2副本,拖拽到 Canvas 节点下的 BG 精灵的 sprite-frame 属性上。
这样,我们就完成了资源的解耦:
首场景只用 Boost 文件夹下的资源。
Match3BN 包中的预制体 Match3UI.prefab 只用到了自己包中的资源。
最后,我们要修改一下之前的加载脚本:
this.scheduleOnce(() => {
assetManager.loadBundle("Match3BN", (e, bundle) => {
bundle.load("Match3UI", Prefab, (err, prefab: Prefab) => {
if (err) {
console.error(err);
return;
}
let match3Node = instantiate(prefab);
this.node.addChild(match3Node);
match3Node.getComponent(UITransform).setContentSize(G_VIEW_SIZE.clone());
})
})
}, 1)
刷新后重新运行,完美的实现了。
支持
后面会有游戏逻辑的教程吗,大佬。
会,整个游戏的实现。但是要先构建出 UI 管理器、资源管理器,抽象成框架,这个是怎么从 0 到 1 的。要把这个东西讲清楚,要很多节呢。
赞赞赞赞赞赞赞赞赞
赞赞赞赞赞赞赞赞赞
老哥,拿你这个项目作为我找工作demo了,期待更新
那你可能要明年找工作了
我是打算明年找的
这个帖子写完是不是会得到一个super writer title
顺其自然,有最好,哈哈
关于框架的意义和演变
在上一节中,我们自己创建了一个名为【Match3BN】的 Asset Bundle 。我们进入玩法界面的时候,先加载了 Match3BN 包,再通过这个包去加载包内的预制体,最后实例化出了玩法界面。
后续我们继续加载其它预制体的时候,比如说羊了个羊的棋子预制体,也是要重复这个加载流程。
而这个流程,我们一般会抽象成资源加载模块的某个方法。并且这个资源加载模块,在我们做下个游戏的时候,也是能够【复用】的。
因此,为了【复用】我们的劳动成果,我们将这些东西抽象成了:
1、【库】
2、【框架】
3、【工具】
4、【解决方案】
我们所使用的 Cocos Creator 本身就是游戏开发沉淀下来的解决方案,当然,它肯定是包含了各种工具、框架和库的。
粒度更小的就是论坛里近期比较火热的几个框架:
鹤九日 oops-framework
马赛克 MKFramework
向前 XForge
当然还有很多已实现财富自由的老鸟们留下的框架,这里不在赘述,感谢这些大牛们愿意分享自己的劳动成果,本人的一些实现,也是受到了这些框架的启发和影响。
这些框架存在的意义就是:【复用】。
所谓的效率提升,本质就是复用,复用就是使用之前做过的东西,不用重新制造。所谓的开发效率高、生产力高,其底层逻辑就是【复用】逻辑,所谓站在前人的肩膀上,就是这个意思。
本教程是新手向的,这些框架对他们而言,其实会遇到使用上的困难。如果没有人教或者讲解,对他们而言,使用门槛还是很高的。
所以,我这边会以演变的形式,慢慢的抽象出一套 Framework,让新手不用走弯路,至少了解我本人的这套框架是如何演变出来的。
因此从资源管理入手,我们开始我们的抽象工作。
资源管理器
资源管理器 ResManager
首先进入我们框架演变的第一步,引入单例模式的 ResManager。
事实上,演变到最后,我们的游戏中,不会出现 XXManager.getInstance() 这种单例使用模式的。
我们在 assets 目录下新建 fw 文件夹,在其中新增 res 文件夹,在该文件夹下新建 ResManager.ts 文件,在其中添加以下代码,使其成为一个单例模式的类
/** 单例模式的资源管理器 */
export class ResManager {
private static _instance: ResManager = null!;
/** 获取单例的接口 */
static getInstance() {
if (this._instance === null) {
this._instance = new ResManager();
}
return this._instance;
}
private constructor() {
// 私有化的构造函数
}
}
接下来,将之前加载玩法界面预制体的接口移动到资源管理器中,并同步修改加载接口:
1、ResManager.ts 中,新增方法:
private constructor() {
// 私有化的构造函数
}
loadPrefab(bundleName: string, prefabPath: string, cb: (prefab: Prefab | null) => void) {
assetManager.loadBundle(bundleName, (e, bundle) => {
bundle.load(prefabPath, Prefab, (err, prefab: Prefab) => {
if (err) {
console.error(err);
cb(null);
return;
}
cb(prefab)
})
})
}
2、Boost.ts 中同步修改
this.scheduleOnce(() => {
ResManager.getInstance().loadPrefab("Match3BN", "Match3UI", prefab => {
let match3Node = instantiate(prefab);
this.node.addChild(match3Node);
match3Node.getComponent(UITransform).setContentSize(G_VIEW_SIZE.clone());
})
}, 1)
运行后,表现如初,一切正常。
当然,这仅仅是开始。目前 ResManager 并不完善,但至少我们完成了逻辑依赖的迁移:
资源的加载从【依赖引擎 API 】转化为【依赖框架层 API】。
这种依赖的迁移,也是我们编写框架的其中一个意义。