Cocos Creator之AssetBundle(基礎)

一, 前言

     從CC 2.4開始,官方提出了一個新的概念AssetBundle,他兼容resources.從字面上來說, 他就叫作"資源包". 他的意義很像Egret的資源包管理. 既是對資源進行包級別的管理.
ide

二, 準備

    1, 準備聲音資源Shot.mp3 , 資源目錄及配置以下:函數

B01.png

 2, 準備資源加載信息, 以下this

let resPkg: Map<string,IResPkgModel> = new Map<string, IResPkgModel>( [
    [
        "Sounds",
        {
            assetType: AudioClip,
            urls: [
                "Shot" ,
                //"Open"
            ]
        }
    ]
] );

注: ①,Sounds爲包名稱url

     ②, assetType: 包中資源的類型
設計

     ③, urls : 包中各資源的路徑(從Sounds開始)
blog

附: IResPkgModel接口以下:接口

export interface IResPkgModel{
    /**資源類型*/
    assetType: Asset;
    /**資源地址*/
    urls: Array<string>;
}

三, 須要用到的API

      step1 : cc.assetManager.loadBundle 加載包體對應的 AssetManager.Bundle , 獲得bundle句柄 . 如Sounds胞體遊戲

      step2: 使用獲得的bundle句柄使用bundle.load加載包體中對應的資源
ip

四, 包加載器設計方案

      ①, 解析加載資源信息, 獲得各個包的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 版本

相關文章
相關標籤/搜索