前言
在我的框架中一直没有提供加载相关的内容。因为我觉得资源管理器的接口都已经提供了,而资源怎么加载是一件相对比较灵活的事情,所以一直没有提供与加载相关的内容。但是后来居然不止一个人问我如何加载资源?于是我将自己的使用方式简单讲解一下。如果有什么不对的地方,还望大家留言指教。
注意事项
- 加载的资源是由哪个Bundle提供的?
- 加载的资源的类型是什么?
- 不同类型的资源加载后是否有特殊的操作?
- 同步加载还是异步加载?
- 有些资源加载失败了会如何处理?
- 资源加载的顺序是怎样的
问题解析
- 对于第一个问题,我们必须要明确我们加载的资源隶属于哪个Bundle。否则加载肯定会因报错而失败。所以普通资源肯定是要在Bundle加载之后的。对于Bundle如何组织请看我之前的文章《CocosCreator之AssetBundle使用方案分享》。对于资源如何加载请看我之前的文章《游戏开发之资源管理(跨引擎)》
- 资源的类型也是需要指定的。即使有些引擎没有类型这个概念,你为了统一使用也可以自定义一套类型。比如我的资源管理器使用的就是我自己定义的ResType.是与任何引擎都无关的。当然每个资源还有一个url属性。加上资源属于哪个Bundle,刚好有三个属性。
import { ResType } from "./ResInterface";
export default class LoadingItem {
//资源id
protected url: string;
//资源类型
protected type: ResType;
constructor(url: string, type: ResType) {
this.url = url;
this.type = type;
}
getUrl() {
return this.url;
}
getType() {
return this.type;
}
}
export default class LoadResItem extends LoadingItem {
//BundleID
protected moduleID: string;
constructor( url: string, type: ResType,mid: string) {
super(url, type)
this.moduleID = mid;
}
getModuleID() {
return this.moduleID;
}
}
- 不同类型的资源加载后是否有特殊的操作?
比如bundle加载完需要初始化,配置文件加载完需要放入数据管理器等。
loadingFinish(): void {
for (let index = 0; index < this.resList.length; index++) {
const element = this.resList[index];
let type = element.getType()
let url = element.getUrl()
switch (type) {
case ResType.AssetBundle:
let res = ModuleManager.getLoader(element.getModuleID()).getRes(url, type)
ModuleManager.setLoaderByBundle(url, res)
break;
case ResType.Json:
let data = ModuleManager.getLoader(element.getModuleID()).getRes(url, type)
ModuleManager.addFile(data)
break;
case ResType.Prefab:
break;
}
}
this.resList.length = 0;
if (this.callback) {
this.callback();
}
}
- 同步加载还是异步加载?
如果引擎支持异步加载当然是使用异步加载,如果不支持那就只能一个一个加载了。
下面给出一个同步加载的例子。
loadSync() {
if (this.totalCount != 0) {
this.progressBar$VSprite.progress = (this.totalCount - this.loadingList.length) / this.totalCount;
}
if (this.loadingList.length > 0) {
let loadingitem = this.loadingList.shift()
ModuleManager.getLoader(loadingitem.getModuleID())
.loadRes(loadingitem.getUrl(), loadingitem.getType(), (err, item: ResItem) => {
if (err) {
this.errorList.push(loadingitem)
}
this.loadSync()
})
} else {
if (this.errorList.length > 0) {
//有加载失败的,弹出提示是否继续加载
TipC.instance().showTip(GameText.RES_LOAD_ERROR, (s: ResultState) => {
if (s == ResultState.YES) {
this.reset(this.errorList.slice(0))
this.errorList.length = 0;
this.loadSync()
} else {
cc.game.end()
}
})
} else {
this.controller.loadingFinish()
}
}
}
- 有些资源加载失败了会如何处理?
我会将加载失败的资源放入一个列表中,当所有资源加载完毕后判断错误资源列表的长度,如果长度为零,加载结束,如果不为零,弹出提示,是否加载这些失败的资源,如果不加载直接退出游戏。
if (this.errorList.length > 0) {
//有加载失败的,弹出提示是否继续加载
TipC.instance().showTip(GameText.RES_LOAD_ERROR, (s: ResultState) => {
if (s == ResultState.YES) {
this.reset(this.errorList.slice(0))
this.errorList.length = 0;
this.loadSync()
} else {
cc.game.end()
}
})
} else {
this.controller.loadingFinish()
}
- 资源加载的顺序是怎样的?
首先还是要加载resource下的资源和进入游戏就需要用到的分包。等这些资源加载完毕后,如果需要加载分包中的资源再重新加载一次分包中的资源。如果有些模块用到的Bundle并不是一进入游戏就需要的,那么我们就可以在使用时加载。
intoLayer() {
if (ModuleManager.hasLoader(ModuleID.LOBBY)) {
this.showView();
} else {
LoadingC.instance().addItem('data/game_info', ResType.Json, ModuleID.RES)
LoadingC.instance().addItem('data/pet_info', ResType.Json, ModuleID.RES)
LoadingC.instance().addItem('data/prop_info', ResType.Json, ModuleID.RES)
LoadingC.instance().addItem('data/ai_info', ResType.Json, ModuleID.RES)
LoadingC.instance().addItem('data/audio_info', ResType.Json, ModuleID.RES)
LoadingC.instance().addItem('data/guide_config', ResType.Json, ModuleID.RES)
LoadingC.instance().addItem('data/clothe_info', ResType.Json, ModuleID.RES)
LoadingC.instance().addItem('guide/GuideView', ResType.Prefab, ModuleID.RES)
let matrix = SDKManager.getChannel().getMatrix();
let list = null;
if (matrix) {
list = [ModuleID.LOBBY, ModuleID.PET, ModuleID.PROPS, ModuleID.CRAZY_CLICK, ModuleID.AUDIO, ModuleID.PUBLIC]
} else {
list = [ModuleID.LOBBY, ModuleID.PET, ModuleID.PROPS, ModuleID.AUDIO, ModuleID.PUBLIC]
}
LoadingC.instance().addItemList(list, ResType.AssetBundle, ModuleID.RES)
LoadingC.instance().intoLayer(() => {
this.loadProps()
})
}
}
loadProps() {
let list = PropMgr.instance().getActiveProps()
for (let index = 0; index < list.length; index++) {
const element = list[index];
LoadingC.instance().addItem(element.getPrefab(), ResType.Prefab, ModuleID.PROPS)
}
let petlist = PetMgr.instance().getPetItemModelList()
for (let index = 0; index < petlist.length; index++) {
const element = petlist[index];
if (element.getState() == ItemState.GOT) {
LoadingC.instance().addItem(element.getPrefab(), ResType.Prefab, ModuleID.PET)
}
}
LoadingC.instance().addItem('prefabs/PropView', ResType.Prefab, ModuleID.PUBLIC)
LoadingC.instance().addItem('prefabs/PetView', ResType.Prefab, ModuleID.PUBLIC)
LoadingC.instance().reload(() => {
let matrix: MatrixMgr = SDKManager.getChannel().getMatrix();
if (matrix && matrix.firstExport()) {
BigExportC.instance().intoExportLayer(0, UIIndex.ROOT, () => {
BigExportC.instance().intoExportLayer(1, UIIndex.ROOT, () => {
this.showView();
})
})
} else {
this.showView()
}
});
}
结语
以上是我个人使用的加载方式,希望分享出来对大家有所启发。如有错误请不吝赐教。
欢迎关注微信公众号《微笑游戏》阅读更多精彩内容
欢迎关注GZH《微笑游戏》,浏览更多内容。