一.简介

  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学习笔记的更多相关文章

  1. 热更新解决方案--xlua学习笔记

    一.热更新方案简介 在Unity游戏工程中,C#代码(编译型语言)资源和Resources文件夹下的资源打包后都不可以更改,因此这部分内容不能进行热更新,而lua代码(解释型语言)逻辑不需要进行预编译 ...

  2. 热更新解决方案--tolua学习笔记

    一.tolua使用准备工作:从GitHub上下载tolua(说明:这篇笔记使用的Unity版本是2019.4.18f1c1,使用的tolua是2021年4月9日从GitHub上Clone的tolua工 ...

  3. 热更新语言--lua学习笔记

    一.lua安装和编程环境搭建 lua语言可以在官网:http://luadist.org/下载安装包安装,编程IDE之前学习使用的是SciTE(https://www.cnblogs.com/movi ...

  4. linux基础命令学习笔记(二)

    linux基础命令学习笔记(二) 1.kill :终止进程  kill pid (唯一标示一个进程) kill -9  强制终止  kill -15 命令未结束不能终止 # ps aux 查看所有进程 ...

  5. Objective-c基础知识学习笔记

    Objective-c基础知识学习笔记(一) 一直有记录笔记的习惯.但非常久没分享一些东西了,正好上半年開始学习IOS了,如今有空写点.因开发须要,公司特意为我们配置了几台新MAC.还让我们自学了2周 ...

  6. Unity3D4.x之AssetBundle学习笔记

    关于AssetBundle AssetBundle可用来将多个资源打包为一个文件,实现动态下载和更新.需要注意的是Unity3D5.x以后对打包方式进行了升级,不用再在依赖关系上伤透脑筋,但是和4.x ...

  7. ASP.Net开发基础温故知新学习笔记

    申明:本文是学习2014版ASP.Net视频教程的学习笔记,仅供本人复习之用,也没有发布到博客园首页. 一.一般处理程序基础 (1)表单提交注意点: ①GET通过URL,POST通过报文体: ②需在H ...

  8. unity3d热更新插件uLua学习整理

    前言 IOS不能热更新,不是因为不能用反射,是因为System.Reflection.Assembly.Load 无法使用System.Reflection.Emit 无法使用System.CodeD ...

  9. Python基础教程学习笔记:第一章 基础知识

    Python基础教程 第二版 学习笔记 1.python的每一个语句的后面可以添加分号也可以不添加分号:在一行有多条语句的时候,必须使用分号加以区分 2.查看Python版本号,在Dos窗口中输入“p ...

随机推荐

  1. MDN 文档高级操作进阶教程

    MDN 文档高级操作进阶教程 MDN 文档, 如何优雅的使用 MDN 文档上的富文本编辑器 pre & 语法高亮器 code & note box source code 上传附件 i ...

  2. HTML5 in depth

    HTML5 in depth Content Models Web Storage web storage 存储用户信息, 替代 cookies LocalStorage SessionStorage ...

  3. post upload file & application/x-www-form-urlencoded & multipart/form-data

    post upload file application/x-www-form-urlencoded & multipart/form-data https://stackoverflow.c ...

  4. 打造NGK生态星空计划,高倍币VAST即将震撼上线!

    援引华盛顿邮报.彭博社.路透社以及CNN等知名媒体的报道,NGK官方近日宣布,为了完善NGK生态星空计划,NGK官方近日即将推出SPC的子币VAST,以鼓励更多的生态建设者参与. NGK官方相关负责人 ...

  5. 「NGK每日快讯」12.3日NGK公链第30期官方快讯!

  6. 聊一下PBN程序图例中的XTT

       PBN航路点的定位容差用XTT与ATT来表示,ATT=0.8*XTT.保护区半宽用1.5*XTT+BV计算得到,BV值在不同的航段取值不同. 对于A至E类航空器,距ARP 30nm以外BV值为2 ...

  7. 微信小程序:事件绑定

    小程序中绑定事件,通过bind关键字来实现.如bindinput,bindtap(绑定点击事件),bindchange等. 什么是事件 事件是视图层到逻辑层的通讯方式. 事件可以将用户的行为反馈到逻辑 ...

  8. Vue框架简介及简单使用

    目录 一.前端框架介绍 二.vue框架简介 三.vue使用初体验 1. vue如何在页面中引入 2. 插值表达式 3. 文本指令 4. 方法指令(事件指令) 5. 属性指令 四.js数据类型补充 1. ...

  9. Spirent Testcenter二层DHCP绑定流配置

    1.OLT配置 配一个VLAN,若GE口打Tag,不需要打PVID,打Untag,配PVID. 在ONU上配一个Other Bridge的WAN连接,并配置VLAN 2.TestCenter配置 选定 ...

  10. keras报错:AttributeError: '_thread._local' object has no attribute 'value'

    需求是使用pyqt5中的槽函数运行keras模型训练,为了不让工具在模型训练的过程中出现假死的现象,于是把训练操作放到单独的线程中运行,于是问题来了,训练操作在主线程运行时正常,但是界面假死,假若训练 ...