一:设置AssetBundle属性

——指定属性
在编辑器预览窗口的右下角有一个AssetBundle的属性设置
AssetBundle(二)——AssetBundle使用流程_热更新
第一栏是AB包的属性名字,第二栏是AB包的属性变体(后缀)

  • AB包的变体可以不设置(变体不能为unity,会报空指针)
  • AB包的设置是不区分大小写的(就算设置为大写的,最后也会被改为小写)
  • AB包的名称是可以指定目录路径的(例如:prefab/cube或者prefab\cube都可以)AssetBundle(二)——AssetBundle使用流程_热更新_02       AssetBundle(二)——AssetBundle使用流程_AssetBundle_03
     

——删除属性
如果想删除自定义的AB包名称,只能将此名称不指定给任何一个资源,之后选择列表中的Remove Unused Names则会删除所有当前没有使用的属性。
AssetBundle(二)——AssetBundle使用流程_热更新_04


 

——设置属性需要注意的地方
1.如果想要将几个资源打包到同一个包中,则资源的路径要相同,变体也要相同。如果名字相同,变体不相同仍会打到不同的包里
AssetBundle(二)——AssetBundle使用流程_AssetBundle_05AssetBundle(二)——AssetBundle使用流程_热更新_06
AssetBundle(二)——AssetBundle使用流程_AssetBundle_07

2.打包时会自动寻找设置了AB包属性的资源,将它们进行打包
如果没有任何资源设置了AB包属性则会出现警告
AssetBundle(二)——AssetBundle使用流程_热更新_08


二:构建AB包

构建AB包有两种方式:
一种是手动在编辑器里设置好AB包属性,之后通过代码一键打包
第二种是通过代码去设置资源的AB包属性,进行打包

——手动设置属性去构建
新建一个Editor文件夹和一个CreateAssetBundles脚本(脚本必须放在Editor文件夹中)
AssetBundle(二)——AssetBundle使用流程_热更新_09
编译完会发现编辑器菜单栏出现了一个AssetBundle菜单,点击Build AssetBundles发现报错:输出路径不存在(说明打包时并不会自动创建路径),所以在打包前需要判断一下打包的路径是否存在
AssetBundle(二)——AssetBundle使用流程_热更新_10
完整代码如下:

using System.IO;
using UnityEditor;

public class CreateAssetBundles
{
    [MenuItem("AssetBundle/Build AssetBundles")]//打包按钮名称的层级关系
    static void BuildAllAssetBundles()
    {
        string assetBundleDirectory = "Assets/AssetBundles";//打包的路径
        //如果文件夹不存在则创建对应的文件夹
        if (!Directory.Exists(assetBundleDirectory))
        {
            Directory.CreateDirectory(assetBundleDirectory);
        }
        BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);//创建AssetBundle包
    }
}

内置的打包方法:BuildPipeline.BuildAssetBundles(string outputpath,BuildAssetBundleOptions,BuildTarget)

  • outputpath:输出路径(打包到的指定路径)
  • BuildAssetBundleOptions:打包选项
    1.BuildAssetBundleOptions.None:使用LZMA算法压缩,压缩的包更小,但是加载时间更长     2.BuildAssetBundleOptions.UncompressedAssetBundle:不压缩,包大,加载快,但是下载速度会慢3.BuildAssetBundleOptions.ChunkBasedCompression:使用LZ4算法压缩,压缩后的包比LZMA算法压缩的包大,但是我们可以加载指定资源不用解压全部,加载速度快
    4.BuildAssetBundleOptions.DisableWriteTypeTree:不写入类型信息,会降低对Unity不同版本的兼容性,但是资源包会变小,加载会变快。如果要发布到Web平台上,不能使用这个选项
    5.BuildAssetBundleOptions.IgnoreTypeTreeChanges:忽略TypeTree的变化,不能与DisableWriteTypeTree同时使用6.BuildAssetBundleOptions.AppendHashToAssetBundleName:文件名后面加上 Hash 值,保证不一样的文件有不一样的文件名,这样从CDN服务器上的下载就不会因为缓存而获取到错误的文件。
  • BuildTarget:打包到的平台(AssetBundle在不同的平台下是不兼容的)

——通过代码设置属性去构建


三:上传AB包——使用NetBox2

使用NetBox2可以快速搭建一个本地服务器,它的根目录就是当前NetBox的目录

