[CocosCreator]封装动态加载资源

       欢迎喜欢或者从事CocosCreator开发的小伙伴请加入我的大家庭CocosCreator游戏开发Q群:26855530

       使用过CocosCreator开发的小伙伴都知道,动态加载是用起来容易却不好管理的一大功能,稍微处理不当就很容易出现资源没有释放造成资源浪费,甚至内存泄露等问题.我写了一个管理动态加载资源的管理类,专门解决这类问题!如果哪里不对,欢迎指出,一起探讨

 直接进主题:

/**
 * 动态资源加载管理类
 */
class DynamicAssetManager {

    private _assetMap: Map<string, cc.Asset[]> = null;
    private _assetRefCountMap: Map<string, number> = null;

    /**
     * 初始化
     */
    init() {
        this._assetMap = new Map<string, cc.Asset[]>();
        this._assetRefCountMap = new Map<string, number>();
        cc.log("动态资源管理器初始化完成");
    }

    /**
     * 动态加载资源(可以同时加载多个资源)
     * @param node
     * @param url
     * @param callBackFun
     */
    load(node: cc.Node, url: string | string[], assetType: typeof cc.Asset, callBackFun: Function) {
        if (node && url) {
            if (Array.isArray(url))
                cc.resources.load(url, assetType, (err, assets: cc.Asset[]) => {
                    if (err) {
                        cc.error(err.message || err);
                        return;
                    }
                    if (this.pushAsset(node, assets)) {
                        callBackFun(assets)
                    }
                });
            else
                cc.resources.load(url, assetType, (err, asset: cc.Asset) => {
                    if (err) {
                        cc.error(err.message || err);
                        return;
                    }
                    if (this.pushAsset(node, asset)) {
                        callBackFun(asset)
                    }
                });
        }
    }

    /**
     * 动态加载目录全部资源
     * @param node
     * @param url
     * @param callBackFun
     */
    loadDir(node: cc.Node, url: string, assetType: typeof cc.Asset, callBackFun: Function) {
        if (node && url) {
            cc.resources.loadDir(url, assetType, (err, assets: cc.Asset[]) => {
                if (err) {
                    cc.error(err.message || err);
                    return;
                }
                if (this.pushAsset(node, assets)) {
                    callBackFun(assets)
                }
            });
        }
    }

    /**
     * 托管资源
     * @param node
     * @param asset
     */
    private pushAsset(node: cc.Node, asset: cc.Asset | cc.Asset[]): boolean {
        if (node && node.isValid) {
            let nodeId: string = node.uuid;
            if (!nodeId || !asset) {
                cc.log(`pushAsset参数不正确:nodeId:${nodeId},asset:${asset}`);
                return false;
            }
            if (asset instanceof Array) {
                for (let as of asset) {
                    this.extracted(as, nodeId);
                }
            } else {
                this.extracted(asset, nodeId);
            }
            return true;
        } else {
            if (asset) {
                cc.log(`老子还没加载完就被干掉了`);
                if (asset instanceof Array) {
                    for (let as of asset) {
                        as.decRef();
                    }
                } else {
                    asset.decRef();
                }
            }
            return false;
        }
    }

    private extracted(asset: cc.Asset, nodeId: string) {
        let assetArray: cc.Asset[] = this._assetMap.get(nodeId);
        if (!assetArray) {
            assetArray = [];
        }
        //同一个节点只增加一次计数
        if (assetArray.indexOf(asset) < 0) {
            asset.addRef();
            assetArray.push(asset);
            this._assetMap.set(nodeId, assetArray);
        }
    }

    /**
     * 释放资源
     * @param node
     * @param source
     */
    pullAsset(node: cc.Node, source: string) {
        if (node && node.isValid) {
            let nodeId: string = node.uuid;
            if (this._assetMap.has(nodeId)) {
                let assetArray: cc.Asset[] = this._assetMap.get(nodeId);
                for (let as of assetArray) {
                    cc.log(`释放资源:${as.name}`);
                    as.decRef();
                }
                this._assetMap.delete(nodeId);
            }
        } else {
            cc.error(`老子无法释放资源:传了个null(寂寞),源头:${source}`);
        }
    }

    /**
     * 当前资源种类数量
     */
    getSize() {
        return this._assetMap.size;
    }

    /**
     * 资源keys
     */
    getKeys() {
        return this._assetMap.keys();
    }
}

export default new DynamicAssetManager();

使用前先进行初始化(我这里用一个常驻节点统一进行处理)

import ResourceManager from "./ResourceManager";
import HeartBeatManager from "../network/HeartBeatManager";
import NetworkManager from "../network/NetworkManager";
import DynamicAssetManager from "./DynamicAssetManager";
import SoundManager from "./SoundManager";

const {ccclass} = cc._decorator;


/**
 * 游戏全局管理器
 */
@ccclass
export default class GameManager extends cc.Component {

    onLoad() {
        cc.game.addPersistRootNode(this.node);
        //cc.macro.ENABLE_MULTI_TOUCH = false;
        GameManager.initMgr(); //注册所有管理器
    }

    static initMgr() {
        DynamicAssetManager.init();//动态资源管理器

        SoundManager.init();//音频管理器

        ResourceManager.init(); //Protobuf资源管理器

        NetworkManager.init();//网路管理器

        HeartBeatManager.init(); //心跳管理器
    }
}

如何使用呢?

import DynamicAssetManager from "../manager/DynamicAssetManager";

const {ccclass, property} = cc._decorator;

@ccclass
export default class XXXXX extends cc.Component {

    onLoad() {
        //动态加载你要的资源可以是预制体,图片,音频等等
        DynamicAssetManager.load(this.node, "你的资源路径",cc.Prefab,
            (prefab: cc.Prefab) => {//根据你要的类型,自行修改,我这里是预制体
                //资源拿到了,你要干嘛该干嘛
            }
        );
    }

    onDestroy() {
        //动态释放(无论上面用到多少次load,这里只要写一次释放就可以了)
        DynamicAssetManager.pullAsset(this.node, this.constructor.name);
    }
}

猜你喜欢

转载自blog.csdn.net/qq183293/article/details/119392956