1、加载Unity的AssetBundle
在Window菜单栏下的PackageManager里面搜AssetBundle,如下图:
有些版本在PackageManager里面找不到这个,可以找到项目的Package文件夹,打开manifest.json文件,添加一行信息即可,然后打开unity即可
"com.unity.assetbundlebrowser": "1.7.0",
2、 AB资源打包
我们可以在想要打包的资源的inspect窗口最下方选择把该资源放进某个包里,也可以在这里创建新包
在打开Window菜单栏下的AssetBundle,就会显示下面的界面,在Configure就可以看到所有创建的包,和包里面的内容。
切换到Build界面配置打包信息
- BuildTarget :选择打包的平台
- Output Path :选择输出后的文件夹
- Clear Floders :选择了之后,每次都会先清空文件夹,再打包
- Copy to StreamingAssets :会把打包后的文件复制一份到StreamingAssets文件夹,这个文件夹的位置在Asset下面
- Compression (压缩的模式):NoCompression 不压缩、解压快、包体大,不推荐; LZMA 压缩最小,解压满,但是用一个资源会把所有资源都解压出来; LZ4 压缩比LZMA大一点,但加载资源时候,用什么解压什么,不会全部解压出来,内存占用低
- -----------(上面这几个比较重要)---------
- Exclude Type Information :表示在资源包中不包含资源的类型信息
- Force Rebuild :每次打包会把所有的包都重写构建,类似于Clear Floders,但是不会删除不再存在的包
- Ignore Type Tree Changes:增量构建检查时,忽略类型数的更改
- Append Hash:将文件的哈希值附加到资源包名上
- Strict Mode:严格模式,如果打包错误了,则打包直接失败,无法成功
- Dry Run Build:运行时构建
最后点击build就可以了!build结束后会出现这个两个文件夹
3、AB包资源加载
创建一个测试脚本,拖拽到场景的一个空物体上来进行测试。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ABTest : MonoBehaviour
{
public Image image;
AssetBundle ab;
void Start()
{
//加载AB包
ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
//加载AB包中的资源
//只用名字加载的话会出现同名不同类型资源分不清,返回的对象是object类型
//Object obj = ab.LoadAsset("Cube");
//建议使用泛型加载或者是Type指定类型
GameObject obj = ab.LoadAsset<GameObject>("Cube");
//GameObject obj = ab.LoadAsset("Cube", typeof(GameObject)) as GameObject;
Instantiate(obj);
//AB包不能重复加载 否则报错
//AssetBundle ab2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model"); !!打咩
//异步加载——>协程
StartCoroutine(LoadABRes("head", "微信图片_20210926193813"));
}
IEnumerator LoadABRes(string ABName, string resName)
{
//加载AB包
AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + ABName);
yield return abcr;
AssetBundleRequest abq = abcr.assetBundle.LoadAssetAsync(resName, typeof(Sprite));
yield return abq;
image.sprite = abq.asset as Sprite;
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
//卸载所有加载的AB包,参数为true的话,会把通过AB包加载的资源也卸载了;
AssetBundle.UnloadAllAssetBundles(true);
}
if (Input.GetKeyDown(KeyCode.A))
{
//卸载指定AB包,参数为true的话,会把通过该AB包加载的资源也卸载了;
ab.Unload(true);
}
}
}
上面代码通过AB包加载了一个立方体,还有一张图片,(具体内容得看你打包了什么文件)
4、AB包的依赖
AB包依赖:如果一个资源身上用到了其他AB包中的资源,这个时候如果只加载了自己的AB包,可能会出现资源丢失的情况,这个时候我们需要把依赖包一起加载才能正常显示。eg:包a的一个模型,用到了包b里面的一个材质,这样我们使用包a来加载这个模型的时候,材质就会丢失。但如果我们同时加载了包b的话,模型就能正常显示。
打包的时候我们会发现,会多一个包,这个包的名字取决于前面的Output path,这个就是主包
解决办法AB包依赖的方法就是利用主包 获取依赖信息
//解决ab包依赖
//1、加载主包
AssetBundle abMain = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "StandaloneWindows");
//2、加载主包中的固定文件
AssetBundleManifest abManifest = abMain.LoadAsset<AssetBundleManifest("AssetBundleManifest");
//3、从固定文件中得到依赖信息
string[] strs = abManifest.GetAllDependencies(ab.name);
//4、遍历依赖包的名字,并加载
for(int i = 0; i < strs.Length; i++)
{
AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + strs[i]);
}
5、AB包资源管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class ABManager : Singleton<ABManager>
{
//字典用来存储所有以及加载过的AB包
private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();
private AssetBundle mainAB = null;
private AssetBundleManifest manifest = null;//配置文件
string PathUrl { get { return Application.streamingAssetsPath + "/"; } }
string MainABName { get => "StandaloneWindows"; }
/// <summary>
/// 加载AB包
/// </summary>
/// <param name="name"></param>
public void LoadAB(string abName)
{
//加载主包
if (mainAB == null)
{
mainAB = AssetBundle.LoadFromFile(PathUrl + MainABName);
manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
//获取依赖包相关信息
AssetBundle ab = null;
string[] strs = manifest.GetAllDependencies(abName);
for (int i = 0; i < strs.Length; i++)
{
if (!abDic.ContainsKey(strs[i]))
{
ab = AssetBundle.LoadFromFile(PathUrl + strs[i]);
abDic.Add(strs[i], ab);
}
}
if (!abDic.ContainsKey(abName))
{
ab = AssetBundle.LoadFromFile(PathUrl + abName);
abDic.Add(abName, ab);
}
}
//同步加载,不指定类型
public Object LoadRes(string abName,string resName)
{
LoadAB(abName);
//返回要加载的资源
return abDic[abName].LoadAsset(resName);
}
//同步加载,根据type指定类型
public Object LoadRes(string abName, string resName, System.Type type)
{
LoadAB(abName);
Object obj = abDic[abName].LoadAsset(resName, type);
//返回要加载的资源
return obj;
}
//同步加载,根据泛型指定类型
public T LoadRes<T>(string abName, string resName) where T:Object
{
LoadAB(abName);
//返回要加载的资源
return abDic[abName].LoadAsset<T>(resName);
}
//异步加载(资源加载使用了异步,ab包加载没有使用)
public void LoadResAsync(string abName,string resName,UnityAction<Object> callBack)
{
StartCoroutine(ReallyLoadResAsync(abName, resName, callBack));
}
private IEnumerator ReallyLoadResAsync(string abName, string resName, UnityAction<Object> callBack)
{
LoadAB(abName);
AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName);
yield return abr;
callBack(abr.asset);
}
//异步加载,根据type
public void LoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
StartCoroutine(ReallyLoadResAsync(abName, resName, type, callBack));
}
private IEnumerator ReallyLoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
LoadAB(abName);
AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName,type);
yield return abr;
callBack(abr.asset);
}
//异步加载 泛型
public void LoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T:Object
{
StartCoroutine(ReallyLoadResAsync<T>(abName, resName, callBack));
}
private IEnumerator ReallyLoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T : Object
{
LoadAB(abName);
AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(resName);
yield return abr;
callBack(abr.asset as T);
}
//单个包卸载
public void UnLoadABPackage(string abName)
{
if (abDic.ContainsKey(abName))
{
abDic[abName].Unload(false);
abDic.Remove(abName);
}
else { Debug.Log("不存在该AB包:" + abName); }
}
//所有包卸载
public void UnloadAllABPackage()
{
AssetBundle.UnloadAllAssetBundles(false);
abDic.Clear();
mainAB = null;
manifest = null;
}
}