一, 前言
从CC 2.4开始,官方提出了一个新的概念AssetBundle,他兼容resources.从字面上来讲, 他就叫做"资源包". 他的意义很像Egret的资源包管理. 既是对资源进行包级别的管理.
二, 准备
1, 准备声音资源Shot.mp3 , 资源目录及配置如下:
2, 准备资源加载信息, 如下
let resPkg: Map<string,IResPkgModel> = new Map<string, IResPkgModel>( [ [ "Sounds", { assetType: AudioClip, urls: [ "Shot" , //"Open" ] } ] ] );
注: ①,Sounds为包名称
②, assetType: 包中资源的类型
③, urls : 包中各资源的路径(从Sounds开始)
附: IResPkgModel接口如下:
export interface IResPkgModel{ /**资源类型*/ assetType: Asset; /**资源地址*/ urls: Array<string>; }
三, 需要用到的API
step1 : cc.assetManager.loadBundle 加载包体对应的 AssetManager.Bundle , 得到bundle句柄 . 如Sounds胞体
step2: 使用得到的bundle句柄使用bundle.load加载包体中对应的资源
四, 包加载器设计方案
①, 解析加载资源信息, 得到各个包的bundle句柄
public preloadResPkg( resPkg:Map<string,IResPkgModel>, progressFunc: ( now: number, total: number ) => void, endFunc : () => void): void
②,根据 包体名称及 其中的url得到对用的资源
public getAsset<T extends Asset>( abName: string, url: string): T|null
具体代码如下:
import { Component, assetManager, Asset, AssetManager } from "cc"; import {IResPkgModel} from "./IResPkgModel"; /** * 资源加载器 */ export class ResMGr extends Component { public static instance: ResMGr; private total: number = 0; private now: number = 0; private totalAb: number = 0; private nowAb: number = 0; // @ts-ignore private progressFunc: ( now: number, total: number ) => void; // @ts-ignore private endFunc: () => void; // @ts-ignore private abBunds: Map<string, AssetManager.Bundle> = new Map<string, AssetManager.Bundle>(); protected onLoad(): void{ if( !ResMGr.instance ){ ResMGr.instance = this; }else{ this.destroy(); return; } } public preloadResPkg( resPkg:Map<string,IResPkgModel>, progressFunc: ( now: number, total: number ) => void, endFunc : () => void): void{ // step1: 加载我们的ab包进来 this.total = 0; this.now = 0; this.totalAb = 0; this.nowAb = 0; this.progressFunc = progressFunc;//进度函数 this.endFunc = endFunc;//结束函数 let keys: IterableIterator<string> = resPkg.keys(); let resultKey: IteratorResult<string> = keys.next(); while( resultKey.done == false ){ this.totalAb ++;//统计本次需要加载的Ab包 this.total += (resPkg.get( resultKey.value ) as IResPkgModel).urls.length; resultKey = keys.next(); } keys = resPkg.keys(); resultKey = keys.next(); while ( resultKey.done == false ){ this.loadAssetsBundle( resultKey.value , () => { this.nowAb ++; if( this.nowAb === this.totalAb){ this.loadAssetsInAssetsBundle( resPkg ); } } ); resultKey = keys.next(); } //end } private loadAssetsBundle( abName: string, endFunc: () => void ): void{ assetManager.loadBundle( abName, ( err, bundle ) => { if( err != null ){ console.log(`[ResMgr]: Load AssetsBundle Error: ${abName}`); if( this.abBunds.has( abName ) ){ this.abBunds.delete( abName ); } }else{ console.log(`[ResMgr]: Load AssetsBundle Success: ${abName}`); this.abBunds.set( abName, bundle ); } if( endFunc ){ endFunc(); } } ); } private loadAssetsInAssetsBundle( resPkg: Map<string,IResPkgModel> ): void{ let keys: IterableIterator<string> = resPkg.keys(); let resultKey: IteratorResult<string> = keys.next(); let resultValue: IResPkgModel; let urlSet: Array<string>; let typeClass: Asset; while ( resultKey.done == false ){ resultValue = resPkg.get( resultKey.value ) as IResPkgModel; urlSet = resultValue.urls; typeClass = resultValue.assetType; for ( let i: number = 0; i < urlSet.length; i ++ ){ if( this.abBunds.has(resultKey.value) ){ this.loadRes( this.abBunds.get(resultKey.value) as AssetManager.Bundle, urlSet[i], typeClass ); } } resultKey = keys.next(); } } private loadRes( abBundle: AssetManager.Bundle, url: string, typeClass: Asset ): void{ //@ts-ignore abBundle.load( url, typeClass,(error, asset) => { this.now++; if (error) { console.log(`load Res ${url} error : ${error}`); } else { console.log(`load Res ${url} sucess!`); } this.progressFunc && this.progressFunc(this.now, this.total); if (this.now >= this.total) { this.endFunc && this.endFunc(); } } ); } /** * 获取包内资源 * @param abName * @param url */ public getAsset<T extends Asset>( abName: string, url: string): T|null{ let bondule: AssetManager.Bundle|null = assetManager.getBundle(abName); if( bondule == null ){ console.log( `[error]: ${abName} AssetsBundle not loaded!!!` ); return null; } return bondule.get( url ); } }
五: 使用
①, 先解析配置资源信息 ResMGr.instance.preloadResPkg
②, 解析完毕后可以得到相应的资源
/** * 开始游戏 */ public startGame(): void{ //预加载资源 // @ts-ignore ResMGr.instance.preloadResPkg( resPkg, null, ()=> { this.enterGameScene(); } ); //end } //进入游戏 public enterGameScene(): void{ let sound: AudioClip|null = ResMGr.instance.getAsset<AudioClip>( "Sounds", "Shot" ); if(sound != null){ sound.play(); } }
使用 CC 3.0.1 版本