1、深入理解unity资源与ab包深入理解资源 (Asset) 与 AssetBundleAB 包文件Assetbundle 文件格式可以理解为,拥有一个列表头和压缩数据块列表。列表头定义了各数据块的起始位置和大小。数据块列表中存储压缩过的 unity 对象的序列化数据。AssetBundle 对象加载并创建 AssetBundle 对象。 Assetbundle 对象是一个轻量级对象,只包含一个资源(Asset) 对象列表和指向实际 AB 包数据的文件对象。AB 包文件加载完成后存放在内存中, 注意只有 LZ4 能够以压缩格式存放在内存中。 这 段内存不能直接访问,由 AssetBundle 对
2、象负责管理。AssetBundle.Unload() 会释放这段内存。Asset 资源实际上 unity 中并没有与资源 (Asset) 这个词对应的类。我们一般把从 AssetBundle 中LoadAsset() 出来的对象称为资源 (Asset) 。AssetBundle.LoadAsset() 等接口从 AssetBundle 对象中解压数据反序列化构建 Object 。Unity 完美的序列化机制可以使任何对象都可以直接序列化为连续内存块,同样任何对象都可以通过 AssetBundle.LoadAsset() 反序列化为结构化对象。AssetBundle.LoadAsset() 接口
3、返回类型是 Object 。此功能也暗示了可以将任何对象从ab 包内存中反序列化出来构建。Prefab 是什么?创建 ab 包时,一般会将 prefab 打入到包中。游戏中通过 AssetBundle.LoadAsset() 将prefab 对象加载出来。再通过加载出来的 prefab 构建 GameObject思考: 代码 1 中 m_Prefab 是什么?是什么类型?如果是 GameObject ,那么这个 GameObject 为什么没有出现在场景中?如果是 GameObject ,为什么一定要通过 Instantiate 再次 clone 一个 GameObject 出来?Unity
4、的 C+ 代码分为两部分, Runtime 和 Editor 。 Runtime 中包含引擎的所有核心功 能, Editor 包含编辑器所需核心功能。Prefab.h/cpp 存放于 Editor 中,实现了编辑器中 prefab 的功能。Prefab 继承于 Object ,包含一个指向 GameObject 的指针。其功能非常简单,仅仅只 是维护编辑器中 prefab 之间的关联关系,用来实现编辑器中 prefab 修改编辑功能。Prefab 只是对 GameObject 在编辑器中一个功能封装。上一段源码:从源码判断, Prefab 功能非常简单,只是实现编辑器中各 prefab 关联编
5、辑功能。结论:因此可以推断, 在最终发布环境中,并无 Prefab 对象存在。 代码 1 中 LoadAsset 构建的对象是 GameObject ,此 GameObject 并不存在于当前场景 (scene) 中,而是被 unity 放到了一个空场景中。LoadAsset 构建的 GameObject 对象, Unity 希望我们把它当作资源 (asset) 使用 。对比代码 2 中 m_Prefab 和 m_GameObject 的 scene 变量。思考?为什么不能需要构建 GameObject 时,直接从 AssetBundle 中反序列化构建呢?推 测 Unity 希 望 开 发
6、者 们 遵 循 的 工 程 实 践 是 , 将 AssetBundle 中 反 序 列 化 构 建 的GameObject 作为资源 (asset) 进行管理。 当游戏中需要构建 GameObject 时,以资源 (asset) 为基础构建,而不是从连续内存上反序列化去构建。从而将对象构建与数据解压解耦。资源 (Asset)资源(Asset) 是 unity 希望开发者们遵循的一种工程实践规范。1.所有 AssetBundle 中 LoadAsset 出来的对象称为资源 (Asset) 。2.资源 (Asset) 与 AssetBundle 之间有强耦合关系。3.资源(Asset) 不要直接被
7、使用在业务逻辑中。资源(Asset) 和业务中创建的对象没有功能上不同。 但在使用方法上有截然不同的区分。资源 (Asset) 可以由 AssetBundle.Unload(true) 统一强制销毁,也可以单个销毁。但是对于同一个 AssetBundle ,LoadAsset 出的资源 (Asset) 只能被销毁一次, 销毁后再 重复 LoadAsset() 会失败。Instantiate()英文翻译为”实例化”,个人觉得这个接口用英文克隆”c lone ”描述更准确。Object.Instantiate() 可以对任何对象 clone 。包括 Texture 、Shader 、 AudioC
8、lip ,当然 应该不会有人对这类内存占用大且不会被修改的对象 clone 。所以,遵循 unity 暗示的工程实践规范。所有占用大量内存且不会被修改的资源 (Asset) 不被 clone ,所有需要修改的逻辑对象会被 clone 出一个新的实例。如下图所示:贴图 (Texture) 则保持引用。引用与非引用资源非引用资源类型:建议使用 Instantiate 构建新对象。 GameObject 被 Instantiate 时, GameObject 包含的非引 用资源也会自动被 Instantiate 。GameObjectMaterial引用资源类型: 这些对象,在 GameObject 被 Instantiate 时会保持引用。MeshTextureShaderAudioClipBytes最佳工程实践 (Best practice)由于资源 (Asset) 对象被销毁后, 无法重复从 AssetBundle 中 Load 出来。 因此, 必须所有资 源 (Asset) 对象不再被引用时, AssetBundle 才可以被销毁。引用新创建的实例来非引用资源,使用 instantiate 创建新实例,可以使用 weakreference计数对该资源的引用引用资源,自己实现某种 ReferenceCount 机制
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1