存储在Resources下的资源,最终会存储在游戏的主体包中,发送给用户,手机系统上,如果需要做资源的更新,是无法使用Resources即时更新(不需要关闭手机游戏,即可实现游戏更新).
AssetBundle(简称AB包):
AB包是独立于游戏主包存在的资源存储文件,使用内部资源时,需要单独下载和加载。
AB包和Resources的区别:
- 存储:Resources内部资源存储在游戏的发布包中;
- AB包存储在独立的文件中(AB包存储在非特殊目录下时,不在游戏的发布包中);
- 加载:Resources内部资源使用Resources.Load();
- AB包(可以理解为可下载的Resources)
- *获得AB包文件(下载,解压streaming拷贝到可写目录)
- 加载步骤1:通过AB包文件路径,加载AB包文件
- 加载步骤2:通过名称(资源名称),加载内部资源
AssetBundle的定义:
- AssetBundle是把一些资源文件,场景文件或二进制文件以某种紧密的方式保存在一起的一些文件。
- AssetBundle内部不能包含C#脚本文件,AssetBundle可以配合Lua实现资源和游戏逻辑代码的更新。
热更新: 不关闭Unity应用的前提,实现游戏资源和代码逻辑的更新。
AB包的创建:
资源导入项目
如果资源未来做更新(资源存储在AB包中),就不要将资源放置在Resources目录下;
资源配置
- 选中需要添加AB包的资源,填写或选择已存在的AB包名称;
- AB包配置修改后或AB内部的资源修改后,都需要重新生成AB包;
- AB包名称如果配置为这样的结构”ui/package”,ui会作为AB包存储的父目录,package是AB包的名称;
- 导入到AB包的资源,包内部是不存在目录的;
生成AB包脚本编写(编辑器脚本)。
AB包压缩方式(实际选择根据项目情况分析):
- 不压缩:AB包比较大,下载较慢,加载速度快(CPU不用运算解压缩)
- LZMA算法压缩:默认压缩模式,文件尺寸居中,加载速度居中
- LZ4算法压缩:5.3以后可用,压缩比例高,文件小,加载速度偏慢
依赖关系:
如果一个AB(名称A)包,使用到了另一个AB(名称B)包的资源,那么两个AB包就产生了依赖关系。也就是A依赖于B。在主 manifest 文件中,存储了依赖关系
导出核心代码:
一般会写一个顶部菜单栏按钮,便于随时导出AB包;
AB包分平台,所以导出的API不同
导出核心代码:
//参数1:AB包文件存储路径
//参数2:导出选项
//参数3:平台(不同平台的ab包是不一样的)
BuildPipeline.BuildAssetBundles(
path,
BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.ForceRebuildAssetBundle,
platform
);
导出选项:
-
None:无任何选项
-
UncompressedAssetBundle:默认压缩模式为LZMA,开启这个选项就不会压缩AB包
-
CollectDependencies:默认开启,开启依赖记录机制
-
DeterministicAssetBundle:将AssetBundle的哈希校验值,存储在ID中(默认开启)
-
ForceRebuildAssetBundle:强制重新导出所有的AB包
- ChunkBasedCompression:使用LZ4算法压缩AB包
-
ForceRebuildAssetBundle:强制重新导出所有的AB包
-
DeterministicAssetBundle:将AssetBundle的哈希校验值,存储在ID中(默认开启)
-
CollectDependencies:默认开启,开启依赖记录机制
-
UncompressedAssetBundle:默认压缩模式为LZMA,开启这个选项就不会压缩AB包
导出后的目录结构:
和存储目录同名的文件和文件.manifest,是主AB包及主AB包配置文件;
无扩展名文件:AB包;文件名.manifest文件:AB包对应的配置文件。
加载AB包内部数据:
如果想处理依赖关系的加载,则必须加载主AB包,因为依赖关系的存储,都存储在主AB包的配置文件中。
- 第一步(加载依赖的AB包文件)
- 1、加载主AB包
- 2、根据主AB包的配置文件,获得我当前需要加载的AB所依赖的AB们
- 3、将所有的依赖AB们,加载进来
- 第二步(加载AB包文件)
- AB包 = AssetBundle.LoadFromFile(AB包文件路径)
- .LoadFromFileSync(AB包文件路径)(异步加载)
- 第三步(加载AB包内资源)
- 资源对象 = AB包对象.LoadAsset<资源类型>("资源名称")
- .LoadAssetSync<资源类型>("资源名称")(异步加载)
- 注意!AB包不能重复加载
Unity性能分析工具:
点击Window/Profiler,可以打开分析工具
Resources.Load() 加载后的资源,Unity会存储在内存中,所以即使场景中的对象被删除,资源的内存占用依然存在,只有使用Resources.UnloadUnusedAssets()释放后,没有被场景引用的资源内存才会被释放。
一些代码
多平台导出AB包:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
public class ExportAB
{
[MenuItem("AB包导出/Windows")]
public static void ForWindows()
{
Export(BuildTarget.StandaloneWindows);
}
[MenuItem("AB包导出/Mac")]
public static void ForMac()
{
Export(BuildTarget.StandaloneOSX);
}
[MenuItem("AB包导出/iOS")]
public static void ForiOS()
{
Export(BuildTarget.iOS);
}
[MenuItem("AB包导出/Android")]
public static void ForAndroid()
{
Export(BuildTarget.Android);
}
private static void Export(BuildTarget platform)
{
//项目的Assets目录的路径,比如xxxxxxx/Assets
string path = Application.dataPath;
//有个需求,我想把包导出到与Assets同级的ab目录下
//比如最终路径,xxxxxxx/ab,通过对path修改实现
path = path.Substring(0, path.Length - 6) + "ab";
//防止路径不存在
if(!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
//导出ab包的核心代码,生成ab包文件
//参数1:ab包文件存储路径
//参数2:导出选项
//参数3:平台(不同平台的ab包是不一样的)
BuildPipeline.BuildAssetBundles(
path,
BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.ForceRebuildAssetBundle,
platform
);
Debug.Log("导出ab包成功");
}
}
一般像存储路径这种固定数据我们会写一个配置类用于存放,便于多个类调用以及统一修改:
public class Config
{
//配置AB包存储的路径
public static string ABPath = Application.dataPath.Substring(0, Application.dataPath.Length - 6) + "ab";
}
有时需要异步加载:文章来源:https://www.toymoban.com/news/detail-837950.html
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class AsyncLoad : MonoBehaviour
{
void Start()
{
//同步加载代码
//GameObject.Find("/Canvas/Image").GetComponent<Image>().sprite = Resources.Load<Sprite>("参考图");
//通过开启协同,执行一个异步Resources加载资源
//StartCoroutine(LoadImage());
//AssetBundle ab = AssetBundle.LoadFromFile(Config.ABPath + "/big");
//GameObject.Find("/Canvas/Image").GetComponent<Image>().sprite = ab.LoadAsset<Sprite>("参考图");
StartCoroutine(LoadAB());
}
//从Resources加载
IEnumerator LoadImage()
{
//开启一个异步加载
ResourceRequest rr = Resources.LoadAsync<Sprite>("参考图");
//协同会在加载资源成功后,继续执行(底层封装了线程加载资源)
yield return rr;
//将加载成功的资源,显示出来
GameObject.Find("/Canvas/Image").GetComponent<Image>().sprite = rr.asset as Sprite;
}
//从AB包加载
IEnumerator LoadAB()
{
AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(Config.ABPath + "/name"); // 这里为具体导出的AB包名
yield return abcr;
GameObject.Find("/Canvas/Image").GetComponent<Image>().sprite = abcr.assetBundle.LoadAsset<Sprite>("参考图");
}
}
处理带有依赖关系的AB包:文章来源地址https://www.toymoban.com/news/detail-837950.html
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Load : MonoBehaviour
{
void Start()
{
//加载主AB包
AssetBundle main = AssetBundle.LoadFromFile(Config.ABPath + "/ab");
//获取主AB包的配置文件
AssetBundleManifest manifest = main.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
//分析预制体所在AB包,依赖哪些AB包
//deps存储了所有依赖的ab包的名字
string[] deps = manifest.GetAllDependencies("test2"); //test2为我想加载的包
//加载依赖的AB包
for(int i = 0; i < deps.Length; i++)
{
AssetBundle.LoadFromFile(Config.ABPath + "/" + deps[i]);
}
//加载预制体所在的AB包
AssetBundle test2 = AssetBundle.LoadFromFile(Config.ABPath + "/test2");
//加载预制体
Object prefab = test2.LoadAsset("Image");
GameObject img = Instantiate(prefab) as GameObject;
img.transform.SetParent(GameObject.Find("/Canvas").transform);
img.transform.localPosition = Vector3.zero;
img.transform.localScale = Vector3.one;
}
}
到了这里,关于Unity学习笔记之AB包(AssetBundle)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!