热更新基础--AssetBundle学习笔记
一.简介
AssetBundle简称AB包,特定平台的资产压缩包(包括模型、贴图、预设体、音效、材质球等资产)。
作用:Resources下的资源只读且打包后不可修改,而AB包存储位置自定,后期可以动态更新;AB包压缩后节省空间;可以进行资源热更新和脚本热更新。
二.官方打包工具AssetBundleBrowser
1.下载安装工具
打开Package Manager窗口
搜索找到打包工具,右下角install安装,这里已经安装。
安装成功后可以在Windows中看到AssetBundle Browser。
Project窗口中Packages文件夹下也会出现打包工具文件夹。
打包工具窗口。
2.使用打包工具打AssetBundle包
点击Project窗口中的资源(可以同时选择多个资源),在Inspector窗口的最下方会出现AssetBundle打包选项,在输入下拉框中填写或选择当前选中的一个或多个资源要打包成的AB包文件的名称和后缀。
再次打开打包工具后再Configure选项中出现了资源。
在Build选项中即可进行打包相关设置(平台、路径、是否清空文件夹、是否打包时同步复制文件到StreamingAssets文件夹下、压缩方式等),压缩方式有LZMA(压缩率高,但是如果取用包中单个文件时会将整个包解压缩,资源使用时效率低)、LZ4(压缩率不如LZMA,但是如果是多个资源在同一个包中又取用单个资源时不需要解压缩整个包,资源使用时效率高)、不压缩3种,推荐LZ4。
打包后包文件存储在工程中AssetBundles文件夹下。
3.AB包文件查看
和Unity项目中的其他文件相同,打包出来的包文件也有响应的manifest清单文件与之对应,打开清单文件:
清单文件中包含包的一些信息,如version、CRC、Hash、Assets、Dependencies等。
三.AB包相关API
1.加载AB包及使用包中文件的相关API
void Start()
{
//加载AB包,AssetBundle类中有多个不同的静态方法用于加载AB包,这里使用从文件加载(根据文件地址加载)
//在AB包打包时勾选StreamingAssets同步,在Assets文件夹下会出现一个StreamingAssets文件夹,AB包会同步复制到文件夹中,这里从这个文件夹下加载AB包
AssetBundle bundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/model"); //加载AB包中的资源
//AssetBundle类中提供了多个不同的成员方法加载AB包中的资源,这里使用泛型加载,也推荐使用泛型加载
GameObject obj = bundle.LoadAsset<GameObject>("Sphere"); //使用资源
Instantiate(obj).transform.position = Vector3.zero; //因为AB包不能重复加载,所以加载完成后需要将其卸载
//参数是一个bool值,代表卸载AB包时是否一同卸载通过AB包中加载的资源
//如刚才将资源实例化在场景中,如果这里参数给true,卸载AB包后刚才实例化出来的Sphere会丢失,如果参数给false,卸载AB包后刚才实例化出来的Sphere不会受到影响 //卸载当前AB包
bundle.Unload(false);
//卸载所有AB包
AssetBundle.UnloadAllAssetBundles(false);
}
Unity提供了AssetBundle类,使用其中的AB包加载的静态方法加载AB包,返回值也是AssetBundle类型,使用加载具体资源的成员方法加载包种具体的资源,推荐使用泛型方法,否则需要进行类型转换。
注意:AB包不能重复加载,会报错,所以使用完成后记得卸载方便下次使用。
2.AB包依赖关系
在打包时,如果某个资源用到了一些依赖资源(Meterial、Sprite等),需要将这个资源依赖的资源一并打包起来,否则会出现资源丢失的问题。但是如果一个资源同时被多个资源使用,会出现重复打包的问题,所以可以将这些依赖资源单独打包,利用主包获取依赖信息。主包名称和文件夹名称相同,如上面的PC包。
void Start()
{
//加载主包
AssetBundle abMain = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/PC");
//加载主包中的固定文件
AssetBundleManifest abManifest = abMain.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
//从固定文件中得到依赖信息
string[] strs = abManifest.GetAllDependencies("model");
//得到依赖包名字
for (int i = 0; i < strs.Length; i++)
{
//加载AB包,需要保存下来,可以声明一个字典将加载好的AB包保存下来
AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + strs[i]);
} abMain.Unload(false);
}
3.AB包管理类,提供加载AB包中资源的同步和异步方法,各有3种重载(根据包名和资源名加载、根据包名和资源名和资源类型加载、根据包名和资源名和泛型资源类型加载),还提供了卸载指定ab包和卸载所有包的方法
public class AssetBundleManager : MonoBehaviour
{
//单例模块
private static AssetBundleManager instance;
public static AssetBundleManager Instance
{
get
{
if (instance == null)
{
GameObject obj = new GameObject("AssetBundleManager");
DontDestroyOnLoad(obj);
instance = obj.AddComponent<AssetBundleManager>();
}
return instance;
}
} //存储所有加载过的AB包的容器
private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();
//主包,只会加载一次
private AssetBundle mainAB = null;
//获取依赖包的配置文件
private AssetBundleManifest manifest = null; //ab包存放的路径,方便修改
private string PathUrl
{
get
{
return Application.streamingAssetsPath + "/";
}
}
//主包名,根据平台不同而不同
private string MainABName
{
get
{
#if UNITY_IOS
return "IOS";
#elif UNITY_ANDROID
return "Android";
#else
return "PC";
#endif
}
} /// <summary>
/// 加载资源,同步加载,3种方法重载
/// </summary>
/// <param name="abName"></param>
/// <param name="resName"></param>
public Object LoadRes(string abName,string resName)
{
LoadAB(abName); Object obj = abDic[abName].LoadAsset(resName);
//如果是GameObject,加载后基本都是创建游戏物体,所以这里判断一下如果是GameObject,直接返回创建好的游戏物体
if (obj is GameObject)
return Object.Instantiate(obj);
else
return obj;
}
public Object LoadRes(string abName,string resName,System.Type type)
{
LoadAB(abName); Object obj = abDic[abName].LoadAsset(resName, type);
//如果是GameObject,加载后基本都是创建游戏物体,所以这里判断一下如果是GameObject,直接返回创建好的游戏物体
if (obj is GameObject)
return Object.Instantiate(obj);
else
return obj;
}
public T LoasRes<T>(string abName,string resName) where T : Object
{
LoadAB(abName); T t = abDic[abName].LoadAsset<T>(resName);
//如果是GameObject,加载后基本都是创建游戏物体,所以这里判断一下如果是GameObject,直接返回创建好的游戏物体
if (t is GameObject)
return Object.Instantiate(t);
else
return t;
} /// <summary>
/// 加载资源,异步加载,3种方法重载
/// </summary>
/// <param name="abName"></param>
/// <param name="resName"></param>
/// <returns></returns>
public void LoadResAsync(string abName,string resName, System.Action<Object> callBack)
{
StartCoroutine(ReallyLoadResAsync(abName, resName, callBack));
}
private IEnumerator ReallyLoadResAsync(string abName, string resName, System.Action<Object> callBack)
{
StartCoroutine(abName); AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName);
yield return abr; //如果是GameObject,加载后基本都是创建游戏物体,所以这里判断一下如果是GameObject,直接创建好游戏物体
if (abr.asset is GameObject)
callBack(Instantiate(abr.asset));
else
callBack(abr.asset);
}
public void LoadResAsync(string abName, string resName, System.Type type, System.Action<Object> callBack)
{
StartCoroutine(ReallyLoadResAsync(abName, resName, type, callBack));
}
private IEnumerator ReallyLoadResAsync(string abName, string resName, System.Type type, System.Action<Object> callBack)
{
StartCoroutine(abName); AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName, type);
yield return abr; //如果是GameObject,加载后基本都是创建游戏物体,所以这里判断一下如果是GameObject,直接创建好游戏物体
if (abr.asset is GameObject)
callBack(Instantiate(abr.asset));
else
callBack(abr.asset);
}
public void LoadResAsync<T>(string abName, string resName, System.Action<T> callBack) where T : Object
{
StartCoroutine(ReallyLoadResAsync<T>(abName, resName, callBack));
}
private IEnumerator ReallyLoadResAsync<T>(string abName, string resName, System.Action<T> callBack) where T : Object
{
StartCoroutine(abName); AssetBundleRequest abr = abDic[abName].LoadAssetAsync<T>(resName);
yield return abr; //如果是GameObject,加载后基本都是创建游戏物体,所以这里判断一下如果是GameObject,直接创建好游戏物体
if (abr.asset is GameObject)
callBack(Instantiate(abr.asset) as T);
else
callBack(abr.asset as T);
} /// <summary>
/// 同步加载依赖包和资源包
/// </summary>
/// <param name="abName"></param>
private void LoadAB(string abName)
{
//先加载依赖包,再加载AB包,最后加载文件
if (mainAB == null)
{
mainAB = AssetBundle.LoadFromFile(PathUrl + MainABName);
manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
} string[] strs = manifest.GetAllDependencies(abName);
for (int i = 0; i < strs.Length; i++)
{
if (!abDic.ContainsKey(strs[i]))
abDic.Add(strs[i], AssetBundle.LoadFromFile(PathUrl + strs[i]));
} //没有包加载包,有包直接取出来使用
if (!abDic.ContainsKey(abName))
abDic.Add(abName, AssetBundle.LoadFromFile(PathUrl + abName));
}
/// <summary>
/// 异步加载依赖包和资源包
/// </summary>
/// <param name="abName"></param>
/// <returns></returns>
private IEnumerator LoadABAsync(string abName)
{
//先加载依赖包,再加载AB包,最后加载文件
if (mainAB == null)
{
AssetBundleCreateRequest createRequest = AssetBundle.LoadFromFileAsync(PathUrl + MainABName);
yield return createRequest;
mainAB = createRequest.assetBundle; AssetBundleRequest request = mainAB.LoadAssetAsync<AssetBundleManifest>("AssetBundleManifest");
yield return request;
manifest = request.asset as AssetBundleManifest;
} string[] strs = manifest.GetAllDependencies(abName);
for (int i = 0; i < strs.Length; i++)
{
if (!abDic.ContainsKey(strs[i]))
{
AssetBundleCreateRequest createRequest = AssetBundle.LoadFromFileAsync(PathUrl + strs[i]);
yield return createRequest;
abDic.Add(strs[i], createRequest.assetBundle);
}
} //没有包加载包,有包直接取出来使用
if (!abDic.ContainsKey(abName))
abDic.Add(abName, AssetBundle.LoadFromFile(PathUrl + abName));
} /// <summary>
/// 卸载单个包
/// </summary>
/// <param name="abName"></param>
public void UnLoad(string abName)
{
if (abDic.ContainsKey(abName))
{
abDic[abName].Unload(false);
abDic.Remove(abName);
} } /// <summary>
/// 卸载所有包
/// </summary>
public void ClearAssetBundles()
{
AssetBundle.UnloadAllAssetBundles(false);
abDic.Clear();
mainAB = null;
manifest = null;
}
}
热更新基础--AssetBundle学习笔记的更多相关文章
- 热更新解决方案--xlua学习笔记
一.热更新方案简介 在Unity游戏工程中,C#代码(编译型语言)资源和Resources文件夹下的资源打包后都不可以更改,因此这部分内容不能进行热更新,而lua代码(解释型语言)逻辑不需要进行预编译 ...
- 热更新解决方案--tolua学习笔记
一.tolua使用准备工作:从GitHub上下载tolua(说明:这篇笔记使用的Unity版本是2019.4.18f1c1,使用的tolua是2021年4月9日从GitHub上Clone的tolua工 ...
- 热更新语言--lua学习笔记
一.lua安装和编程环境搭建 lua语言可以在官网:http://luadist.org/下载安装包安装,编程IDE之前学习使用的是SciTE(https://www.cnblogs.com/movi ...
- linux基础命令学习笔记(二)
linux基础命令学习笔记(二) 1.kill :终止进程 kill pid (唯一标示一个进程) kill -9 强制终止 kill -15 命令未结束不能终止 # ps aux 查看所有进程 ...
- Objective-c基础知识学习笔记
Objective-c基础知识学习笔记(一) 一直有记录笔记的习惯.但非常久没分享一些东西了,正好上半年開始学习IOS了,如今有空写点.因开发须要,公司特意为我们配置了几台新MAC.还让我们自学了2周 ...
- Unity3D4.x之AssetBundle学习笔记
关于AssetBundle AssetBundle可用来将多个资源打包为一个文件,实现动态下载和更新.需要注意的是Unity3D5.x以后对打包方式进行了升级,不用再在依赖关系上伤透脑筋,但是和4.x ...
- ASP.Net开发基础温故知新学习笔记
申明:本文是学习2014版ASP.Net视频教程的学习笔记,仅供本人复习之用,也没有发布到博客园首页. 一.一般处理程序基础 (1)表单提交注意点: ①GET通过URL,POST通过报文体: ②需在H ...
- unity3d热更新插件uLua学习整理
前言 IOS不能热更新,不是因为不能用反射,是因为System.Reflection.Assembly.Load 无法使用System.Reflection.Emit 无法使用System.CodeD ...
- Python基础教程学习笔记:第一章 基础知识
Python基础教程 第二版 学习笔记 1.python的每一个语句的后面可以添加分号也可以不添加分号:在一行有多条语句的时候,必须使用分号加以区分 2.查看Python版本号,在Dos窗口中输入“p ...
随机推荐
- The Weekly Web Dev Challenge: Emoji Ratings
The Weekly Web Dev Challenge: Emoji Ratings /* DESCRIPTION: You job is to enable users to give a rat ...
- cookie & session & token compare
cookie & session & token compare cookie.session.token 区别和优缺点 存储位置 cookie 存在 client 端 session ...
- PPT & order & animation
PPT & order & animation powerpoint order of appearance https://support.office.com/en-us/arti ...
- position: absolute; not work
position: absolute; not work https://stackoverflow.com/questions/11928294/css-position-absolute-with ...
- NGK项目是一个怎样的项目?区块链里算是有前景的吗?
牛市时,项目被众星捧月,优点被无限放大,缺点无限被掩盖:而当市场开始下行时,之前的赞美则变成了贬低.所以了解项目不能盲目跟风,需要有独立的思考.对于近期引起社区讨论的NGK项目,以它为例,今天就来给大 ...
- Captain Technology INC浅谈新能源汽车的未来
近日全世界上最大的资管公司贝莱德向位于的英国电动汽车初创公司Arrival投资1.18亿美元,且该公司已有投资者亚马逊和美国第二大汽车制造商福特汽车参投.中国最知名的电动车公司蔚来股价单日大涨22%, ...
- 「NGK每日快讯」12.14日NGK公链第41期官方快讯!
- 教你玩转CSS border(边框)
边框样式 边框样式属性指定要显示什么样的边界. border-style属性用来定义边框的样式 border-style的值 代码演示: <!DOCTYPE html> <html ...
- Recycle 只显示一行BUG
学习Recycle 两天了,照着网上的Adapter写了2个Demo,结果测试的时候发现,第一个Demo 显示.点击都正常,第二个Demo的Adapter合第一个一模一样,仅仅是类名不同,结果显示的时 ...
- 04、数组与Arrays工具类
目录 前言 一.一维数组 基本认识 内存空间 二.二维数组 基本认识 三.工具类Arrays 前言 去年四月份大一下半学期正式开始学习Java,一路从java基础.数据库.jdbc.javaweb.s ...