一:设置AssetBundle属性
——指定属性
在编辑器预览窗口的右下角有一个AssetBundle的属性设置
第一栏是AB包的属性名字,第二栏是AB包的属性变体(后缀)
- AB包的变体可以不设置(变体不能为unity,会报空指针)
- AB包的设置是不区分大小写的(就算设置为大写的,最后也会被改为小写)
- AB包的名称是可以指定目录路径的(例如:prefab/cube或者prefab\cube都可以)
——删除属性
如果想删除自定义的AB包名称,只能将此名称不指定给任何一个资源,之后选择列表中的Remove Unused Names则会删除所有当前没有使用的属性。
——设置属性需要注意的地方
1.如果想要将几个资源打包到同一个包中,则资源的路径要相同,变体也要相同。如果名字相同,变体不相同仍会打到不同的包里
2.打包时会自动寻找设置了AB包属性的资源,将它们进行打包
如果没有任何资源设置了AB包属性则会出现警告
二:构建AB包
构建AB包有两种方式:
一种是手动在编辑器里设置好AB包属性,之后通过代码一键打包
第二种是通过代码去设置资源的AB包属性,进行打包
——手动设置属性去构建
新建一个Editor文件夹和一个CreateAssetBundles脚本(脚本必须放在Editor文件夹中)
编译完会发现编辑器菜单栏出现了一个AssetBundle菜单,点击Build AssetBundles发现报错:输出路径不存在(说明打包时并不会自动创建路径),所以在打包前需要判断一下打包的路径是否存在
完整代码如下:
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写一句话当作主页)
"http://localhost:64283/"就是我们的服务器网址,后面再加上打包的路径就是AB包的服务器地址(http://localhost:64283/AssetBundle/prefab/model.v1)
——上传文件
将打包好的文件夹整个拖入NexBox的根目录下(与NetBox可执行文件同级)
四:加载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中的预制体处于引用(依赖)关系
如果包B进行Unload(true)之后,材质1和材质2都会进行卸载,则包A中的预制体则会丢失材质(失去引用关系)
首先加载出一个有依赖材质的预制体,接着再加载出依赖的材质
运行后发现预制体包含材质正确的显示在场景中。之后在Update中测试当按下空格键时卸载资源
按下空格后发现Unload参数为true时,预制体材质会丢失。参数为false时,预制体材质并不会丢失
——卸载的注意事项
如果在资源还需要使用的情况下不小心卸载了,则依赖的资源(贴图,材质.....)就丢失了。你可能会想到再次加载出依赖的资源就可以了,但事实并非如此
因为之前加载的预制体只引用了之前加载的依赖资源,当卸载之后它们的引用也就断开了,就算你再次加载出依赖的资源也不会与之前的预制体所连接,除非同时再次加载出预制体和资源