cocos creator 教程:框架 - 资源管理

【muzzik 教程】:框架 - 资源管理

实现功能

  • asset (资源管理器)

    • 资源加载接口整合

    • 编辑器资源加载

    • 资源生命周期管理

  • bundle (bundle 管理器)

    • bundle 加载/重载

    • scene 加载

    • bundle 管理单元

asset (资源管理器)

资源加载接口整合

统一本地/远程/编辑器资源加载接口为 get/get_dir

编辑器资源加载

// path_s_ 格式为 "db://assets/xxx"
const uuid_s = await Editor.Message.request("asset-db", "query-uuid", path_s_);
cc.assetManager.loadAny({ uuid: uuid_s }, completed_f);

资源加载优化

  • 短时间加载/释放
    在游戏中经常会遇到短时间加载/释放同一资源,所以针对这点进行优化
  1. 加载资源后引用计数 + 2
  2. 重载 decRef,在引用计数为 1 时加入释放表,释放表间隔批量释放
  • 未返回时加载相同资源
    如果在加载资源还未返回时,再次加载相同路径的资源,那么 返回的资源对象不是同一个,会造成使用误导(因为引用计数也不相同),可能导致使用者误调用 cc.assetManager.releaseAsset 强制释放,这时候另外一个资源如果还在使用就会导致报错,卡死

    • 解决方案:使用 Map 存储加载的资源对象,如果在加载完成后发现 Map 存在相同资源,则取出资源并 addRef 后替换资源对象

资源释放优化

  • 重启游戏时清理资源

restart 时需要清理定时器,更新释放表,清理 bundle 未使用的资源

  • 使用动态图集时也需要清理对应的纹理资源

bundle (bundle 管理器)

bundle 加载

很简答,封装 cc.assetManager.loadBundle 为异步函数即可

bundle 重载

由于引擎没有实现 bundle 重载后的脚本资源更新,所以需要我们自己做

/** 重新加载 bundle */
async reload(info: Partial<bundle_.bundle_info>): Promise<cc.AssetManager.Bundle | null> {
	if (PREVIEW) {
		return null;
	}

	await this._engine_init_task;

	/** bundle 信息 */
	const bundle_info: bundle_.bundle_info = new bundle_.bundle_info(info)!;
	/** bundle 脚本表 */
	const bundle_script_tab: Record<string, any> = {};
	/** js 系统 */
	const system_js = self["System"];
	/** 脚本缓存表 */
	const script_cache_tab: Record<string, any> = system_js[Reflect.ownKeys(system_js).find((v) => typeof v === "symbol")];

	// 更新 bundle 信息
	this.add(bundle_info);

	// 初始化 bundle 脚本表
	Object.keys(script_cache_tab).forEach((v_s) => {
		const current = script_cache_tab[v_s];
		const parent = script_cache_tab[v_s].p;
		const child = parent.d;

		if (!parent || !child || current.id !== parent.id) {
			return;
		}

		const name_s = parent.id.slice((parent.id as string).lastIndexOf("/") + 1);

		bundle_script_tab[name_s] = parent;
	});

	// 清理脚本缓存
	{
		const bundle_root = bundle_script_tab[bundle_info.bundle_s];

		if (bundle_root) {
			bundle_root.d.forEach((v: { id: string }) => {
				/** 脚本名 */
				const name_s = v.id.slice((v.id as string).lastIndexOf("/") + 1, v.id.length - 3);
				/** ccclass */
				const ccclass = cc.js.getClassByName(name_s);

				// 注销组件
				if (ccclass) {
					cc.js.unregisterClass(ccclass);
				}

				delete script_cache_tab[v.id];
				delete system_js["registerRegistry"][v.id];
			});
			delete script_cache_tab[bundle_root.id];
			delete system_js["registerRegistry"][bundle_root.id];
		}
	}

	// 清理 bundle 资源
	{
		const bundle = cc.assetManager.getBundle(bundle_info.bundle_s);

		if (bundle) {
			bundle.releaseAll();
			cc.assetManager.removeBundle(bundle);
		}
	}

	// 加载 bundle
	return this.load(bundle_info);
}

scene 加载

/** switch_scene 配置 */
export class switch_scene_config {
	constructor(init_?: Partial<switch_scene_config>) {
		Object.assign(this, init_);
	}

	/** bundle名(getBundle 时使用) */
	bundle_s = "resources";
	/** 预加载 */
	preload_b?: boolean;
	/** 加载回调 */
	progress_callback_f?: (finish_n: number, total_n: number, item?: cc.AssetManager.RequestItem) => void;
	/** 加载前调用的函数 */
	before_load_callback_f?: cc.Director.OnBeforeLoadScene;
	/** 启动后调用的函数 */
	launched_callback_f?: cc.Director.OnSceneLaunched;
	/** 场景卸载后回调 */
	unloaded_callback_f?: cc.Director.OnUnload;
}

bundle 管理单元

...

posted @   Muzzik  阅读(437)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起