Unity之AssetBundle学习总结:
发布日期:2022-02-26 00:17:41 浏览次数:7 分类:技术文章

本文共 11539 字,大约阅读时间需要 38 分钟。

★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{    ///     /// 第一种打包方式:选择的多个物体都分别生成一个单独的包    ///     [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);    }    ///     /// 第二种打包方式:选择的多个物体都生成于一个包内    ///     [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();    }    ///     /// 选择某个物体或多个物体,把它(它们)的assetBundleName设置为自己预设体的名称    ///     [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());            }    ///     /// 普通方法1:同步    ///     private void LoadAssetBundle0101()    {        //加载得到AssetBundle资源对象,可以理解为将AssetBundle资源对象加载到内存当中        AssetBundle ab = AssetBundle.LoadFromFile(mURL);        //加载得到的AssetBundle中的资源        //object obj = ab.LoadAsset("Cube1") as GameObject;        //加载指定的资源        //GameObject obj = ab.LoadAsset
(); //加载所有资源 GameObject[] objs = ab.LoadAllAssets
(); print(objs.Length); //克隆资源对象,实现在Game视图的实例化 Instantiate(objs[0]); //打包相同材质的不同prefab,为了更好的看出实例化出的个对象,变换一下位置 Instantiate(objs[1],Vector3.one,Quaternion.identity); //是否卸载AB所有的资源:fasle只卸载当前的资源,true,卸载所有的资源,会导致游戏对象丢失材质 ab.Unload(false); } ///
/// 普通方法1: 异步 /// IEnumerator LoadAssetBundle0102() { //直接异步加载资源的绝对路径 AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(mURL); //等待加载完毕: yield return abcr; //ab接收加载abcr的资源 AssetBundle ab = abcr.assetBundle; //1.直接加载ab的资源 //GameObject obj = ab.LoadAsset
("Cube1"); //2.异步加载ab内所有的资源 AssetBundleRequest abr = ab.LoadAllAssetsAsync
(); //等待加载完毕: yield return abr; //加载资源对象: UnityEngine.Object obj = abr.asset; Instantiate(obj); ab.Unload(false); } ///
/// WWW1的有参方法: /// ///
///
IEnumerator LoadAssetBundle020101(string url) { //1. 需要销毁www //WWW www = new WWW(mURL); //yield return www; //AssetBundle ab = www.assetBundle; //GameObject obj = ab.LoadAsset
("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
("Cube"); //obj包含了prefab、material、texture的所有资源,卸载obj就是卸载了所有的资源 Instantiate(obj); ab.Unload(false); ww.Dispose(); } } ///
/// WWW1的无参方法 /// ///
IEnumerator LoadAssetBundle020102() { //1. //WWW www = new WWW("file://"+mURL); //yield return www; //AssetBundle ab = www.assetBundle; //GameObject obj = ab.LoadAsset
("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
("Cube"); Instantiate(obj); ab.Unload(false); } } ///
/// WWW2: /// ///
///
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
("Cube"); Instantiate(obj); ab.Unload(false); } } IEnumerator LoadManifestFile() { //直接加载总的 AssetBundle 的 Manifest 的资源: AssetBundle ab = AssetBundle.LoadFromFile(AssetBundleSavePath + "/ABS"); //1.加载单个资源,"AssetBundleManifest"不是某个文件,而是规定,无论加载哪个资源都这么写 //AssetBundleManifest abmf = ab.LoadAsset
("AssetBundleManifest"); //2.加载全部资源:总的AssetBundle资源配置文件只有一个,所以只要加载成功,那么Lenght就是1 AssetBundleManifest[] abms = ab.LoadAllAssets
(); //测试是否只有一个文件,也同时测试了,是否加载成功 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")); } } ///
/// 得到配置文件 /// ///
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"); abs.Unload(false); } } ///
/// /// ///
配置文件 ///
要加载的AB名字,需要扩展名 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
abDpsList = new List
(); 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
(sourceName); if (obj != null) { Instantiate(obj); } ab.Unload(false); } // 卸载所有的AB foreach (AssetBundle item in abDpsList) { item.Unload(false); } }}

转载地址:https://blog.csdn.net/TL_1203/article/details/79019402 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:unity之SQLite学习总结
下一篇:LaTeX如何正确输入引号:双引号“”单引号‘’

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年03月31日 16时40分53秒