AssetBundle的学习
1.AssetBundle简称AB包,是一种特定平台的压缩资产文件,类似于压缩包。
- AB包的资产包括模型,贴图,预设体,材质球,音效等。(不包括C#代码,所以使用lua进行热更新)
2.AB的作用
-
相对于Resource文件下的资源AB能更好的管理资源
Resource文件与AB的区别:Resource在打包时是只读文件,无法进行修改,AB包的存储方式可以自定义,压缩状态可以自定义,后期可以动态更新。 -
减少包体大小
可以压缩资源,减少初始包的大小,易于传播 -
可以热更新
1.资源的热更新
2.脚本的热更新 -
热更新的基本规则
客户端:自带一些默认资源和一个资源对比管理文件。
服务器端:资源服务器地址,资源对比文件,各种AB包。
第一步,客户端会从服务器中获得资源服务器地址。
第二部,在资源服务器的资源对比文件,检查需要更新或者下载的AB包,下载AB包完成热更新。
3.生成AB包资源文件
- 使用官方提供的Asset Bundle Browser
- Build
-
在打包Build中先要选择额打包平台然后是打包路径。
-
压缩方式有三种
1.不压缩
2.Standard Compression(LMZZ),这种方式压缩最彻底,压缩出来的AB文件最小,不够要使用其中的一个资源时,需要解压所有文件。
3.Chunk Based Compression(LZ4),压缩后的AB包大小略微大于LMZZ方式的压缩,但是用什么解压什么不用解压所有资源建议使用。 -
ETI:在资源包中 不包含资源的类型信息。
-
FR:重新打包时需要重新构建包,和Clear Folders不同,不会删除不再存在的包。
-
ITTC:增量构建检查时,忽略类型数的更改。
-
Append Hash:将文件哈希值附加到资源包名上。
-
SM:严格模式,如果打包时报错了,则打包直接失败无法成功。
-
- Inspect
- 观察包里的信息,资源,大小等。
- 在打包的路径中查看打包后的文件有三种文件,.meta,.manifest,和AB包
1.AB包文件无后缀,是资源文件。
2.manifest文件:AB包文件信息,AB包依赖关系,版本信息。
3.主包也是AB包(名字和目录名一致),有所有包的依赖关系(非常重要)
4.使用AB包资源文件
1.同步加载AB包
public class ABTest : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
//第一步 加载AB包
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
//第二步 加载AB包中的资源(三种方式)
GameObject obj = ab.LoadAssert("Cube"); //仅使用名字加载,会出现同名不同类型资源分不清的情况,不建议使用
GameObject obj = ab.LoadAssert<GameObject>("Cube"); //使用泛型加载
GameObject obj = ab.LoadAssert("Cube",typeof(GameObject) as GameObject); //Type指定泛型(lua不支持泛型)
Instantiate(obj); //实例化
}
}
2.异步加载AB包
public class ABTest : MonoBehaviour
{
void Start()
{
//异步加载 --> 协程
StartCoroutine(LoadABRes("head","myhead")); //此时myhead是图片资源
}
IEnumerator LoadABRes(string ABName, string resName)
{
//第一步 加载资源包
AssetBundleCreateRequest abcr = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + ABName);
yield return abcr;
//加载资源
AssetBundleCreateRequest abq = abcr.assetBundle.LoadAssertAsync(resName,typeof(Sprite)); //若已知是图片资源
yield return abq;
img.Sprite = abq.asset as Sprite;
}
}
3.卸载AB包资源
//参数为true时会把通过AB包加载的资源也卸载掉
abq.Unload(false); //卸载单个AB包
AssetBundle.UnloadAllAssetBundle(false);//卸载所有加载的AB包
5.AB包的依赖
- 假设有A,B,C,D这4个AB包,A中的a1中的资源用到了B,C中的资源那么必须加载A,B,C这三个包,否则a1将无法正常加载。往往一个资源会依赖多个AB包,这时就可以用主包中的依赖关系解决。
- 主包中记录的依赖关系是包与包之间的依赖关系,不会记录资源与包的依赖关系,比如a2依赖D中的资源,要加载a2还是会加载A,B,C,D这4个包。所以资源依赖了哪几个包无法知道。
//加载主包
AssetBundle abMain = AssetBundle(Application.streamingAssetsPath + "/" + "PC"); //这里PC为主包名
//加载主包中的固定文件
AssetBundle abManifest = AssetBundle.LoadAssert<AssetBundleManifest>("AssetBundleMainfest");
//从固定文件中 得到依赖信息
string[] strs = abManifest.GetAllDependencies("model"); //不用填路径
//得到了依赖包的名字
for(int i = 0; i < strs.Length; i++)
{
AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + strs[i]);
}
6.AB包资源加载管理器
- 同步加载
- 加载依赖包先要加载主包,加载主包得到其中的配置文件,通过配置文件得到相关的依赖包,然后加载依赖包,用键值对的方式来判断是否加载过次AB包。
- 加载依赖包。
- 从目标包中加载资源。
public class ABMgr : SingletonAutoMono<ABMgr>
{
//声明主包
private AssetBunle mainAB = null;
//声明依赖包获取用的配置文件
private AssetBundleMainfest manifest = null;
//字典 用来存储加载过的AB包 (重复加载会报错)
private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();
//AB包存放路径,方便修改
private string PathUrl
{
get
{
return Application.streamingAssetsPath + "/"; //测试用的路径
// Application.persistentDataPath + "/" + "PC"; //热更路径
}
}
//主包名 方方便修改
private string MainABName
{
get
{
#if UNITY_IOS
return "IOS";
#elif UNITY_ANDROID
return "Android";
#else
return "PC";
#endif
}
}
//加载AB包
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);
}
}
//同步加载1 不指定类型
public Object LoadRes(string abName, string resName)
{
//加载AB包
LoadAB(abName);
//加载资源
Object obj = abDic[abName].LoadAsset(resName);
if (obj is GameObject)
return Instantiate(obj);
else
return obj;
}
//同步加载2 根据type指定类型 lua常用
public object LoadRes(string abName, string resName, System.Type type)
{
//加载AB包
LoadAB(abName);
//指定类型加载 避免不同类型文件名相同时在一个包里面分不清类型的情况
Object obj = abDic[abName].LoadAsset(resName, type);
if (obj is GameObject)
return Instantiate(obj);
else
return obj;
}
//同步加载3 根据泛型指定类型加载
public T LoadRes<T>(string abName, string resName) where T:Object
{
//加载AB包
LoadAB(abName);
//指定类型加载 避免不同类型文件名相同时在一个包里面分不清类型的情况
T obj = abDic[abName].LoadAsset<T>(resName);
if (obj is GameObject)
return Instantiate(obj);
else
return obj;
}
}
- AB包卸载时
//单个包卸载
public void Unload(string abName)
{
if(abDic.ContainsKey(abName))
{
abDic[abName].Unload(false);
abDic.Remove(abName);
}
}
//所有包卸载
public void ClearAB()
{
AssetBundle.UnloadAssetBundle(false);
abDic.Clear();
mainAB = null;
mainfest = null;
}
- 异步加载
这里的异步加载指从AB包中加载资源时使用异步方法,加载AB包未使用异步加载方式
1.根据名字异步加载
public void LoadAssetAsyn(string abName, string resName, UnityAction<Object> callBack)
{
StartCoroutine(ReallyLoadResAsync(abName, resName, callBack));
}
private IEnumerable ReallyLoadResAsync(string abName, string resName, UnityAction<Object> callBack)
{
//加载AB包
LoadAB(abName);
//加载资源
AssetBundleRequest abr = abDic[abName].LoadAssetAsyn(resName);
yield return abr;
//异步加载结束后,通过委托 传递给外部 外部来使用
if (abr.asset is GameObject)
callBack(Instantiate(abr.asset));
else
callBack(abr.asset);
}
2.根据type异步加载
public void LoadAssetAsyn(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
StartCoroutine(ReallyLoadResAsync(abName, resName, type, callBack));
}
private IEnumerable ReallyLoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
//加载AB包
LoadAB(abName);
//加载资源
AssetBundleRequest abr = abDic[abName].LoadAssetAsyn(resName, type);
yield return abr;
//异步加载结束后,通过委托 传递给外部 外部来使用
if (abr.asset is GameObject)
callBack(Instantiate(abr.asset));
else
callBack(abr.asset);
}
3.根据泛型异步加载
public void LoadAssetAsyn<T>(string abName, string resName, UnityAction<T> callBack) where T:Object
{
StartCoroutine(ReallyLoadResAsync<T>(abName, resName, callBack));
}
private IEnumerable ReallyLoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T:Object
{
//加载AB包
LoadAB(abName);
//加载资源
AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(resName);
yield return abr;
//异步加载结束后,通过委托 传递给外部 外部来使用
if (abr.asset is GameObject)
callBack(Instantiate(abr.asset) as T);
else
callBack(abr.asset) as T;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)