——运行程序
双击运行之后发现出现了403 Forbidden,这是因为我们没有默认的首页(可以用html写一句话当作主页)
AssetBundle(二)——AssetBundle使用流程_热更新_11
"http://localhost:64283/"就是我们的服务器网址,后面再加上打包的路径就是AB包的服务器地址(http://localhost:64283/AssetBundle/prefab/model.v1)



——上传文件
将打包好的文件夹整个拖入NexBox的根目录下(与NetBox可执行文件同级)
AssetBundle(二)——AssetBundle使用流程_AssetBundle_12


四:加载AB包

——从本地加载资源

同步加载:AssetBundle.LoadFromFile(path)
                  path:本地路径
步骤:
1.从本地路径中加载AB包文件并返回一个AssetBundle对象(如果定义了变体则路径的最后必须加上变体名)
2.从AssetBundle对象中加载出对应名称的资源(不是设置打包属性的名称而是在Unity编辑器中真实存在的资源名称,不区分大小写),返回一个对应的资源类型

using UnityEngine;

public class LoadFromFile : MonoBehaviour
{
    private void Start()
    {
        string path = "Assets/MyAssetBundles/prefab/cube";
        AssetBundle ab = AssetBundle.LoadFromFile(path);
        Instantiate(ab.LoadAsset<GameObject>("Cube"));
    }
}

异步加载:AssetBundle.LoadFromFileAsync(path)
                  path:本地路径
步骤:
1.从本地路径中加载AB包文件并返回一个AssetBundleCreateRequest对象(如果定义了变体则路径的最后必须加上变体名)
2.等待AssetBundleCreateRequest加载完毕
3.从AssetBundleCreateRequest对象的assetbundle中加载出对应名称的资源(不是设置打包属性的名称而是在Unity编辑器中真实存在的资源名称,不区分大小写),返回一个对应的资源类型

using UnityEngine;
using System.IO;
using System.Collections;

public class LoadFromLocal : MonoBehaviour
{
    private IEnumerator Start()
    {
        string path = "Assets/MyAssetBundles/prefab/cube";
        AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path);
        yield return request;
        Instantiate(request.assetBundle.LoadAsset<GameObject>("Cube"));
    }
}

——从内存加载资源

同步加载:AssetBundle.LoadFromMemory(byte[] binary)
                  binary:字节数组
步骤:
1.从字节数组中加载AB包文件并返回一个AssetBundle对象(如果定义了变体则路径的最后必须加上变体名)
2.从AssetBundle对象中加载出对应名称的资源(不是设置打包属性的名称而是在Unity编辑器中真实存在的资源名称,不区分大小写),返回一个对应的资源类型

using UnityEngine;
using System.IO;

public class LoadFromMemory : MonoBehaviour
{
    private void Start()
    {
        string path = "Assets/MyAssetBundles/prefab/cube";
        AssetBundle ab = AssetBundle.LoadFromMemory(File.ReadAllBytes(path));
        Instantiate(ab.LoadAsset<GameObject>("Cube"));
    }
}

异步加载:AssetBundle.LoadFromMemoryAsync(byte[] binary)
                  binary:字节数组
步骤:
1.从字节数组中加载AB包文件并返回一个AssetBundleCreateRequest对象(如果定义了变体则路径的最后必须加上变体名)
2.等待AssetBundleCreateRequest加载完毕
3.从AssetBundleCreateRequest对象的assetbundle中加载出对应名称的资源(不是设置打包属性的名称而是在Unity编辑器中真实存在的资源名称,不区分大小写),返回一个对应的资源类型

using System.Collections;
using UnityEngine;
using System.IO;

public class LoadFromMemory : MonoBehaviour
{
     private IEnumerator Start()
    {
        string path = "Assets/MyAssetBundles/prefab/cube";
        AssetBundleCreateRequest request = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));
        yield return request;
        Instantiate(request.assetBundle.LoadAsset<GameObject>("Cube"));
    }
}

——使用WWW加载资源

1.不推荐使用WWW.LoadFromCacheOrDownload这种方法加载资源,这种方法已经被UnityWebRequest所代替
2.WWW.LoadFromCacheOrDownload如果是第一次加载时,会先将资源放到缓存(Cache)里,第二次加载时会直接从Cache中取,所以在测试时需要每次都把缓存清空之后再次测试,不然测试结果不准确

既可以从本地加载也可以从服务器加载

WWW.LoadFromCacheOrDownload(string url, int version)

  • url:路径
    如果是本地路径直接复制文件管理器上的路径即可:
    string url = @"file://:C:\Unity\Test\Assets\AssetBundles\prefab.a"
    string url = @"file:///:C:\Unity\Test\Assets\AssetBundles\prefab.a"
    string url = @"C:\Unity\Test\Assets\AssetBundles\prefab.a"

    如果是服务器则复制网址即可:
    string url = @"http://localhost:52481/AssetBundle/prefab/model.v1";
  • version:版本号

步骤:
1.读取本地路径/服务器上的AB包并返回一个WWW对象
2.等待加载完成后获得AssetBundle对象并返回
3.从AssetBundle对象中加载出对应名称的资源(不是设置打包属性的名称而是在Unity编辑器中资源的名称,不区分大小写),返回一个对应的资源类型

using System.Collections;
using UnityEngine;

