简述小游戏-动态-资源管理方案

引擎:CocosCreator。 语言: TS

前言:最近一个朋友和我聊天吐槽了一下cocosCreator的资源管理问题并问我有没有好的管理方案和方法,但我认为他并没有真正去尝试做一下而是人云亦云的在叙述给我听~没劲!,所以我花了2小时浏览了一下官方文档和尝试,并给了这位朋友回复;记录下来希望能够抛砖引玉获得大家更优秀的方案。

在这里插入图片描述

一、静态资源引用的管理

二、动态资源引用的管理

  • 看一下引擎为我们提供的资源释放接口:
    在这里插入图片描述

根据上面释放接口我们可以梳理成两种方式进行管理:
1、使用第一中方式,引用计数我们自定义,然后自己进行管理增加和减少,当自定义对应的资源的引用计数为0,我们手动调用资源释放接口。(不建议使用,使用比较复杂但是可正常实现资源管理)
2、我们只需要调用addRef增加引用计数,decRef减少引用计数,当引用为0的时候系统自动给我们清理。(推荐使用)

  • 如何验证资源是否被释放掉?
        //打印内存中所有的资源,可通过uuid去进行查找
        cc.assetManager.assets; 
        //内置bundle的get方式去查找对应资源类型
        cc.resources.get('path/name',cc.SpriteFrame);
  • 使用内置bundle和资源图集/图片/预制体为案例封装了一下关于资源释放,其他类型资源和其他bundle都差不多,可自行整理(建议:按场景、界面、窗口等单位去释放,而不是当一个小怪物死亡后立马就进行释放,虽然这样也可以)。
//*********************************************************//
//重点说一下这:
//因为内存中只包含一份资源,所以我的思路是:只要资源在内存中,引用计数最大是1;

//if (_asset.refCount <= 1) { _asset.addRef(); } //图片资源refCount+1
//因为图集加载进来给图集addRef()后,图集内所有的图片资源refCount都是1了,然后又对使用到的图集中图片进行addRef();目的是为了防止释放图集的时候把图片同样给释放掉。
//图片我们是进行统一释放管理的。

//释放我们提供了释放所有和释放单个,根据自己的需求进行调用。
//*********************************************************//
export default class AssetManager {
    private cachSpriteAtlas: Map<string, cc.SpriteAtlas> = new Map();
    private cachSpritFrames: Map<string, cc.SpriteFrame> = new Map();
    private cachPrefabs: Map<string, cc.Prefab> = new Map();
    //......
    //音频、数据、粒子、动画等Map资源容器
    /**
     * 内置bundle动态管理加载图集资源函数
     * @param assetPath  图集路径
     * @param assetName  图片名称
     * @param assetType  资源类型-图集类型
     * @param onComplete 完成回调
     */
    public loadByResources_SpriteAtlas(assetPath: string, assetName: string, assetType: typeof cc.Asset, onComplete: (err: Error, asset: cc.Asset) => void) {
        let _assetAtlas = <cc.SpriteAtlas>cc.resources.get(assetPath, assetType); //感觉没有什么卵用,可能读取到后会快一下。 留着吧
        if (_assetAtlas) {
            let _asset = _assetAtlas.getSpriteFrame(assetName);
            if (_asset && onComplete) { onComplete(null, _asset); }

            if (_asset.refCount <= 1) { _asset.addRef(); } //图片资源refCount+1
            if (!this.cachSpritFrames.get(assetName)) { this.cachSpritFrames.set(assetName, _asset); }
        }
        else {
            cc.resources.load(assetPath, assetType, (err: Error, assetAtlas: cc.Asset) => {
                if (err) {
                    console.warn("Error:", err);
                    return;
                }

                _assetAtlas = <cc.SpriteAtlas>assetAtlas;
                let _asset = _assetAtlas.getSpriteFrame(assetName);
                if (_asset && onComplete) { onComplete(err, _asset); }

                if (_assetAtlas.refCount == 0) { _assetAtlas.addRef(); } //图集资源refCount+1
                if (_asset.refCount <= 1) { _asset.addRef(); } //图片资源refCount+1
                if (!this.cachSpriteAtlas.get(assetPath)) { this.cachSpriteAtlas.set(assetPath, _assetAtlas); }
                if (!this.cachSpritFrames.get(assetPath + '/' + assetName)) { this.cachSpritFrames.set(assetPath + '/' + assetName, _asset); }
            })
        }
    }

