游戏开发之资源加载管理器

前言

在我的框架中一直没有提供加载相关的内容。因为我觉得资源管理器的接口都已经提供了,而资源怎么加载是一件相对比较灵活的事情,所以一直没有提供与加载相关的内容。但是后来居然不止一个人问我如何加载资源?于是我将自己的使用方式简单讲解一下。如果有什么不对的地方,还望大家留言指教。

注意事项

  • 加载的资源是由哪个Bundle提供的?
  • 加载的资源的类型是什么?
  • 不同类型的资源加载后是否有特殊的操作?
  • 同步加载还是异步加载?
  • 有些资源加载失败了会如何处理?
  • 资源加载的顺序是怎样的

问题解析

  1. 对于第一个问题,我们必须要明确我们加载的资源隶属于哪个Bundle。否则加载肯定会因报错而失败。所以普通资源肯定是要在Bundle加载之后的。对于Bundle如何组织请看我之前的文章《CocosCreator之AssetBundle使用方案分享》。对于资源如何加载请看我之前的文章《游戏开发之资源管理(跨引擎)》
  2. 资源的类型也是需要指定的。即使有些引擎没有类型这个概念,你为了统一使用也可以自定义一套类型。比如我的资源管理器使用的就是我自己定义的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;
    }
}
  1. 不同类型的资源加载后是否有特殊的操作?
    比如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();
        }

    }
  1. 同步加载还是异步加载?
    如果引擎支持异步加载当然是使用异步加载,如果不支持那就只能一个一个加载了。
    下面给出一个同步加载的例子。
    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()
            }

        }
    }
  1. 有些资源加载失败了会如何处理?
    我会将加载失败的资源放入一个列表中,当所有资源加载完毕后判断错误资源列表的长度,如果长度为零,加载结束,如果不为零,弹出提示,是否加载这些失败的资源,如果不加载直接退出游戏。
            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()
            }
  1. 资源加载的顺序是怎样的?
    首先还是要加载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《微笑游戏》,浏览更多内容。

你可能感兴趣的:(游戏开发之资源加载管理器)