Unity之AssetBundle学习总结:

★AssetBundle:

准备:1.在Project视图中建一个Editor的文件夹,进行预编译,在其内建一个脚本用来做预编译操作;

    2.创建几个预设体实现预编译后带来的功能;

    3.创建一个文件夹用来存储生成的包;

    4.引用命名空间using UnityEditor;




实例学习AssetBundle:


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class CreateAssetBundle : Editor
{


    /// <summary>
    /// 第一种打包方式:选择的多个物体都分别生成一个单独的包
    /// </summary>
    [MenuItem("AB/BuildAll")]
    static void BuildAllAB()
    {
        //打包方式单一
        //具有相同名字的资源,会打到一个Bundle当中
        //.mainfest是bundle的配置文件
        //每一个bundle都有这样一个配置文件,通过它可以查看每个bundle中的版本、hash、资源和依赖等信息
        //还有一个全局的总的配置文件(与打包的输出目录重名),通过总的配置文件,可以查看一共有多少个bundle包和每个bundle的信息

        /*
         * 1.资源没变的bundle,不会触发重新打包,及时bundle删除了,也不会重新打包,但是配置文件丢失,会触发重新打包
         * 2.可以强制进行重新打包 
         * BuildPipeline.BuildAssetBundles("Assets/ABS",BuildAssetBundleOptions.ForceRebuildAssetBundle  ,BuildTarget.StandaloneWindows);
         */

        /*
         * 1.不压缩,资源最大,但访问速度读取最快 
         * BuildPipeline.BuildAssetBundles("Assets/ABS",BuildAssetBundleOptions.UncompressedAssetBundle ,BuildTarget.StandaloneWindows);

         * 2.默认采用LZMA形式进行压缩,压缩比较大,访问速度较慢
         * BuildPipeline.BuildAssetBundles("Assets/ABS",BuildAssetBundleOptions.None ,BuildTarget.StandaloneWindows);

         * 3.采用LZ4进行压缩,基于Chunk算法,压缩比较小,访问速度较快
         * BuildPipeline.BuildAssetBundles("Assets/ABS",BuildAssetBundleOptions.ChunkBasedCompression ,BuildTarget.StandaloneWindows);
         */
        BuildPipeline.BuildAssetBundles("Assets/ABS",BuildAssetBundleOptions.None ,BuildTarget.StandaloneWindows);
        AssetDatabase.Refresh();
        Debug.Log(111);
    }
    /// <summary>
    /// 第二种打包方式:选择的多个物体都生成于一个包内
    /// </summary>
    [MenuItem("AB/BuildABSecelt")]
    static void BuildABSecelt()
    {
        AssetBundleBuild[] abbs = new AssetBundleBuild[1];
        abbs[0].assetBundleName = "Custom";
        Object[] selects = Selection.objects;
        string[] selectnames = new string[selects.Length];
        for (int i = 0; i < selects.Length; i++)
        {
            //获取选择到资源的路径
            selectnames[i] = AssetDatabase.GetAssetPath(selects[i]);
        }
        abbs[0].assetNames = selectnames;
        //该方法不再依靠Unity编辑器中的AssetBundleName进行打包,而是通过纯代码的方式进行打包
        BuildPipeline.BuildAssetBundles("Assets/ABS", abbs, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
        //更新Project视图
        AssetDatabase.Refresh();
    }
    /// <summary>
    /// 选择某个物体或多个物体,把它(它们)的assetBundleName设置为自己预设体的名称
    /// </summary>
    [MenuItem("AB/SetABName")]
    static void SetABName()
    {
        Object[] selects = Selection.objects;
        foreach (var item in selects)
        {
            string path = AssetDatabase.GetAssetPath(item);
            AssetImporter asset = AssetImporter.GetAtPath(path);
            asset.assetBundleName = item.name;
            //变体:asset.assetBundleVariant       
            asset.SaveAndReimport();
        }
        AssetDatabase.Refresh();
    }
}


该脚本实现的效果:




图1:




图2:




图3:




★使用AssetBundle的好处:

☆没有打包材质时的所占空间大小:




☆打包材质后所占的空间大小:




☆比较:相同个体和相同材质的情况下:

1.没有打包材质的空间大小:



2.打包材质的空间大小:



总结:若是n个相同的物体单独打包不打包材质,就会打包n个材质

            如果打包n个材质并打包材质,就会减少n-1个材质的空间大小


加载AssetBundle:


/*************************
 * Title:	""
 * Function:
 * -1.直接加载
 *    (1) LoadFromFile,直接从文件加载,这是最快的加载方式,在后台将AB解压后加载AB对象,分为异步和同步;
 *    (2) LoadFromMemory,从内存中加载,从内存中获取AB的二进制数据,然后再去创建AB对象,分为异步和同步;一般用在加密的数据上
 *  2.通过WWW类下载:
 *    (1)WWW www=new WWW(url);
 *    (2)WWW.LoadFromCachorDownload();
 * 实际使用环境的分析:

   (1) 随游戏一同发布的AssetBundle(一般位于StreamingAssets文件夹中):

       在打AssetBundle包时,使用LZ4压缩格式进行打包(开启BuildAssetBundleOptions.ChunkBasedCompression即可)。

       在运行时需要加载AssetBundle对象时,使用LoadFromFile方法进行加载。

       这样做的好处是:即可以将AssetBundle文件压缩,又可以兼顾加载速度,且节约内存。

   (2) 作为更新包,需要从服务端下载的AssetBundle:

       在打AssetBundle包时,使用默认的LZMA格式压缩。

       使用WWW.LoadFromCacheOrDownload 

       方法下载并缓存AssetBundle包文件。

       这样做的好处是:获得了最大的压缩率,在下载过程中可以减少数据传输量。同时,在本地磁盘创建缓存之后,
       又可以兼顾之后的加载速度,且节约内存。

   (3) 进行加密的AssetBundle:

       在打AssetBundle包时,使用LZ4压缩格式进行打包(开启BuildAssetBundleOptions.ChunkBasedCompression即可)。

       在运行时需要加载AssetBundle对象时,使用LoadFromMemory方法进行加载。(这也是从内存中使用流数据加载AssetBundle
       对象的仅有的使用场景。) 

   (4) 需要自己压缩的AssetBundle:

       我们自己也可以使用第三方库或工具对生成的AssetBundle包文件进行压缩,如果需要这样做,则我们最好不要再使用
       Unity3D对AssetBundle进行压缩,因此在打包时选择开启BuildAssetBundleOptions.UncompressedAssetBundle。

       在运行时需要加载AssetBundle对象时,使用LoadFromFileAsync方法进行异步加载。

 * Author:	v.
 * Date:	2018.1.9
 * Version:	1.0
 * Description:
 * 
 *************************/
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LoadTest : MonoBehaviour 
{
    private string AssetBundleSavePath;  //存放AssetBundle的目录
    private string mURL;                 //要加载的AssetBundle的绝对目录,包含文件本身

    void Awake () 
	{
        //打包存放的文件夹路径:
        AssetBundleSavePath = Application.dataPath + "/ABS";
        //要加载的AssetBundle的绝对路径(资源对象的路径)
        mURL = AssetBundleSavePath + "/prefabs/cube1";
	}

    private void Start()
    {
        //普通方法:

        //LoadAssetBundle0101();
        //LoadAssetBundle0102();

        //www方法:本地连接需要在目录前添加 "file://"

        /* 协程的调用方法一:*/

        //只打包prefab:
        //StartCoroutine("LoadAssetBundle020101", "file://"+mURL);
        //StartCoroutine("LoadAssetBundle020102");

        //打包prefab、material、texture:
        //StartCoroutine("LoadAssetBundle0102");

        /* 协程的调用方法二:*/

        //只打包Prefab
        //StartCoroutine(LoadAssetBundle020101("file://" + mURL));  
        //StartCoroutine(LoadAssetBundle020102());
        //StartCoroutine(LoadAssetBundle0202("file://" + mURL));

        //通过总的AssetBundle的Manifest文件加载:
        StartCoroutine(LoadManifestFile());
        
    }
    /// <summary>
    /// 普通方法1:同步
    /// </summary>
    private void LoadAssetBundle0101()
    {
        //加载得到AssetBundle资源对象,可以理解为将AssetBundle资源对象加载到内存当中
        AssetBundle ab = AssetBundle.LoadFromFile(mURL);
        //加载得到的AssetBundle中的资源
        //object obj = ab.LoadAsset("Cube1") as GameObject;
        //加载指定的资源
        //GameObject obj = ab.LoadAsset<GameObject>();
        //加载所有资源
        GameObject[] objs = ab.LoadAllAssets<GameObject>();
        print(objs.Length);
        //克隆资源对象,实现在Game视图的实例化
        Instantiate(objs[0]);
        //打包相同材质的不同prefab,为了更好的看出实例化出的个对象,变换一下位置
        Instantiate(objs[1],Vector3.one,Quaternion.identity);
        //是否卸载AB所有的资源:fasle只卸载当前的资源,true,卸载所有的资源,会导致游戏对象丢失材质
        ab.Unload(false);

    }
    /// <summary>
    /// 普通方法1: 异步
    /// </summary>
    IEnumerator LoadAssetBundle0102()
    {
        //直接异步加载资源的绝对路径
        AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(mURL);
        //等待加载完毕:
        yield return abcr;
        //ab接收加载abcr的资源
        AssetBundle ab = abcr.assetBundle;
        //1.直接加载ab的资源
        //GameObject obj = ab.LoadAsset<GameObject>("Cube1");
        //2.异步加载ab内所有的资源
        AssetBundleRequest abr = ab.LoadAllAssetsAsync<GameObject>();
        //等待加载完毕:
        yield return abr;
        //加载资源对象:
        UnityEngine.Object obj = abr.asset;
        Instantiate(obj);
        ab.Unload(false);
    }
    /// <summary>
    /// WWW1的有参方法:
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    IEnumerator LoadAssetBundle020101(string url)
    {
        //1. 需要销毁www
        //WWW www = new WWW(mURL);
        //yield return www;
        //AssetBundle ab = www.assetBundle;
        //GameObject obj = ab.LoadAsset<GameObject>("Cube");
        //Instantiate(obj);
        //ab.Unload(false);
        //www.Dispose();
        //2.使用using不需要销毁www
        using (WWW www = new WWW(url))
        {
            yield return www;
            //打包prefab、material、texture的时候:
            //需要下载本地链接的material的资源:  否则会丢失材质
            WWW ww = new WWW("file://" + AssetBundleSavePath + "/materials/material_01");
            AssetBundle ab = www.assetBundle;
            AssetBundle abMaterial_01 = ww.assetBundle;
            //运用直接加载的方法加载texture的资源:
            AssetBundle abTextures_01 = AssetBundle.LoadFromFile(AssetBundleSavePath + "/textures/textures_01");
            //把游戏对象加载到内存,方便克隆:
            GameObject obj = ab.LoadAsset<GameObject>("Cube");
            //obj包含了prefab、material、texture的所有资源,卸载obj就是卸载了所有的资源
            Instantiate(obj);
            ab.Unload(false); 
            ww.Dispose();
        }
    }
    /// <summary>
    /// WWW1的无参方法
    /// </summary>
    /// <returns></returns>
    IEnumerator LoadAssetBundle020102()
    {
        //1.
        //WWW www = new WWW("file://"+mURL);
        //yield return www;
        //AssetBundle ab = www.assetBundle;
        //GameObject obj = ab.LoadAsset<GameObject>("Cube");
        //Instantiate(obj);
        //ab.Unload(false);
        //www.Dispose();
        //2.using
        using (WWW www = new WWW("file://" + mURL))
        {
            yield return www;
            AssetBundle ab = www.assetBundle;
            GameObject obj = ab.LoadAsset<GameObject>("Cube");
            Instantiate(obj);
            ab.Unload(false);
        }
    }
    /// <summary>
    /// WWW2:
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    IEnumerator LoadAssetBundle0202(string url)
    {
        //0表示该prefab第一次打包的版本,如果在没有删除打包资源的情况下改变某值则版本会变成1
        //继续使用0也能够实例化到Game视图中,但是并不是改变某值后的版本,只是存在于内存中的版本0
        //因此想要实现改变某值后的资源展现在实例化对象中,就要把0改为1;
        using (WWW www = WWW.LoadFromCacheOrDownload(url, 0))
        {
            yield return www;
            AssetBundle ab = www.assetBundle;
            GameObject obj = ab.LoadAsset<GameObject>("Cube");
            Instantiate(obj);
            ab.Unload(false);
        }
    }
    IEnumerator LoadManifestFile()
    {
        //直接加载总的 AssetBundle 的 Manifest 的资源:
        AssetBundle ab = AssetBundle.LoadFromFile(AssetBundleSavePath + "/ABS");
        //1.加载单个资源,"AssetBundleManifest"不是某个文件,而是规定,无论加载哪个资源都这么写
        //AssetBundleManifest abmf = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        //2.加载全部资源:总的AssetBundle资源配置文件只有一个,所以只要加载成功,那么Lenght就是1
        AssetBundleManifest[] abms = ab.LoadAllAssets<AssetBundleManifest>();
        //测试是否只有一个文件,也同时测试了,是否加载成功
        if (abms.Length == 1)
        {
            //得到所有的AssetBundle资源的名字
            string[] allABName = abms[0].GetAllAssetBundles();
            //创建一个Hash128的数组接收所有资源的HashID
            Hash128[] allHS = new Hash128[allABName.Length]; 
            //遍历所有资源的名称
            for (int i = 0; i < allABName.Length; i++)
            {
                //将所有资源的HashID添加到allHS数组中
                allHS[i] = abms[0].GetAssetBundleHash(allABName[i]);
                //打印所有的资源名称以及HashID;
                //也可以不用创建这个数组,那这个只能实现一个功能,仅仅将资源名称和HashID打印出来而已。
                //创建数组,可以通过存储在数组内的HashID搜索以及实现你想要实现的功能。
                print(allABName[i] + " " + allHS[i]);
            }
            ab.Unload(false);
        }
        yield return null;
    }
}



实例:减少代码的冗杂,提高代码的重用性:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LoadTT : MonoBehaviour 
{
    string mPathAB;
    AssetBundleManifest mABMF;

    private void Awake()
    {
        mPathAB = Application.dataPath + "/ABS";
    }

    private void Start()
    {
        StartCoroutine("LoadABMF");
        
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            StartCoroutine(LoadSource(mABMF, "prefabs/cube1.ab", "Cube1"));
        }
    }

    /// <summary>
    /// 得到配置文件
    /// </summary>
    /// <returns></returns>
    IEnumerator LoadABMF()
    {
        WWW absWWW = WWW.LoadFromCacheOrDownload ("file://" + mPathAB + "/ABS", 2);
        yield return absWWW;

        // 判断absWWW有没有错误
        if (!string.IsNullOrEmpty(absWWW.error))
        {
            Debug.Log(absWWW.error);
        }
        else
        {
            // 总的AB
            AssetBundle abs = absWWW.assetBundle ;
            // 总的配置文件
            mABMF = abs.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            abs.Unload(false);
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="manifest">配置文件</param>
    /// <param name="abName">要加载的AB名字,需要扩展名</param>
    IEnumerator LoadSource(AssetBundleManifest manifest, string abName, string sourceName)
    {
        // 得到所有依赖的AB的名字
        string[] dps = manifest.GetAllDependencies(abName);
#if UNITY_EDITOR
        foreach (string item in dps)
        {
            print(item);
        }
#endif
        //AssetBundle[] abDps = new AssetBundle[dps.Length];
        List<AssetBundle> abDpsList = new List<AssetBundle>();
        for (int i = 0; i < dps.Length; i++)
        {
            string urlDpsFile = "file://" + mPathAB + "/" + dps[i];
            WWW wwwDps = WWW.LoadFromCacheOrDownload(urlDpsFile , manifest.GetAssetBundleHash(dps[i]));
            yield return wwwDps;
            AssetBundle abDps = wwwDps.assetBundle;
            abDpsList.Add(abDps);
        }

        string url = "file://" + mPathAB + "/" + abName;
        WWW abWWW = WWW.LoadFromCacheOrDownload(url , manifest.GetAssetBundleHash(abName));
        yield return abWWW;
        if (!string.IsNullOrEmpty(abWWW.error ))
        {
            print(abWWW.error );
        }
        else
        {
            AssetBundle ab = abWWW.assetBundle ;
            GameObject obj = ab.LoadAsset<GameObject>(sourceName);
            
            if (obj != null)
            {
                Instantiate(obj);
            }
            ab.Unload(false);
        }

        // 卸载所有的AB
        foreach (AssetBundle item in abDpsList)
        {
            item.Unload(false);
        }
    }
}




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值