    /**
     * 内置bundle动态管理加载非图集资源函数
     * @param assetPath 资源路径
     * @param assetType 资源类型
     * @param onComplete 完成回调
     */
    public loadByResources(assetPath: string, assetType: typeof cc.Asset, onComplete: (err: Error, asset: cc.Asset) => void) {
        let _asset: cc.Asset = cc.resources.get(assetPath, assetType);
        if (_asset) {
            if (onComplete) {
                onComplete(null, _asset);
            }
        }
        else {
            cc.resources.load(assetPath, assetType, (err: Error, asset: cc.Asset) => {
                if (err) {
                    console.warn("Error:", err);
                    return;
                }
                if (asset.refCount == 0) { asset.addRef(); }
                if (onComplete) { onComplete(err, asset); }

                if (assetType == cc.SpriteFrame) {
                    if (!this.cachSpritFrames.get(assetPath)) { this.cachSpritFrames.set(assetPath, <cc.SpriteFrame>asset); }
                }
                else if (assetType == cc.Prefab) {
                    if (!this.cachPrefabs.get(assetPath)) { this.cachPrefabs.set(assetPath, <cc.Prefab>asset); }
                }
            })
        }
    }

    /**
     * 释放类型资源
     * @param assetType 释放资源类型
     * @param path  释放的资源路径名称(默认=null,代表释放当前界面所有动态加载的资源类型)
     */
    public releaseByResources(assetType: typeof cc.Asset, path: string = null) {
        if (assetType == cc.SpriteAtlas) {
            this.releaseTypeAsset(this.cachSpriteAtlas, assetType, path);
        }
        else if (assetType == cc.SpriteFrame) {
            this.releaseTypeAsset(this.cachSpritFrames, assetType, path);
        }
        else if (assetType == cc.Prefab) {
            this.releaseTypeAsset(this.cachPrefabs, assetType, path);
        }
    }

    private releaseTypeAsset(cachAssets: Map<string, cc.Asset>, assetType: typeof cc.Asset, path: string) {
        if (path == null) {
            cachAssets.forEach((value, key) => {
                if (value) {
                    value.decRef();
                }
            })
            cachAssets.clear();
        }
        else {
            let _key: string = null;
            for (const [key, value] of Array.from(cachAssets.entries())) {
                if (key == path) {
                    _key = key;

                    if (value) { value.decRef();}
                    break;
                }
            }

            if(_key != null) {
                cachAssets.delete(_key);
            }
        }
    }
}


  • 因为我不想采用继承的方式去管理,所以记得在其他文件中使用的时候去初始化一下自己。比如:
其他文件.ts
 cc.Class NewClass{
    private assetManager: AssetManager = null;
    onLoad() {
        this.assetManager = new AssetManager();
    }
    start() {
        //动态加载预制体
        this.assetManager.loadByResources("item", cc.Prefab, (err, asset: cc.Prefab) => {
            let tempNode: cc.Node = cc.instantiate(asset)
            tempNode.parent = this.node;
            tempNode.position = cc.Vec3.ZERO;
        })
        //动态加载图片
        this.assetManager.loadByResources('UIImage/Bag_zhihuan', cc.SpriteFrame, (err, asset) => {
    
        });
        //动态加载图集图片
        this.assetManager.loadByResources_SpriteAtlas('UIImage/Bag', '100005', cc.SpriteFrame, (err, asset) => {
    
        });
    }

    onDestroy(){
        //释放对应类型动态加载的所有的资源
        this.assetManager.releaseByResources(cc.SpriteAtlas)
        this.assetManager.releaseByResources(cc.SpriteFrame)
        this.assetManager.releaseByResources(cc.Prefab)
        //释放单张资源(这里我根据的是路径去释放)
        this.assetManager.releaseByResources(cc.SpriteAtlas,'UIImage/Bag');//只释放这个图集
        this.assetManager.releaseByResources(cc.SpriteFrame,'UIImage/Bag_zhihuan')//只释放这张图片
        this.assetManager.releaseByResources(cc.SpriteFrame,'UIImage/Bag/100005') //只释放图集中的这张图片
        this.assetManager.releaseByResources(cc.Prefab, 'item')
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值