public class LoadFromWWW : MonoBehaviour
{
    private IEnumerator Start()
    {
        Caching.ClearCache();
        while (!Caching.ready)
        {
            yield return null;
        }

        string url = @"C:\Unity\AB包\Assets\AssetBundle\prefab\model.v1";
        //string url = @"http://localhost:52481/AssetBundle/prefab/model.v1";
        WWW www= WWW.LoadFromCacheOrDownload(url, 0);
        yield return www;
        if (!string.IsNullOrEmpty(www.error))
        {
            Debug.Log(www.error);
            yield break;
        }
        Instantiate(www.assetBundle.LoadAsset<GameObject>("Model"));
    }
}

——使用UnityWebRequest加载资源

既可以从本地加载也可以从服务器加载

UnityWebRequest.GetAssetBundle(string uri)
uri:路径
如果是本地路径直接复制文件管理器上的路径即可:
string url = @"file://:C:\Unity\Test\Assets\AssetBundles\prefab.a"
string url = @"file:///:C:\Unity\Test\Assets\AssetBundles\prefab.a"
string url = @"C:\Unity\Test\Assets\AssetBundles\prefab.a"

如果是服务器则复制网址即可:
string url = @"http://localhost:52481/AssetBundle/prefab/model.v1";

步骤:
1.读取本地路径/服务器的AB包并返回一个UnityWebRequest对象
2.等待加载完成后获得AssetBundle对象并返回
3.从AssetBundle对象中加载出对应名称的资源(不是设置打包属性的名称而是在Unity编辑器中资源的名称,不区分大小写),返回一个对应的资源类型

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class LoadFromWeb : MonoBehaviour
{
    //第一种写法
    private IEnumerator Start()
    {
        string path = @"C:\Unity\AB包\Assets\AssetBundle\prefab\model.v1";
        //string url = @"http://localhost:52481/AssetBundle/prefab/model.v1";
        UnityWebRequest request = UnityWebRequest.GetAssetBundle(path);
        yield return request.SendWebRequest();
        AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
        Instantiate(ab.LoadAsset<GameObject>("Model"));
    }

    //第二种写法
    private IEnumerator Start()
    {
        string path = @"C:\Unity\AB包\Assets\AssetBundle\prefab\model.v1";
        //string url = @"http://localhost:52481/AssetBundle/prefab/model.v1";
        UnityWebRequest request = UnityWebRequest.GetAssetBundle(path);
        yield return request.SendWebRequest();
        AssetBundle ab = (request.downloadHandler as       
        DownloadHandlerAssetBundle).assetBundle;
        Instantiate(ab.LoadAsset<GameObject>("Model"));
    }
}

五:卸载

——卸载的优缺点
优点:卸载资源可以减少内存使用
缺点:有可能导致资源丢失


——什么时候应该去卸载?
1.在场景切换的时候
2.在关卡切换的时候


——卸载的方法
1.assetbundle.Unload(bool unloadAllLoadedObjects)
unloadAlLoadedlObjects:是否卸载所有加载的资源
如果为true,则会卸载当前包所有资源,包括正在使用着(被依赖)的资源
如果为false,则会卸载当前包未被依赖的资源,被其他资源依赖的资源不会被卸载,官方推荐参数为false
2.AssetBundle.UnloadAllAssetBundles(bool unloadAllObjects)
unloadAllObjects:是否卸载所有加载的资源
如果为true,则会卸载所有AB包的资源,包括正在使用着(被依赖)的资源
如果为false,则会卸载所有AB包未被依赖的资源,被其他资源依赖的资源不会被卸载,官方推荐参数为false

例如包A中的预制体依赖了包B中的材质1
如果包B进行Unload(false)之后,材质2会进行卸载,而材质1仍然与包A中的预制体处于引用(依赖)关系
AssetBundle(二)——AssetBundle使用流程_AssetBundle_13
如果包B进行Unload(true)之后,材质1和材质2都会进行卸载,则包A中的预制体则会丢失材质(失去引用关系)
AssetBundle(二)——AssetBundle使用流程_热更新_14
 

首先加载出一个有依赖材质的预制体,接着再加载出依赖的材质
AssetBundle(二)——AssetBundle使用流程_AssetBundle_15
运行后发现预制体包含材质正确的显示在场景中。之后在Update中测试当按下空格键时卸载资源
AssetBundle(二)——AssetBundle使用流程_AssetBundle_16
按下空格后发现Unload参数为true时,预制体材质会丢失。参数为false时,预制体材质并不会丢失

——卸载的注意事项
如果在资源还需要使用的情况下不小心卸载了,则依赖的资源(贴图,材质.....)就丢失了。你可能会想到再次加载出依赖的资源就可以了,但事实并非如此
因为之前加载的预制体只引用了之前加载的依赖资源,当卸载之后它们的引用也就断开了,就算你再次加载出依赖的资源也不会与之前的预制体所连接,除非同时再次加载出预制体和资源