目录
A guide to AssetBundles and Resources
1.Assets, Objects and serialization
1.1. Inside Assets and Objects
2.1. Best Practices for the Resources System
2.2. Proper uses of the Resources system
2.3. Serialization of Resources
3.3.1 AssetBundle.LoadFromMemory(Async)
3.3.2.AssetBundle.LoadFromFile(异步)
3.3.3. AssetBundleDownloadHandler
3.3.4. WWW.LoadFromCacheOrDownload
3.4. Loading Assets From AssetBundles
3.4.1. Low-level loading details
3.4.2. AssetBundle dependencies
参考官网教程:
A guide to AssetBundles and Resources
This is a series of articles that provides an in-depth discussion of Assets and resource management in the Unity engine. It seeks to provide expert developers with deep, source-level knowledge of Unity's Asset and serialization systems. It examines both the technical underpinnings of Unity's AssetBundle system and the current best practices for employing them. 提供Unity资产和序列化系统的深入源级知识。它研究了Unity的AssetBundle系统的技术基础和当前使用它们的最佳实践。
The guide is broken down into four chapters:
1.Assets, Objects and serialization discusses the low-level details of how Unity serializes Assets and handles references between Assets. It is strongly recommended that readers begin with this chapter as it defines terminology used throughout the guide.
2.The Resources folder discusses the built-in Resources API.
3.AssetBundle fundamentals builds on the information in chapter 1 to describe how AssetBundles operate, and discusses both the loading of AssetBundles and the loading of Assets from AssetBundles.
4.AssetBundle usage patterns is a long article discussing many of the topics surrounding the practical uses of AssetBundles. It includes sections on assigning Assets to AssetBundles and on managing loaded Assets, and describes many common pitfalls encountered by developers using AssetBundles.
1.资产,对象和序列化讨论了Unity如何序列化资产和处理资产之间引用的低级细节。强烈建议读者从本章开始,因为它定义了整个指南中使用的术语。
2.Resources文件夹讨论了内置的Resources API。
3.AssetBundle基础知识建立在第1章的信息基础上,用于描述AssetBundles的运作方式,并讨论AssetBundles的加载和AssetBundles的资产加载。
4.AssetBundle使用模式是一篇长篇文章,讨论围绕AssetBundles实际使用的许多主题。它包括有关将资产分配给AssetBundles和管理已加载资产的部分,并描述了使用AssetBundles的开发人员遇到的许多常见陷阱。
Note: This guide's terms for Objects and Assets differ from Unity's public API naming conventions. 注意:本指南的对象和资产术语与Unity的公共API命名约定不同。
The data this guide calls Objects are called Assets in many public Unity APIs, such as AssetBundle.LoadAssetand Resources.UnloadUnusedAssets. The files this guide calls Assets are rarely exposed to any public APIs. When they are exposed, it is generally only in build-related code, such as AssetDatabase and BuildPipeline. In these cases, they are called files in public APIs. 本指南称为Objects的数据在许多公共Unity API 中称为Assets,例如AssetBundle.LoadAsset和Resources.UnloadUnusedAssets。本指南称之为Assets的文件很少暴露给任何公共API。当它们被公开时,通常只在与构建相关的代码中,例如AssetDatabase和BuildPipeline。在这些情况下,它们在公共API 中称为files。
1.Assets, Objects and serialization
This chapter covers the deep internals of Unity's serialization system and how Unity maintains robust references between different Objects, both in the Unity Editor and at runtime. It also discusses the technical distinctions between Objects and Assets. The topics covered here are fundamental to understanding how to efficiently load and unload Assets in Unity. Proper Asset management is crucial to keeping loading times short and memory usage low.
本章介绍Unity的序列化系统的深层内部,以及Unity如何在Unity Editor和运行时维护不同对象之间的健壮引用。它还讨论了对象和资产之间的技术区别。这里涉及的主题是理解如何在Unity中有效加载和卸载资产的基础。正确的资产管理对于缩短加载时间和降低内存使用率至关重要。
1.1. Inside Assets and Objects
内部资产和对象
To understand how to properly manage data in Unity, it is important to understand how Unity identifies and serializes data. The first key point is the distinction between Assets and UnityEngine.Objects. 为了了解如何在Unity中正确管理数据,了解Unity如何识别和序列化数据非常重要。第一个重点是Assets和UnityEngine.Objects之间的区别。
An Asset is a file on disk, stored in the Assets folder of a Unity project. Textures, 3D models, or audio clips are common types of Assets. Some Assets contain data in formats native to Unity, such as materials. Other Assets need to be processed into native formats, such as FBX files. 一个资产是磁盘上的文件,存储在Unity项目的Assets文件夹中。纹理,3D模型或音频剪辑是常见的资产类型。某些资产包含Unity本机格式的数据,例如材料。其他资产需要处理为本机格式,例如FBX文件
A UnityEngine.Object, or Object with a capitalized 'O', is a set of serialized data collectively describing a specific instance of a resource. This can be any type of resource which the Unity Engine uses, such as a mesh, sprite, AudioClip or AnimationClip. All Objects are subclasses of the UnityEngine.Object base class. 一个UnityEngine.Object,或大写“O”的对象,是一组序列化的数据统称为一个资源(resource)的特定实例(instance)。这可以是Unity Engine使用的任何类型的资源,例如网格,脚本,AudioClip或AnimationClip。所有对象都是UnityEngine.Object基类的子类。
While most Object types are built-in, there are two special types. 虽然大多数对象类型都是内置的,但有两种特殊类型。
- A ScriptableObject provides a convenient system for developers to define their own data types. These types can be natively serialized and deserialized by Unity, and manipulated in the Unity Editor's Inspector window.
- A MonoBehaviour provides a wrapper that links to a MonoScript. A MonoScript is an internal data type that Unity uses to hold a reference to a specific scripting class within a specific assembly and namespace. The MonoScript does not contain any actual executable code.
There is a one-to-many relationship between Assets and Objects; that is, any given Asset file contains one or more Objects.
一个ScriptableObject提供了一个方便的系统开发人员可以定义自己的数据类型。Unity可以对这些类型进行本机序列化和反序列化,并在Unity Editor的Inspector窗口中进行操作。
一个MonoBehaviour提供一个wrapper(包装?)链接到一个MonoScript。MonoScript是一种内部数据类型,Unity用于保存对特定程序集和命名空间内特定脚本类的引用。该MonoScript并没有包含任何实际的可执行代码。
资产和对象之间存在一对多的关系; 也就是说,任何给定的Asset文件都包含一个或多个Objects
1.2. Inter-Object references
对象间引用
All UnityEngine.Objects can have references to other UnityEngine.Objects. These other Objects may reside within the same Asset file, or may be imported from other Asset files. For example, a material Object usually has one or more references to texture Objects. These texture Objects are generally imported from one or more texture Asset files (such as PNGs or JPGs). 所有UnityEngine.Objects都可以引用其他UnityEngine.Objects。这些其他对象可以驻留在同一资产文件中,也可以从其他资产文件导入。例如,材质Object通常具有一个或多个对纹理对象的引用。这些纹理对象通常从一个或多个纹理资源文件(例如PNG或JPG)导入。
When serialized, these references consist of two separate pieces of data: a File GUID and a Local ID. The File GUID identifies the Asset file where the target resource is stored. A locally unique(1) Local ID identifies each Object within an Asset file because an Asset file may contain multiple Objects. 序列化时,这些引用由两个单独的数据组成:File GUID和Local ID。文件GUID标识存储目标资源的资产文件。一个本地唯一Local ID标识资产文件中的每个对象,因为资产文件可能包含多个对象。
File GUIDs are stored in .meta files. These .meta files are generated when Unity first imports an Asset, and are stored in the same directory as the Asset. 文件GUID存储在.meta文件中。这些.meta文件是在Unity首次导入资产时生成的,并存储在与资产相同的目录中。
The above identification and referencing system can be seen in a text editor: create a fresh Unity project and change its Editor Settings to expose Visible Meta Files and to serialize Assets as text. Create a material and import a texture into the project. Assign the material to a cube in the scene and save the scene. 可以在文本编辑器中查看上述标识和引用系统:创建一个新的Unity项目并更改其编辑器设置以公开可见元文件并将资产序列化为文本。创建材质并将纹理导入到项目中。将材质指定给场景中的立方体并保存场景。
Using a text editor, open the .meta file associated with the material. A line labeled "guid" will appear near the top of the file. This line defines the material Asset's File GUID. To find the Local ID, open the material file in a text editor. The material Object's definition will look like this:
使用文本编辑器打开与材料关联的.meta文件。标有“guid”的行将出现在文件顶部附近。此行定义材料Asset的文件GUID。要查找本地ID,请在文本编辑器中打开材料文件。材质Object的定义如下所示:
--- !u!21 &2100000 Material: serializedVersion: 3 ... more data … |
In the above example, the number preceded by an ampersand is the material's Local ID. If this material Object were located inside an Asset identified by the File GUID "abcdefg", then the material Object could be uniquely identified as the combination of the File GUID "abcdefg" and the Local ID "2100000".在上面的示例中,以&符号开头的数字是素材的本地ID。如果此材料Object位于由文件GUID“abcdefg”标识的资产内,则可以将材料Object唯一标识为文件GUID“abcdefg”和本地ID“2100000”的组合。
1.3. Why File GUIDs and Local IDs?
Why is Unity's File GUID and Local ID system necessary? The answer is robustness and to provide a flexible, platform-independent workflow.
The File GUID provides an abstraction of a file's specific location. As long as a specific File GUID can be associated with a specific file, that file's location on disk becomes irrelevant. The file can be freely moved without having to update all Objects referring to the file.
As any given Asset file may contain (or produce via import) multiple UnityEngine.Object resources, a Local ID is required to unambiguously distinguish each distinct Object.
If the File GUID associated with an Asset file is lost, then references to all Objects in that Asset file will also be lost. This is why it is important that the .meta files must remain stored with the same file names and in the same folders as their associated Asset files. Note that Unity will regenerate deleted or misplaced .meta files.
The Unity Editor has a map of specific file paths to known File GUIDs. A map entry is recorded whenever an Asset is loaded or imported. The map entry links the Asset's specific path to the Asset's File GUID. If the Unity Editor is open when a .meta file goes missing and the Asset's path does not change, the Editor can ensure that the Asset retains the same File GUID.
If the .meta file is lost while the Unity Editor is closed, or the Asset's path changes without the .meta file moving along with the Asset, then all references to Objects within that Asset will be broken.
1.4. Composite Assets and importers
As mentioned in the Inside Assets and Objects section, non-native Asset types must be imported into Unity. This is done via an asset importer. While these importers are usually invoked automatically, they are also exposed to scripts via the AssetImporter API. For example, the TextureImporter API provides access to the settings used when importing individual texture Assets, such as PNG files.
The result of the import process is one or more UnityEngine.Objects. These are visible in the Unity Editor as multiple sub-assets within the parent Asset, such as multiple sprites nested beneath a texture Asset that has been imported as a sprite atlas. Each of these Objects will share a File GUID as their source data is stored within the same Asset file. They will be distinguished within the imported texture Asset by a Local ID.
The import process converts source Assets into formats suitable for the target platform selected in the Unity Editor. The import process can include a number of heavyweight operations, such as texture compression. As this is often a time-consuming process, imported Asset are cached in the Library folder, eliminating the need to re-import Assets again on the next Editor launch.
Specifically, the results of the import process are stored in a folder named for the first two digits of the Asset's File GUID. This folder is stored inside the Library/metadata/ folder. The individual Objects from the Asset are serialized into a single binary file that has a name identical to the Asset's File GUID.
This process applies to all Assets, not just non-native Assets. Native assets do not require lengthy conversion processes or re-serialization.
1.5. Serialization and instances
While File GUIDs and Local IDs are robust, GUID comparisons are slow and a more performant system is needed at runtime. Unity internally maintains a cache(2) that translates File GUIDs and Local IDs into simple, session-unique integers. These are called Instance IDs, and are assigned in a simple, monotonically-increasing order when new Objects are registered with the cache.
The cache maintains mappings between a given Instance ID, File GUID and Local ID defining the location of the Object's source data, and the instance of the Object in memory (if any). This allows UnityEngine.Objects to robustly maintain references to each other. Resolving an Instance ID reference can quickly return the loaded Object represented by the Instance ID. If the target Object is not yet loaded, the File GUID and Local ID can be resolved to the Object's source data, allowing Unity to load the object just-in-time.
At startup, the Instance ID cache is initialized with data for all Objects immediately required by the project (i.e., referenced in built Scenes), as well as all Objects contained in the Resources folder. Additional entries are added to the cache when new assets are imported at runtime(3) and when Objects are loaded from AssetBundles. Instance ID entries are only removed from the cache when an AssetBundle providing access to a specific File GUID and Local ID is unloaded. When this occurs, the mapping between the Instance ID, its File GUID and Local ID are deleted to conserve memory. If the AssetBundle is re-loaded, a new Instance ID will be created for each Object loaded from the re-loaded AssetBundle.
For a deeper discussion of the implications of unloading AssetBundles, see the Managing Loaded Assets section in the AssetBundle Usage Patterns article.
On specific platforms, certain events can force Objects out of memory. For example, graphical Assets can be unloaded from graphics memory on iOS when an app is suspended. If these Objects originated in an AssetBundle that has been unloaded, Unity will be unable to reload the source data for the Objects. Any extant references to these Objects will also be invalid. In the preceding example, the scene may appear to have invisible meshes or magenta textures.
Implementation note: At runtime, the above control flow is not literally accurate. Comparing File GUIDs and Local IDs at runtime would not be sufficiently performant during heavy loading operations. When building a Unity project, the File GUIDs and Local IDs are deterministically mapped into a simpler format. However, the concept remains identical, and thinking in terms of File GUIDs and Local IDs remains a useful analogy during runtime. This is also the reason why Asset File GUIDs cannot be queried at runtime.
1.6. MonoScripts
It is important to understand that a MonoBehaviour has a reference to a MonoScript, and MonoScripts simply contain the information needed to locate a specific script class. Neither type of Object contains the executable code of script class. 重要的是要了解MonoBehaviour具有对MonoScript的引用,而MonoScripts只包含查找特定脚本类所需的信息。这两种类型的Object都不包含脚本类的可执行代码。
A MonoScript contains three strings: assembly name, class name, and namespace.
MonoScript包含三个字符串:程序集名称,类名称和命名空间。
While building a project, Unity compiles all the loose script files in the Assets folder into Mono assemblies. C# scripts outside of the Plugins subfolder are placed into Assembly-CSharp.dll. Scripts within the Plugins subfolder are placed into Assembly-CSharp-firstpass.dll, and so on. In addition, Unity 2017.3 also introduces the ability to define custom managed assemblies. 构建项目时,Unity会将Assets文件夹中的所有松散脚本文件编译为Mono程序集。插件子文件夹之外的C#脚本放在Assembly-CSharp.dll中。Plugins子文件夹中的脚本放在Assembly-CSharp-firstpass.dll中,依此类推。此外,Unity 2017.3还引入了定义自定义托管程序集的功能。
These assemblies, as well as pre-built assembly DLL files, are included in the final build of a Unity application. They are also the assemblies to which a MonoScript refers. Unlike other resources, all assemblies included in a Unity application are loaded on application start-up. 这些程序集以及预构建的程序集DLL文件都包含在Unity应用程序的最终版本中。它们也是MonoScript引用的程序集。与其他资源不同,Unity应用程序中包含的所有程序集都在应用程序启动时加载。
This MonoScript Object is the reason why an AssetBundle (or a Scene or a prefab) does not actually contain executable code in any of the MonoBehaviour Components in the AssetBundle, Scene or prefab. This allows different MonoBehaviours to refer to specific shared classes, even if the MonoBehaviours are in different AssetBundles.
此MonoScript对象是:AssetBundle(或场景或预制件)实际上不包含AssetBundle,Scene或预制件中的任何MonoBehaviour组件中的可执行代码的原因。这允许不同的MonoBehaviours引用特定的共享类,即使MonoBehaviours位于不同的AssetBundle中。
1.7. Resource lifecycle
To reduce loading times and manage an application's memory footprint, it's important to understand the resource lifecycle of UnityEngine.Objects. Objects are loaded into/unloaded from memory at specific and defined times.
An Object is loaded automatically when:
The Instance ID mapped to that Object is dereferenced
The Object is currently not loaded into memory
The Object's source data can be located.
Objects can also be explicitly loaded in scripts, either by creating them or by calling a resource-loading API (e.g., AssetBundle.LoadAsset). When an Object is loaded, Unity tries to resolve any references by translating each reference's File GUID and Local ID into an Instance ID. An Object will be loaded on-demand the first time its Instance ID is dereferenced if two criteria are true:
The Instance ID references an Object that is not currently loaded
The Instance ID has a valid File GUID and Local ID registered in the cache
This generally occurs very shortly after the reference itself is loaded and resolved.
If a File GUID and Local ID do not have an Instance ID, or if an Instance ID with an unloaded Object references an invalid File GUID and Local ID, then the reference is preserved but the actual Object will not be loaded. This appears as a "(Missing)" reference in the Unity Editor. In a running application, or in the Scene View, "(Missing)" Objects will be visible in different ways, depending on their types. For example, meshes will appear to be invisible, while textures may appear to be magenta.
Objects are unloaded in three specific scenarios:
Objects are automatically unloaded when unused Asset cleanup occurs. This process is triggered automatically when scenes are changed destructively (i.e. when SceneManager.LoadScene is invoked non-additively), or when a script invokes the Resources.UnloadUnusedAssets API. This process only unloads unreferenced Objects; an Object will only be unloaded if no Mono variable holds a reference to the Object, and there are no other live Objects holding references to the Object. Furthermore, note that anything marked with HideFlags.DontUnloadUnusedAsset and HideFlags.HideAndDontSave will not be unloaded.
Objects sourced from the Resources folder can be explicitly unloaded by invoking the Resources.UnloadAsset API. The Instance ID for these Objects remains valid and will still contain a valid File GUID and LocalID entry. If any Mono variable or other Object holds a reference to an Object that is unloaded with Resources.UnloadAsset, then that Object will be reloaded as soon as any of the live references are dereferenced.
Objects sourced from AssetBundles are automatically and immediately unloaded when invoking the AssetBundle.Unload(true) API. This invalidates the File GUID and Local ID of the Object's Instance ID, and any live references to the unloaded Objects will become "(Missing)" references. From C# scripts, attempting to access methods or properties on an unloaded object will produce a NullReferenceException.
If AssetBundle.Unload(false) is called, live Objects sourced from the unloaded AssetBundle will not be destroyed, but Unity will invalidate the File GUID and Local ID references of their Instance IDs. It will be impossible for Unity to reload these Objects if they are later unloaded from memory and live references to the unloaded Objects remain. (4)
1.8. Loading large hierarchies
When serializing hierarchies of Unity GameObjects, such as during prefabs serialization, it is important to remember that the entire hierarchy will be fully serialized. That is, every GameObject and Component in the hierarchy will be individually represented in the serialized data. This has interesting impacts on the time required to load and instantiate hierarchies of GameObjects.
When creating any GameObject hierarchy, CPU time is spent in several different ways:
Reading the source data (from storage, from an AssetBundle, from another GameObject, etc.)
Setting up the parent-child relationships between the new Transforms
Instantiating the new GameObjects and Components
Awakening the new GameObjects and Components on the main thread
The latter three time costs are generally invariant regardless of whether the hierarchy is being cloned from an existing hierarchy or is being loaded from storage. However, the time to read the source data increases linearly with the number of Components and GameObjects serialized into the hierarchy, and is also multiplied by the speed of the data source.
On all current platforms, it is considerably faster to read data from elsewhere in memory rather than loading it from a storage device. Further, the performance characteristics of the available storage media vary widely between different platforms. Therefore, when loading prefabs on platforms with slow storage, the time spent reading the prefab's serialized data from storage can rapidly exceed the time spent instantiating the prefab. That is, the cost of the loading operation is bound to storage I/O time.
As mentioned before, when serializing a monolithic prefab, every GameObject and component's data is serialized separately, which may duplicate data. For example, a UI screen with 30 identical elements will have the identical element serialized 30 times, producing a large blob of binary data. At load time, the data for all of the GameObjects and Components on each one of those 30 duplicate elements must be read from disk before being transferred to the newly-instantiated Object. This file reading time is a significant contributor to the overall cost of instantiating large prefabs. Large hierarchies should be instantiated in modular chunks, and then be stitched together at runtime.
Unity 5.4 note: Unity 5.4 altered the representation of transforms in memory. Each root transform's entire child hierarchy is stored in compact, contiguous regions of memory. When instantiating new GameObjects that will be instantly reparented into another hierarchy, consider using the new GameObject.Instantiate overloaded variants which accept a parent argument. Using this overload avoids the allocation of a root transform hierarchy for the new GameObject. In tests, this speeds up the time required for an instantiate operation by about 5-10%.
2.The Resources folder
2.1. Best Practices for the Resources System
资源系统
Don't use it.
不要使用它。
这个强烈的建议有几个原因:
This strong recommendation is made for several reasons:
Use of the Resources folder makes fine-grained memory management more difficult使用Resources文件夹会使细粒度的内存管理变得更加困难
Improper use of Resources folders will increase application startup time and the length of builds
-As the number of Resources folders increases, management of the Assets within those folders becomes very difficult
资源文件夹使用不当会增加应用程序启动时间和构建时间
随着资源文件夹数量的增加,对这些文件夹中的资产(Assets)的管理变得非常困难
The Resources system degrades a project's ability to deliver custom content to specific platforms and eliminates the possibility of incremental content upgrades
-AssetBundle Variants are Unity's primary tool for adjusting content on a per-device basis
资源系统降低了项目向特定平台提供自定义内容的能力,并消除了增量内容升级的可能性
AssetBundle Variants是Unity基于每个设备调整内容的主要工具
2.2. Proper uses of the Resources system
正确使用资源系统
There are two specific use cases where the Resources system can be helpful without impeding good development practices: 有两个特定用例,其中资源系统可以提供帮助,而不会妨碍良好的开发实践:
1. The ease of the Resources folder makes it an excellent system to rapidly prototype. However, when a project moves into full production, the use of the Resources folder should be eliminated. Resources文件夹的简易性使其成为快速原型的优秀系统。但是,当项目进入完全生产阶段时,应该消除Resources文件夹的使用。
2. The Resources folder may be useful in some trivial cases, if the content is:在一些简单的情况下,Resources文件夹可能很有用:
Generally required throughout a project's lifetime
Not memory-intensive
Not prone to patching, or does not vary across platforms or devices
Used for minimal bootstrapping
通常在整个项目的生命周期中都需要
不是内存密集型的
不容易修补,或者不会跨平台或设备变化
用于最小的自举
Examples of this second case include MonoBehaviour singletons used to host prefabs, or ScriptableObjects containing third-party configuration data, such as a Facebook App ID. 第二种情况的示例包括用于托管预制件的MonoBehaviour单例,或包含第三方配置数据的ScriptableObject,例如Facebook App ID。
2.3. Serialization of Resources
The Assets and Objects in all folders named "Resources" are combined into a single serialized file when a project is built. This file also contains metadata and indexing information, similar to an AssetBundle. As described in the AssetBundle documentation, this index includes a serialized lookup tree that is used to resolve a given Object's name into its appropriate File GUID and Local ID. It is also used to locate the Object at a specific byte offset in the serialized file's body.
在构建项目时,名为“Resources”的所有文件夹中的Assets和Objects将合并为一个序列化文件。此文件还包含元数据和索引信息,类似于AssetBundle。如AssetBundle文档中所述,此索引包括一个序列化查找树,用于将给定Object的名称解析为其相应的File GUID和Local ID。它还用于在序列化文件正文中的特定字节偏移处定位Object。
On most platforms, the lookup data structure is a balanced search tree, which has a construction time that grows at an O(n log(n)) rate. This growth also causes the index's loading time to grow more-than-linearly as the number of Objects in Resources folders increases.
在大多数平台上,查找数据结构是平衡搜索树,其构造时间以O(n log(n))速率增长。随着Resources文件夹中对象数量的增加,这种增长也会导致索引的加载时间增长超过线性。
This operation is unskippable and occurs at application startup time while the initial non-interactive splash screen is displayed. Initializing a Resources system containing 10,000 assets has been observed to consume multiple seconds on low-end mobile devices, even though most of the Objects contained in Resources folders are rarely actually needed to load into an application's first scene.
此操作是不可映射的,并且在应用程序启动时发生,同时显示初始非交互式启动屏幕。已经观察到初始化包含10,000个资产的资源系统在低端移动设备上消耗多秒,即使资源文件夹中包含的大多数对象实际上很少需要加载到应用程序的第一个场景中。
3.AssetBundle fundamentals
本章讨论AssetBundles。它介绍了构建AssetBundle的基本系统,以及用于与AssetBundles交互的核心API。特别是,它讨论了AssetBundles本身的加载和卸载,以及AssetBundles中特定Asset和Objects的加载和卸载。
This chapter discusses AssetBundles. It introduces the fundamental systems upon which AssetBundles are built, as well as the core APIs used to interact with AssetBundles. In particular, it discusses both the loading and unloading of AssetBundles themselves, as well as the loading and unloading of specific Asset and Objects from AssetBundles.
3.1. Overview
The AssetBundle system provides a method for storing one or more files in an archival format that Unity can index and serialize. AssetBundles are Unity's primary tool for the delivery and updating of non-code content after installation. This permits developers to submit a smaller app package, minimize runtime memory pressure, and selectively load content optimized for the end-user's device.
Understanding the way AssetBundles work is essential to building a successful Unity project for mobile devices. For an overall description of AssetBundle contents, review the AssetBundle documentation.
AssetBundle系统提供了存储一个或多个文件的方法,用一种以Unity可以索引和序列化的存档格式。AssetBundles是Unity在安装后交付和更新非代码内容的主要工具。这允许开发人员提交较小的应用程序包,最小化运行时内存压力,并有选择地加载针对最终用户设备优化的内容。
了解AssetBundles的工作方式对于为移动设备构建成功的Unity项目至关重要。有关AssetBundle内容的总体描述,请查看AssetBundle文档。
3.2. AssetBundle layout
To summarize, an AssetBundle consists of two parts: a header and data segment.
总而言之,AssetBundle由两部分组成:头部和数据段。
The header contains information about the AssetBundle, such as its identifier, compression type, and a manifest. The manifest is a lookup table keyed by an Object's name. Each entry provides a byte index that indicates where a given Object can be found within the AssetBundle's data segment. On most platforms, this lookup table is implemented as a balanced search tree. Specifically, Windows and OSX-derived platforms (including iOS) employ a red-black tree. Therefore, the time needed to construct the manifest will increase more than linearly as the number of Assets within an AssetBundle grows.
标头包含有关AssetBundle的信息,例如其标识符,压缩类型和清单。清单是一个由Object名称标识的查找表。每个实体(entry)都提供一个字节索引,指示在AssetBundle的数据段中可以找到给定Object的位置。在大多数平台上,此查找表实现为平衡搜索树。具体来说,Windows和OSX派生的平台(包括iOS)使用红黑树。因此,随着AssetBundle内资产数量的增加,构建清单所需的时间将增加超过线性。
The data segment contains the raw data generated by serializing the Assets in the AssetBundle. If LZMA is specified as the compression scheme, the complete byte array for all serialized assets is compressed. If LZ4 is instead specified, bytes for separate Assets are individually compressed. If no compression is used, the data segment will remain as raw byte streams. 数据段包含通过序列化AssetBundle中的资产生成的原始数据。如果将LZMA指定为压缩方案,则会压缩所有序列化资产的完整字节数组。如果指定了LZ4,则单独压缩单独Assets的字节。如果未使用压缩,则数据段将保留为原始字节流。
Prior to Unity 5.3, Objects could not be compressed individually inside an AssetBundle. As a consequence, if a version of Unity before 5.3 is instructed to read one or more Objects from a compressed AssetBundle, Unity had to decompress the entire AssetBundle. Generally, Unity cached a decompressed copy of the AssetBundle to improve loading performance for subsequent loading requests on the same AssetBundle.
在Unity 5.3之前,无法在AssetBundle中单独压缩对象。因此,如果指示5.3之前的Unity版本从压缩的AssetBundle读取一个或多个对象,则Unity必须解压缩整个AssetBundle。通常,Unity会缓存AssetBundle的解压缩副本,以提高同一AssetBundle上后续加载请求的加载性能。
3.3. Loading AssetBundles
AssetBundles can be loaded via four distinct APIs. The behavior of these four APIs is different depending on two criteria:
AssetBundles可以通过四个不同的API加载。这四种API的行为因两个标准而异:
- Whether the AssetBundle is LZMA compressed, LZ4 compressed or uncompressed
AssetBundle是否为LZMA压缩,LZ4是压缩还是未压缩
2.The platform on which the AssetBundle is being loaded正在加载AssetBundle的平台
These APIs are: 这些API是:
AssetBundle.LoadFromMemory(Async optional异步可选)
AssetBundle.LoadFromFile(Async optional异步可选)
UnityWebRequest's DownloadHandlerAssetBundle
WWW.LoadFromCacheOrDownload (on Unity 5.6 or older在Unity 5.6或更早版本上)
3.3.1 AssetBundle.LoadFromMemory(Async)
Unity's recommendation is not to use this API. 建议不要使用此API
AssetBundle.LoadFromMemoryAsync loads an AssetBundle from a managed-code byte array (byte[] in C#). It will always copy the source data from the managed-code byte array into a newly-allocated, contiguous block of native memory. If the AssetBundle is LZMA compressed, it will decompress the AssetBundle while copying. Uncompressed and LZ4-compressed AssetBundles will be copied verbatim.
AssetBundle.LoadFromMemoryAsync从托管代码字节数组(C#中的byte [])加载AssetBundle 。它总是将源数据从托管代码字节数组复制到新分配的,连续的本机内存块中。如果AssetBundle是LZMA压缩的,它将在复制时解压缩AssetBundle。未压缩和LZ4压缩的AssetBundles将逐字复制。
The peak amount of memory consumed by this API will be at least twice the size of the AssetBundle: one copy in native memory created by the API, and one copy in the managed byte array passed to the API. Assets loaded from an AssetBundle created via this API will therefore be duplicated three times in memory: once in the managed-code byte array, once in the native-memory copy of the AssetBundle and a third time in GPU or system memory for the asset itself.
此API消耗的最大内存量至少是AssetBundle大小的两倍:API创建的本机内存中的一个副本,以及传递给API的托管字节数组中的一个副本。因此,通过此API创建的AssetBundle加载的资产将在内存中重复三次:一次在托管代码字节数组中,一次在AssetBundle的本机内存副本中,第三次在GPU或系统内存中用于资产本身。
Prior to Unity 5.3.3, this API was known as AssetBundle.CreateFromMemory. Its functionality has not changed. 在Unity 5.3.3之前,此API称为AssetBundle.CreateFromMemory。它的功能没有改变。
3.3.2.AssetBundle.LoadFromFile(异步)
AssetBundle.LoadFromFile is a highly-efficient API intended for loading uncompressed or LZ4-compressed AssetBundle from local storage, such as a hard disk or an SD card. AssetBundle.LoadFromFile是一种高效API,用于从本地存储(如硬盘或SD卡)加载未压缩或LZ4压缩的AssetBundle。
On desktop standalone, console, and mobile platforms, the API will only load the AssetBundle's header, and will leave the remaining data on disk. The AssetBundle's Objects will be loaded on-demand as loading methods (e.g. AssetBundle.Load) are called or as their InstanceIDs are dereferenced. No excess memory will be consumed in this scenario. In the Unity Editor, the API will load the entire AssetBundle into memory, as if the bytes were read off disk and AssetBundle.LoadFromMemoryAsync was used. This API can cause memory spikes to appear during AssetBundle loading if the project is profiled in the Unity Editor. This should not affect performance on-device and these spikes should be re-tested on-device before taking remedial action. 在桌面独立,控制台和移动设备平台上,API将仅加载AssetBundle的头部,并将剩余数据保留在磁盘上。当调用加载方法(例如AssetBundle.Load)或取消引用其InstanceID时,AssetBundle的对象将按需加载。在这种情况下,不会消耗多余的内存。在Unity Editor中,API会将整个AssetBundle加载到内存中,就像从磁盘读取字节并使用AssetBundle.LoadFromMemoryAsync一样。如果在Unity Editor中对项目进行了分析,则此API可能会导致在AssetBundle加载期间出现内存峰值。这不应该影响设备上的性能,并且应该在采取补救措施之前在设备上重新测试这些尖峰。
Note: On Android devices with Unity 5.3 or older, this API will fail when trying to load AssetBundles from the Streaming Assets path. This issue has been resolved in Unity 5.4. For more details, see the section Distribution - shipped with project section of the AssetBundle usage patterns chapter
注意:在使用Unity 5.3或更早版本的Android设备上,尝试从Streaming Assets路径加载AssetBundle时,此API将失败。Unity 5.4中已解决此问题。有关更多详细信息,请参阅AssetBundle使用模式一章中的分发 - 随项目一起提供的部分。(该部分为这个教程的最后一章)
Prior to Unity 5.3, this API was known as AssetBundle.CreateFromFile. Its functionality has not been changed.
3.3.3. AssetBundleDownloadHandler
The UnityWebRequest API allows developers to specify exactly how Unity should handle downloaded data and allows developers to eliminate unnecessary memory usage. The simplest way to download an AssetBundle using UnityWebRequest is call UnityWebRequest.GetAssetBundle.
该UnityWebRequest API允许开发人员指定统一究竟应该如何处理下载的数据,并允许开发者以消除不必要的内存使用情况。使用UnityWebRequest下载AssetBundle的最简单方法是调用UnityWebRequest.GetAssetBundle。
For the purposes of this guide, the class of interest is DownloadHandlerAssetBundle. Using a worker thread, it streams downloaded data into a fixed-size buffer and then spools the buffered data to either temporary storage or the AssetBundle cache, depending on how the Download Handler has been configured. All of these operations occur in native code, eliminating the risk of expanding the managed heap. Additionally, this Download Handler does not keep a native-code copy of all downloaded bytes, further reducing the memory overhead of downloading an AssetBundle.
出于本指南的目的,有关的类是DownloadHandlerAssetBundle。使用工作线程,它将下载的数据流式传输到固定大小的缓冲区,然后将缓冲的数据假脱机到临时存储或AssetBundle缓存,具体取决于下载处理程序的配置方式。所有这些操作都在本机代码中进行,从而消除了扩展托管堆的风险。此外,该下载处理程序并没有保存所有下载的字节的本机代码副本,进一步降低了下载的AssetBundle的内存开销。
LZMA-compressed AssetBundles will be decompressed during download and cached using LZ4 compression. This behavior may be changed by setting Caching.CompressionEnabled.
LZMA压缩的AssetBundles将在下载期间解压缩并使用LZ4压缩进行缓存。可以通过设置Caching.CompressionEnabled来更改此行为。
When the download is complete, the assetBundle property of the Download Handler provides access to the downloaded AssetBundle, as if AssetBundle.LoadFromFile had been called on the downloaded AssetBundle. 当下载完成后,Download Handler 的assetBundle属性提供连接到下载的AssetBundle,仿佛AssetBundle.LoadFromFile已经调用下载AssetBundle。
If caching information is provided to a UnityWebRequest object, and the requested AssetBundle already exists in Unity's cache, then the AssetBundle will become available immediately and this API will operate identically to AssetBundle.LoadFromFile.
如果向UnityWebRequest对象提供缓存信息,并且Unity缓存中已存在所请求的AssetBundle,那么AssetBundle将立即可用,并且此API将与AssetBundle.LoadFromFile完全相同。
Prior to Unity 5.6, the UnityWebRequest system used a fixed pool of worker threads and an internal job system to safeguard against excessive, concurrent downloads. The size of the thread pool was not configurable. In Unity 5.6, these safeguards have been removed to accommodate more modern hardware, and allow for faster access to HTTP response codes and headers. 在Unity 5.6之前,UnityWebRequest系统使用固定的工作线程池和内部作业系统来防止过多的并发下载。线程池的大小不可配置。在Unity 5.6中,已删除这些安全措施以适应更多现代硬件,并允许更快地访问HTTP响应代码和标头。
3.3.4. WWW.LoadFromCacheOrDownload
*Note: Beginning in Unity 2017.1, WWW.LoadFromCacheOrDownload simply wraps around UnityWebRequest. Accordingly, developers using Unity 2017.1 or higher should migrate to UnityWebRequest. WWW.LoadFromCacheOrDownload will be deprecated in a future release. *
*注意:从Unity 2017.1开始,WWW.LoadFromCacheOrDownload简单地包装UnityWebRequest。因此,使用Unity 2017.1或更高版本的开发人员应迁移到UnityWebRequest。WWW.LoadFromCacheOrDownload将在以后的版本中弃用。*
The following information is applicable to Unity 5.6 or older. 以下适用Unity 5.6或更早版本。
WWW.LoadFromCacheOrDownload is an API that allows loading of Objects from both remote servers and local storage. Files can be loaded from local storage via a file:// URL. If the AssetBundle is present in the Unity cache, this API will behave exactly like AssetBundle.LoadFromFile.
If an AssetBundle has not yet been cached, then WWW.LoadFromCacheOrDownload will read the AssetBundle from its source. If the AssetBundle is compressed, it will be decompressed using a worker thread and written into the cache. Otherwise, it will be written directly into the cache via the worker thread. Once the AssetBundle is cached, WWW.LoadFromCacheOrDownload will load header information from the cached, decompressed AssetBundle. The API will then behave identically to an AssetBundle loaded with AssetBundle.LoadFromFile. This cache is shared between WWW.LoadFromCacheOrDownload and UnityWebRequest. Any AssetBundle downloaded with one API will also be available via the other API.
While the data will be decompressed and written to the cache via a fixed-size buffer, the WWW object will keep a full copy of the AssetBundle's bytes in native memory. This extra copy of the AssetBundle is kept to support the WWW.bytes property.
Due to the memory overhead of caching an AssetBundle's bytes in the WWW object, AssetBundles should remain small - a few megabytes, at most. For more discussion of AssetBundle sizing, see the Asset assignment strategies section in the AssetBundle usage patterns chapter.
Unlike UnityWebRequest, each call to this API will spawn a new worker thread. Accordingly, on platforms with limited memory, such as mobile devices, only a single AssetBundle at a time should be downloaded using this API, in order to avoid memory spikes. Be careful of creating an excessive number of threads when calling this API multiple times. If more than 5 AssetBundles need to be downloaded, create and manage a download queue in script code to ensure that only a few AssetBundle downloads are running occurring simultaneously.
3.3.5. Recommendations
建议
In general, AssetBundle.LoadFromFile should be used whenever possible. This API is the most efficient in terms of speed, disk usage and runtime memory usage.
通常,应尽可能使用AssetBundle.LoadFromFile。在速度,磁盘使用和运行时内存使用方面,此API是最有效的。
For projects that must download or patch AssetBundles, it is strongly recommended to use UnityWebRequest for projects using Unity 5.3 or newer, and WWW.LoadFromCacheOrDownload for projects using Unity 5.2 or older. As detailed in the Distribution section of the next chapter, it is possible to prime the AssetBundle Cache with Bundles included within a project's installer.
对于必须下载或补丁AssetBundles项目,强烈建议使用UnityWebRequest在Unity 5.3或更高版本,以及项目WWW.LoadFromCacheOrDownload在Unity 5.2或以上的项目。如下一章的“ 分发”部分所述,可以使用项目安装程序中包含的Bundle来填充AssetBundle Cache。
When using either UnityWebRequest *or *WWW.LoadFromCacheOrDownload, ensure that the downloader code properly calls Dispose after loading the AssetBundle. Alternately, C#'s using statement is the most convenient way to ensure that a WWW or UnityWebRequest is safely disposed.
使用UnityWebRequest *或* WWW.LoadFromCacheOrDownload时,请确保在加载AssetBundle后下载程序代码正确调用Dispose。或者,C#的using语句是确保安全地处理WWW或UnityWebRequest的最方便的方法。
For projects with substantial engineering teams that require unique, specific caching or downloading requirements, a custom downloader may be considered. Writing a custom downloader is a non-trivial engineering task, and any custom downloader should be made compatible with AssetBundle.LoadFromFile. See the Distribution section of the next chapter for more details.
对于需要具有独特,特定缓存或下载要求的大量工程团队的项目,可以考虑使用自定义下载程序。编写自定义下载程序是一项非常重要的工程任务,任何自定义下载程序都应与AssetBundle.LoadFromFile兼容。有关更多详细信息,请参阅下一章的“ 分发”部分。
3.4. Loading Assets From AssetBundles
UnityEngine.Objects can be loaded from AssetBundles using three distinct APIs that are all attached to the AssetBundle object, which have both synchronous and asynchronous variants:
UnityEngine.Objects可以使用三个不同的API从AssetBundles加载,这些API都附加到AssetBundle对象,它们具有同步和异步变体:
- LoadAsset (LoadAssetAsync)
- LoadAllAssets (LoadAllAssetsAsync)
- LoadAssetWithSubAssets(LoadAssetWithSubAssetsAsync)
The synchronous versions of these APIs will always be faster than their asynchronous counterpart, by at least one frame. 这些API的同步版本将始终比其异步版本快至少一帧。
Asynchronous loads will load multiple Objects per frame, up to their time-slice limits. See the Low-level loading details section for the underlying technical reasons for this behavior. 异步负载将每帧加载多个对象,直到其时间片限制。有关此行为的基本技术原因,请参阅低级加载详细信息部分。(下一节)
LoadAllAssets should be used when loading multiple independent UnityEngine.Objects. It should only be used when the majority or all of the Objects within an AssetBundle need to be loaded. Compared to the other two APIs, LoadAllAssets is slightly faster than multiple individual calls to LoadAssets. Therefore, if the number of assets to be loaded is large, but less than 66% of the AssetBundle needs to be loaded at a single time, consider splitting the AssetBundle into multiple smaller bundles and using LoadAllAssets.
LoadAllAssets应该加载多个独立UnityEngine.Objects时使用。它只应在需要加载AssetBundle中的大多数或所有对象时使用。与其他两个API相比,LoadAllAssets比对LoadAssets的多个单独调用稍快。因此,如果要加载的资产数量很大,但是一次只需要加载少于66%的AssetBundle,请考虑将AssetBundle拆分为多个较小的包并使用LoadAllAssets。
LoadAssetWithSubAssets should be used when loading a composite Asset which contains multiple embedded Objects, such as an FBX model with embedded animations or a sprite atlas with multiple sprites embedded inside it. If the Objects that need to be loaded all come from the same Asset, but are stored in an AssetBundle with many other unrelated Objects, then use this API.
加载包含多个嵌入对象的复合资产时,应使用LoadAssetWithSubAssets,例如具有嵌入动画的FBX模型或嵌入了多个脚本的脚本集。如果需要加载的对象全部来自同一资产,但存储在带有许多其他无关对象的AssetBundle中,则使用此API。
For any other case, use LoadAsset or LoadAssetAsync. 其他情况,LoadAsset或LoadAssetAsync
3.4.1. Low-level loading details
底层加载细节
UnityEngine.Object loading is performed off the main thread: an Object's data is read from storage on a worker thread. Anything which does not touch thread-sensitive parts of the Unity system (scripting, graphics) will be converted on the worker thread. For example, VBOs will be created from meshes, textures will be decompressed, etc.
UnityEngine.Object加载是在主线程上执行的:从工作线程的存储中读取Object的数据。任何不接触Unity系统的线程敏感部分(脚本,图形)的东西都将在工作线程上转换。例如,VBO将从网格创建,纹理将被解压缩等。
From Unity 5.3 onward, Object loading has been parallelized. Multiple Objects are deserialized, processed and integrated on worker threads. When an Object finishes loading, its Awake callback will be invoked and the Object will become available to the rest of the Unity Engine during the next frame.
从Unity 5.3开始,对象加载已经并行化。多个对象在工作线程上反序列化,处理和集成。当Object完成加载时,将调用其Awake回调,并且Object将在下一帧对Unity Engine的其余部分可用。
The synchronous AssetBundle.Load methods will pause the main thread until Object loading is complete. They will also time-slice Object loading so that Object integration does not occupy more than a certain number of milliseconds of frame time. The number of milliseconds is set by the property Application.backgroundLoadingPriority:
同步AssetBundle.Load方法将暂停主线程,直到对象加载完成。它们还会对对象加载进行时间分片,以便对象集成不占用超过一定毫秒的帧时间。毫秒数由属性Application.backgroundLoadingPriority设置:
ThreadPriority.High: Maximum 50 milliseconds per frame每帧最多50毫秒
ThreadPriority.Normal: Maximum 10 milliseconds per frame
ThreadPriority.BelowNormal: Maximum 4 milliseconds per frame
ThreadPriority.Low: Maximum 2 milliseconds per frame.
From Unity 5.2 onwards, multiple Objects are loaded until the frame-time limit for Object loading is reached. Assuming all other factors equal, the asynchronous variants of the asset loading APIs will always take longer to complete than the comparable synchronous version due to the minimum one-frame delay between issuing the asynchronous call and the object becoming available to the Engine. 从Unity 5.2开始,加载多个对象,直到达到对象加载的帧时间限制。假设所有其他因素相等,资产加载API的异步变体将始终比同类的同步版本更长,因为发出异步调用和引擎可用的对象之间的最小一帧延迟。
3.4.2. AssetBundle dependencies
The dependencies among AssetBundles are automatically tracked using two different APIs, depending on the runtime environment. In the Unity Editor, AssetBundle dependencies can be queried via the AssetDatabase API. AssetBundle assignments and dependencies can be accessed and changed via the AssetImporter API. At runtime, Unity provides an optional API to load the dependency information generated during an AssetBundle build via a ScriptableObject-based AssetBundleManifest API.
AssetBundles之间的依赖关系使用两个不同的API自动跟踪,具体取决于运行时环境。在Unity Editor中,可以通过AssetDatabase API 查询AssetBundle依赖项。可以通过AssetImporter API 访问和更改AssetBundle分配(assignments)和依赖项。在运行时,Unity提供了一个可选API,用于通过基于ScriptableObject的AssetBundleManifest API 加载在AssetBundle构建期间生成的依赖关系信息。
An AssetBundle is dependent upon another AssetBundle when one or more of the parent AssetBundle's UnityEngine.Objects refers to one or more of the other AssetBundle's UnityEngine.Objects. For more information on inter-Object references, see the Inter-Object references section of the Assets, Objects and Serialization article.
当一个或多个父AssetBundle的UnityEngine.Object引用一个或多个其他AssetBundle的UnityEngine.Object时,AssetBundle依赖于另一个AssetBundle。有关对象间引用的更多信息,请参阅“ 资产,对象和序列化”一文的“ 对象间引用”部分。
As described in the Serialization and instances section of that article, AssetBundles serve as sources for the source data identified by the FileGUID & LocalID of each Object contained within the AssetBundle. 如该文章的序列化和实例部分所述,AssetBundles充当由AssetBundle中包含的每个Object的FileGUID和LocalID标识的源数据的源。
Because an Object is loaded when its Instance ID is first dereferenced, and because an Object is assigned a valid Instance ID when its AssetBundle is loaded, the order in which AssetBundles are loaded is not important. Instead, it is important to load all AssetBundles that contain dependencies of an Object before loading the Object itself. Unity will not attempt to automatically load any child AssetBundles when a parent AssetBundle is loaded.
因为在首次取消引用其实例ID时加载了Object,并且因为在加载AssetBundle时为Object分配了有效的实例ID,所以AssetBundle(之间)的加载顺序并不重要。相反,在加载Object本身之前加载包含Object依赖关系的所有AssetBundle非常重要。加载父AssetBundle时,Unity不会尝试自动加载任何子AssetBundle。
Example:
Assume material A refers to texture B. Material A is packaged into AssetBundle 1, and texture B is packaged into AssetBundle 2. 假设材料A引用组织B。材料A打包到AssetBundle 1中,纹理B打包到AssetBundle 2中。
In this use case, AssetBundle 2 must be loaded prior to loading Material A out of AssetBundle 1.
在此用例中,必须在从AssetBundle 1加载材料A 之前加载AssetBundle 2。
This does not imply that AssetBundle 2 must be loaded before AssetBundle 1, or that Texture B must be loaded explicitly from AssetBundle 2. It is sufficient to have AssetBundle 2 loaded prior to loading Material A out of AssetBundle 1.
这并不意味着必须在AssetBundle 1之前加载AssetBundle 2,或者必须从AssetBundle 2显式加载Texture B.在从MaterialBundle 1加载材料A之前加载AssetBundle 2就足够了。
However, Unity will not automatically load AssetBundle 2 when AssetBundle 1 is loaded. This must be done manually in script code.但是,在加载AssetBundle 1时,Unity 不会自动加载AssetBundle 2。这必须在脚本代码中手动完成。
For more information on AssetBundle dependencies, refer to the manual page.
有关AssetBundle依赖关系的更多信息,请参阅手册页。
3.4.3. AssetBundle manifests
When executing the AssetBundle build pipeline using the BuildPipeline.BuildAssetBundles API, Unity serializes an Object containing each AssetBundle's dependency information. This data is stored in a separate AssetBundle, which contains a single Object of the AssetBundleManifest type.
使用BuildPipeline.BuildAssetBundles API 执行AssetBundle构建管道(pipeline)时,Unity会序列化包含每个AssetBundle依赖项信息的Object。此数据存储在单独的AssetBundle中,该AssetBundle包含AssetBundleManifest类型的单个Object。
This Asset will be stored in an AssetBundle with the same name as the parent directory where the AssetBundles are being built. If a project builds its AssetBundles to a folder at (projectroot)/build/Client/, then the AssetBundle containing the manifest will be saved as (projectroot)/build/Client/Client.manifest.
此资产将存储在AssetBundle中,其名称与构建AssetBundle的父目录的名称相同。如果项目将AssetBundles构建到(projectroot)/ build / Client /的文件夹,则包含清单的AssetBundle将保存为(projectroot)/build/Client/Client.manifest。
The AssetBundle containing the manifest can be loaded, cached and unloaded just like any other AssetBundle. 包含清单的AssetBundle可以像任何其他AssetBundle一样加载,缓存和卸载。
The AssetBundleManifest Object itself provides the GetAllAssetBundles API to list all AssetBundles built concurrently with the manifest and two methods to query the dependencies of a specific AssetBundle:
AssetBundleManifest对象本身提供了GetAllAssetBundles API,用于列出与清单同时构建的所有AssetBundle,以及两种查询特定AssetBundle依赖关系的方法:
1.AssetBundleManifest.GetAllDependencies returns all of an AssetBundle's hierarchical dependencies, which includes the dependencies of the AssetBundle's direct children, its children's children, etc.
AssetBundleManifest.GetAllDependencies返回所有AssetBundle的层次依赖关系,包括AssetBundle的直接子节点,子节点子节点等的依赖关系。
2.AssetBundleManifest.GetDirectDependencies returns only an AssetBundle's direct children
AssetBundleManifest.GetDirectDependencies仅返回AssetBundle的直接子项
Note that both of these APIs allocate string arrays. Accordingly, they should only be used sparingly, and not during performance-sensitive portions of an application's lifetime.
请注意,这两个API都分配字符串数组。因此,它们应该只是谨慎使用,而不是在应用程序生命周期的性能敏感部分使用。
3.4.4. Recommendations
In many cases, it is preferable to load as many needed Objects as possible before players enter performance-critical areas of an application, such as the main game level or world. This is particularly critical on mobile platforms, where access to local storage is slow and the memory churn of loading and unloading Objects at play-time can trigger the garbage collector.
在许多情况下,最好在玩家进入应用程序的性能关键区域(例如主游戏级别或世界)之前加载尽可能多的所需对象。这在移动平台上尤其重要,因为移动平台对本地存储的访问速度很慢,并且在运行(交互)时加载和卸载对象的内存流失可以触发垃圾收集器。
For projects that must load and unload Objects while the application is interactive, see the Managing loaded assets section of the AssetBundle usage patterns article for more information on unloading Objects and AssetBundles.
对于必须在应用程序交互时加载和卸载对象的项目,请参阅AssetBundle使用模式文章的管理已加载资源部分,以获取有关卸载对象和AssetBundle的更多信息。
4.AssetBundle usage patterns
This chapter discusses problems and potential solutions to various aspects of using AssetBundles in practice. 本系列的前一章介绍了AssetBundles的基础知识,其中包括各种加载API的底层行为。本章讨论在实践中使用AssetBundle的各个方面的问题和可能的解决方案。
4.1Managing loaded Assets
管理已加载的资产