Unity 简易AssetBundle打包方法(二)

时隔半年又回来填坑了…没看过的小伙伴可以先看一下AssetBundle (一)。这次主要是对上次的一些细节补充和扩展。

一. AssetBundle打包

先回顾一下打包流程吧

using UnityEditor;
using System.IO;

public class CreateAssetBundles
{
	[MenuItem("Assets/Build AssetBundles")]
	static void BuildAssetBundles()
	{
		// 输出路径
		var dir = "AssetBundles";
		if (! Directory.Exists(dir))
            // 默认在工程路径下创建 
            // 创建后例: E:/ProjectName/AssetBundles
			Directory.CreateDirectory(dir);
		
		// BuildAssetBundleOptions.None: 使用LZMA算法压缩,压缩包更小,但是加载时间更长。
		// BuildAssetBundleOptions.UncompressedAssetBundle: 不压缩,包大,加载快
		// BuildAssetBundleOptions.ChunkBasedCompression: 使用LZ4压缩,压缩率没有LZMA高,但是我们可以加载指定资源而不用解压全部
		// 注:使用LZ4压缩,可以获得跟不压缩一样的加载速度,而且比不压缩文件要小

		// BuildTarget 选择build出来的AB包要使用的平台
		BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
	}
}

我们在Unity中为每个需要打包的对象设置好相应的AssetBundle名后再点击Assets/Build AssetBundles即可自行打包

我这里直接跳过为每个打包对象命名的过程,不了解的可以先去看下我之前的AssetBundle (一)中有详细过程

二. AssetBundle.manifest文件

首先看一下打包后的文件目录

我们主要先来看一下AssetBundle.manifest文件,用记事本或者其他工具打开后如下图

我们稍微分析一下文件结构内容。

  • CRC: 学过计算机网络的小伙伴应该对这个很熟悉,简单介绍一下就是一个检验码,用来检验文件的完整性

  • AssetBundleInfos: 这类似于一个列表,列出了所有进行AssetBundle对象的信息。我们这里一共打包了有5个对象,所以Info从0到4

  • Dependencies: 这个就比较关键了,记录了对象的所有依赖项。

    • 如obj1.ab依赖于m1.ab, 意思就是物体obj1需要材质m1
    • 而obj2.ab依赖于m2.ab, 并且m2.ab依赖于shader1.ab,如果想要让物体obj2正确显示,我们就需要材质m2和着色器shader1

AssetBundle.manifest文件只是为了方便我们观察打包后的对象信息,我们实际在Unity中加载使用的则是没有.manifest后缀名的AssetBundle文件,这在之后会讲到

看完了AssetBundle.manifest文件,我们再来看一下具体对象的.manifest文件,我们以obj2.ab为例,打开如下图

首先是版本号,这里跟我们没太大关系。CRC之前也已经讲过了。Hashes生成唯一的哈希ID,如果生成包有内容改动就会修改,可以判别是否有发生改动

Assets: 这里存放了当前对象在Unity中保存的相对路径
Dependencies: 存储了当前对象的依赖项的绝对路径(只是便于我们观察,实际使用无需考虑路径)

三. 加载文件

  • 代码示例为本地加载
public class TestStart : MonoBehaviour {
	void Start () 
	{
		// 加载AssetBundles(不是.manifest后缀名的) 类似于总文件夹
		var mainfestAB = AssetBundle.LoadFromFile("AssetBundles/AssetBundles");

		// 根据你的AssetBundles获取到AssetBundles.manifest中所有打包信息
		var mainfest = mainfestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
		
		// 获取到指定对象的所有依赖对象 接下来要准备先加载它们
		var deps = mainfest.GetAllDependencies("obj2.ab");

		Debug.Log(deps.Length);
		List<AssetBundle> depList = new List<AssetBundle>();

		for (int i = 0; i < deps.Length; ++i)
		{
            // 先加载依赖项
			var ab = AssetBundle.LoadFromFile("AssetBundles/" + deps[i]);
			depList.Add(ab);
		}

		var cubeAb = AssetBundle.LoadFromFile("AssetBundles/obj2.ab");

		var cube = cubeAb.LoadAsset("obj2") as GameObject;

		Instantiate(cube);
	}
}

对于依赖项的加载没有先后顺序影响的说法,只要在物体实例化生成之前,将所有依赖对象都加载至内存中即可

讲上述代码脚本挂载至场景任一物体运行即可生成obj2。

这里我们还把实例化的对象obj2(clone)拖拽至prefabs文件夹下作为一个预制体,原因之后会讲解

此时我们Unity还处于Play模式,我们观察该prefab右下角的实例化对象是显示正常的

我们退出Play模式, 再观察该obj2(Clone)的预制体会发现材质丢失了。原因很明显,当我们退出Play模式后,运行时的AssetBundle内存数据就被释放了,导致了材质的丢失。

这里要讲一下AssetBundle提供的一个函数Unload, 我们在之前的Instantiate(cube)后面添加如下代码

        // 实例化后要有个好习惯 释放掉AssetBundle文件中内存映像
		// 释放掉cubeAB里面关于资源的压缩文件数据
		cubeAb.Unload(false);

		for (int i = 0; i < depList.Count; i++)
		{
			depList[i].Unload(false);
		}

Unload(false)会释放当前AssetBundle对象的内存映像,那肯定有人会有疑问了:你释放了内存映像那你生成的物体不就也消失了么?

当然设置为false时,只是将该AssetBundle对象的序列化数据释放,并不会影响以及实例化的物体。而之后再有要使用该AssetBundle对象则会丢失数据。

Unload(true)就显得更加暴力, 只要场景中有物体引用该AssetBundle中的对象,便会丢失该资源。我们在上述代码后面再加一行

        // 强制释放掉所有内存引用
		mainfestAB.Unload(true);

启动后,将obj2(Clone)再次拖拽至prefabs文件夹下,会发现此时在运行时材质就已经丢失了

基本上现在就了解到这个程度吧…如果之后有更深入的了解会继续更新

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值