Unity 3D(三)附件 Unity 3D 5.6.5f1 AssetBundle官方文档的翻译

1 AssetBundles(资源包)

An AssetBundle is an archive file containing platform specific Assets (Models, Textures, Prefabs, Audio clips, and even entire Scenes) that can be loaded at runtime. AssetBundles can express dependencies between each other; e.g. a material in AssetBundle A can reference a texture in AssetBundle B. For efficient delivery over networks, AssetBundles can be compressed with a choice of built-in algorithms depending on use case requirements (LZMA and LZ4).

AssetsBundle是一个包含特定平台的资源 (模型、纹理、预制件、音频剪辑甚至整个场景) 的存档文件, 可在运行时加载。AssetBundles可以表达相互依存关系;例如资源包A中的Material可以引用资源包B中纹理。为了提高网络传输效率, AssetBundles可以根据要求选择内置算法(LZMA 和 LZ4)进行压缩。

AssetBundles can be useful for downloadable content (DLC), reducing initial install size, loading assets optimized for the end-user’s platform, and reduce runtime memory pressure.

AssetBundles对于可下载内容 (DLC) 来说非常有用, 可以减少安装文件的大小, 只加载针对特定平台优化过的资源, 并降低内存使用量。

1.1 What’s in an AssetBundle?(AssetBundle里面有什么?)

Good question, actually “AssetBundle” can refer to two different, but related things.

好问题,实际上“AssetBundle”可以指两种不同但相关的东西。

First is the actual file on disk. This we call the AssetBundle archive, or just archive for short in this document. The archive can be thought of as a container, like a folder, that holds additional files inside of it. These additional files consist of two types; the serialized file and resource files. The serialized file contains your assets broken out into their individual objects and written out to this single file. The resource files are just chunks of binary data stored separately for certain assets (textures and audio) to allow us to load them from disk on another thread efficiently.

首先是磁盘上的实际文件。我们称之为"AssetBundle存档"(在本文档中简称"存档")。 归档文件可以被视为一个容器,就像文件夹一样,可以在其中包含文件。 这些内含文件包含两种类型: 序列化文件和资源文件。序列化文件包含分解成独立对象并写入单文件的Asset。资源文件是存储某些Assets(纹理和音频)的二进制数据块,允许我们在子线程中从磁盘加载。

Second is the actual AssetBundle object you interact with via code to load assets from a specific archive. This object contains a map of all the file paths of the assets you added to this archive to the objects that belong to that asset that need to be loaded when you ask for it.

其次是实际的AssetBundle对象. 您通过代码与AssetBundle对象进行交互, 以便从文件中加载资源。此对象包含文件路径到需要加载的那个资源的映射.

2 AssetBundle Workflow(AssetBundle的使用过程)

To get started with AssetBundles, follow these steps. More detailed information about each piece of the workflow can be found in the other pages in this section of documentation.

要开始使用AssetBundles,请按照以下步骤操作。 有关每个工作流程的更多详细信息,请参阅本文档的其他页面。(注:所有页面都在这一个博客里了)

2.1 Assigning Assets to AssetBundles (将资源分配到资源包)

To assign a given Asset to an AssetBundle, follow these steps:

要将给定资源(Asset)分配给资源包(AssetBundle),请按照下列步骤操作:

  1. Select the asset you want to assign to a bundle from your Project View
  2. Examine the object in the inspector
  3. At the bottom of the inspector, you should see a section to assign AssetBundles and Variants:
  4. The left-hand drop down assigns the AssetBundle while the right-hand drop down assigns the variant
  5. Click the left-hand drop down where it says “None” to reveal the currently registered AssetBundle names
  6. If none have yet been created, you’ll see a list like that in the image above
  7. Click “New…” to create a new AssetBundle
  8. Type in the desired AssetBundle name. Note that AssetBundle names do support a type of folder structure depending on what you type. To add sub folders, separate folder names by a “/”. For example: AssetBundle name “environment/forest” will create a bundle named forest under an environment sub folder
  9. Once you’ve selected or created an AssetBundle name, you can repeat this process for the right hand drop down to assign or create a Variant name, if you desire. Variant names are not required to build the AssetBundles
  1. 从Project视图中选择要分配给AssetBundle的资源
  2. 检查Inspector视图中的对象
  3. 在Inspector视图的底部,您应该看到一个分配AssetBundles和变量的部分:
  4. 左侧下拉分配AssetBundle,而右侧下拉分配变量
  5. 单击左侧下拉列表,显示“无”,以显示当前已注册的AssetBundle名称
  6. 如果还没有创建,您将在上图中看到类似的列表
  7. 单击“新建...”以创建新的AssetBundle
  8. 输入所需的AssetBundle名称。请注意,AssetBundle名称支持一种文件夹结构,具体取决于您键入的内容。要添加子文件夹,请用“/”分隔文件夹名称。例如:AssetBundle名称“environment / forest”将在environment子文件夹下创建名为forest的包
  9. 一旦选择或创建了AssetBundle名称,您可以重复此过程, 点击右边的下拉框以分配或创建变量名称(如果需要)。构建AssetBundle不需要变量名称

To read more information on AssetBundle assignments and accompanying strategies, see documentation on Preparing Assets for AssetBundles .

想要阅读更多关于分配AssetBundle和相关策略的信息, 请访问...

2.2 Build the AssetBundles(构建AssetBundles)

Create a folder called Editor in the Assets folders, and place a script with the following contents in the folder:

在Asset文件夹下创建一个Editor文件夹, 建一个脚本, 内容如下.

using UnityEditor;

public class CreateAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        string assetBundleDirectory = "Assets/AssetBundles";
        if(!Directory.Exists(assetBundleDirectory)
{
    Directory.CreateDirectory(assetBundleDirectory);
}
BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, BuildTarget.Standalone);
    }
}

This script will create a menu item at the bottom of the Assets menu called “Build AssetBundles” that will execute the code in the function associated with that tag. When you click Build AssetBundles a progress bar will appear with a build dialogue. This will take all the assets you labeled with an AssetBundle name in and place them in a folder at the path defined by assetBundleDirectory.

此脚本将在Assets菜单底部创建一个名为“Build AssetBundles”的菜单项,该菜单项将执行与该标记关联的函数中的代码。 单击“构建AssetBundles”时,将显示一个带有进度条的构建对话框。 这将获取您标记为AssetBundle名称的所有资源,并将它们放在assetBundleDirectory定义的路径中的文件夹中。

 For more detail about what this code is doing, see documentation on Building AssetBundles.

有关此代码正在执行的操作的更多详细信息,请参阅有关构建AssetBundle的文档。

2.3 Upload AssetBundles to off-site storage(将资源包上传到离线存储器)

This step is unique to each user and not a step Unity can tell you how to do. If you plan on uploading your AssetBundles to a third party hosting site, do that here. If you’re doing strictly local development and intend to have all of your AssetBundles on disk, skip to the next step.

此步骤对每个用户来说都是不一样的,Unity无法告诉你操作的步骤。 如果您计划将AssetBundles上传到第三方托管网站,请在此处执行此操作。 如果您正在进行严格的本地开发并打算将所有AssetBundle都放在磁盘上,请跳到下一步。

2.4 Loading AssetBundles and Assets(载入资源包和资源)

For users intending to load from local storage, you’ll be interested in the AssetBundles.LoadFromFile API. Which looks like this:

对于打算从本地存储加载的用户,您将对AssetBundles.LoadFromFile 函数感兴趣。 看起来像这样:

public class LoadFromFileExample extends MonoBehaviour {
    function Start() {
        var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
        if (myLoadedAssetBundle == null) {
            Debug.Log("Failed to load AssetBundle!");
            return;
        }
        var prefab = myLoadedAssetBundle.LoadAsset.<GameObject>("MyObject");
        Instantiate(prefab);
    }
}

LoadFromFile takes the path of the bundle file.

LoadFromFile函数的参数是资源包文件的路径.

If you’re hosting your AssetBundles yourself and need to download them into your game, you’ll be interested in the UnityWebRequest API. Here’s an example:

如果您自己托管AssetBundles并需要将它们下载到游戏中,您将对UnityWebRequest 函数感兴趣。 这是一个例子:

IEnumerator InstantiateObject()

    {
        string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
        UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
        yield return request.Send();
        AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
        GameObject cube = bundle.LoadAsset<GameObject>("Cube");
        GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");
        Instantiate(cube);
        Instantiate(sprite);
    }

GetAssetBundle(string, int) takes the uri of the location of the AssetBundle and the version of the bundle you want to download. In this example we’re still pointing to a local file but the string uri could point to any url you have your AssetBundles hosted at.

GetAssetBundle(string,int)的参数是AssetBundle的位置uri和版本号。虽然在这个例子中,我们指向的是本地文件,但字符串uri可以指向您拥有AssetBundles的任何URL。

The UnityWebRequest has a specific handle for dealing with AssetBundles, DownloadHandlerAssetBundle, which gets the AssetBundle from the request.

UnityWebRequest有一个特定的函数来处理AssetBundles,DownloadHandlerAssetBundle(),它从请求中获取AssetBundle。

Regardless of the method you use, you’ll now have access to the AssetBundle object. From that object you’ll need to use LoadAsset<T>(string) which takes the type, T, of the asset you’re attempting to load and the name of the object as a string that’s inside the bundle. This will return whatever object you’re loading from the AssetBundle. You can use these returned objects just like any object inside of Unity. For example, if you want to create a GameObject in the scene, you just need to call Instantiate(gameObjectFromAssetBundle).

无论您使用哪种方法,您现在都可以访问AssetBundle对象。 获取该对象以后,您需要使用LoadAsset <T>(string),它的参数是您要加载的资源的类型T、和对象的名称(String类型)。 这将返回您从AssetBundle加载的任何对象。 您可以像使用Unity中的任何对象一样使用这些返回的对象。 例如,如果要在场景中创建GameObject,则只需调用Instantiate(gameObjectFromAssetBundle)。

For more information on APIs that load AssetBundles, see documentation on Using AssetBundles Natively.

想知道关于这些加载资源包的接口的更多信息,参见文档....

3 Preparing Assets for AssetBundles(准备要保存到资源包的资源)

When using AssetBundles you are free to assign any asset to any bundle you desire. However, there are certain strategies to consider when setting up your bundles. These grouping strategies are meant to be used however you see fit for your specific project. Feel free to mix and match these strategies as you see fit.

使用AssetBundles时,您可以随意将任何资源分配给任何资源包里。但是,在分配资源时需要考虑某些分组策略。这些分组策略的目标是适合您的项目。您可以根据需要随意混合和匹配这些策略。

3.1 Logical Entity Grouping (按逻辑实体分组)

Logical Entity Grouping is where assets are assigned to AssetBundles based on the functional portion of the project they represent. This includes sections such as User-Interface, characters, environments, and anything else that may appear frequently throughout the lifetime of the application.

按逻辑实体分组是指资源根据其所代表的项目的功能分配给AssetBundles的位置。 这包括诸如用户界面、字符、环境以及在应用程序的整个生命周期中可能经常出现的任何其他内容。

Examples(举例)

  • Bundling all the textures and layout data for a User-Interface screen
  • Bundling all the models and animations for a character/set of characters
  • Bundling the textures and models for pieces of the scenery shared across multiple levels
  • 把用户界面的所有纹理和布局数据打包在一起
  • 把一个角色/一组角色的所有模型和动画打包在一起
  • 将多个关卡共享的纹理和模型打包在一起

Logical Entity Grouping is ideal for downloadable content (DLC) for the fact that, with everything separated in this way, you’re able to make a change to a single entity and not require the download of additional, unchanged, assets.

The biggest trick to being able to properly implement this strategy is that the developer assigning assets to their respective bundles must be familiar with precisely when and where each asset will be used by the project.

逻辑实体分组是可下载内容(DLC)的理想选择,因为通过这种方式将所有内容分开,您可以对单个实体进行修改,而无需下载其他未更改的资源。

能够正确实施此策略的最大诀窍是,开发人员将资源分配到不同的资源包必须熟悉项目每个资源的使用时间和地点。

3.2 Type Grouping (按类型分组)

For this strategy you’ll assign assets that are of similar type, such as audio tracks or language localization files, to a single AssetBundle.

您可以将相似类型的资源(例如音频轨道或语言本地化文件)分配给一个AssetBundle。

Type grouping is one of the better strategies for building AssetBundles to be used by multiple platforms. For example if your audio compression settings are identical between windows and mac platforms, you can pack all audio data into AssetBundles by themselves and reuse those bundles, whereas shaders tend to get compiled with more platform specific options so a shader bundle you build for mac may not be reused on windows. In addition, this method is great for making your AssetBundles compatible with more unity player versions as textures compression formats and settings change less frequently than something like your code scripts or prefabs.

按类型分组是构建AssetBundles以供多个平台使用的更好策略之一。 例如,如果您的音频压缩设置在Windows和Mac平台之间是相同的,您可以自己将所有音频数据打包到AssetBundle并重复使用这些包,而着色器(shaders)往往在不同的平台使用不同的选项进行编译,因此您为Mac构建的着色器包可能 不能在Windows上重复使用。 此外,这种方法非常适合使您的AssetBundles与更多Unity播放器版本兼容,因为纹理压缩格式和设置的修改频率低于代码脚本或预制件(Prefab)。

3.3 Concurrent Content Grouping (按并发内容分组)

Concurrent Content Grouping is the idea that you will bundle assets together that will be loaded and used at the same time. You could think of these types of bundles as being used for a level based game where each level contains totally unique characters, textures, music, etc. You would want to be absolutely certain that an asset in one of these AssetBundles is only used at the same time the rest of the assets in that bundle are going to be used. Having a dependency on a single asset inside a Concurrent Content Grouping bundle would result in significant increased load times. You would be forced to download the entire bundle for that single asset.

按并发内容分组是指您将资源捆绑在一起,同时加载和使用。 您可以将这些类型的包视为用于基于关卡的游戏,其中每个级别包含完全独特的人物角色、纹理、音乐等。您需要绝对保证其中的资源只跟本资源包中的其它资源同时使用。其它资源包依赖于并发内容包中的某个资源会导致加载时间显著增加。因为您将必须下载包含这个资源的整个资源包。

The most common use-case for Concurrent Content Grouping bundles is for bundles that are based on scenes. In this assignment strategy, each scene bundle should contain most or all of that scenes dependencies.

按并发内容对资源包分组最常见的例子是针对基于场景的资源包。 在此分配策略中,每个场景资源包应包含大部分或全部场景依赖项。

Note that a project absolutely can and should mix these strategies as your needs require. Using the optimal asset assignment strategy for any given scenario greatly increases efficiency for any project.

请注意,项目绝对可以并且应该根据您的需求混合使用这些策略。 对特定方案使用最优资源分配策略可以大大提高效率。

For example, a project may decide to group its User-Interface (UI) elements for different platforms into their own Platform-UI specific bundle but group its interactive content by level/scene.

例如,项目应该将不同平台的用户界面(UI)元素按照平台分组,而不是按关卡(场景)对其UI进行分组。

Regardless of the strategy you follow, here are some additional tips that are good to keep in mind across the board:

  • Split frequently updated objects into AssetBundles separate from objects that rarely change
  • Group objects that are likely to be loaded simultaneously. Such as a model, its textures, and its animations
  • If you notice multiple objects across multiple AssetBundles are dependant on a single asset from a completely different AssetBundle, move the dependency to a separate AssetBundle. If several AssetBundles are referencing the same group of assets in other AssetBundles, it may be worth pulling those dependencies into a shared AssetBundle to reduce duplication.
  • If two sets of objects are unlikely to ever be loaded at the same time, such as Standard and High Definition assets, be sure they are in their own AssetBundles.
  • Consider splitting apart an AssetBundle if less that 50% of that bundle is ever frequently loaded at the same time
  • Consider combining AssetBundles that are small (less that 5 to 10 assets) but whose content is frequently loaded simultaneously
  • If a group of objects are simply different versions of the same object, consider AssetBundle Variants

无论您想用哪种策略,以下是一些最需要一直记住的提示:

  • 将频繁更新的对象与很少修改的对象分开
  • 对可能同时加载的对象进行分为一组,例如模型、纹理和动画
  • 如果您发现多个不同AssetBundle中的对象依赖于来自一个完全不同的资源包中的资源,请将依赖的资源包移动到单独的资源包中。如果多个AssetBundle引用其它多个AssetBundle中的同一组资产,则最好将这些依赖项放到共享AssetBundle中以减少重复。
  • 如果不可能同时加载两组对象,例如标准和高清属性,请确保它们位于自己的AssetBundles中。
  • 如果经常加载某个资源包中的一小部分,请拆分资源包
  • 考虑组合小资源包(少于5到10个资源)但其经常被同时加载的资源包
  • 如果一组对象只是同一对象的不同版本,请考虑AssetBundle Variants

4 Building AssetBundles (构造资源包)

In the documentation on the AssetBundle Workflow, we have a code sample which passes three arguments to the BuildPipeline.BuildAssetBundles function. Let’s dive a little deeper into what we’re actually saying.

在第二章中,我们有一个代码示例,它将三个参数传递给BuildPipeline.BuildAssetBundles函数。 让我们更深入地了解我们实际所说的内容。

Assets/AssetBundles: This is the directory that the AssetBundles will be output to. You can change this to any output directory you desire, just ensure that the folder actually exists before you attempt a build.

Assets / AssetBundles:这是AssetBundles输出的目录。您可以对输出目录任意修改,只需确保在构建(Build)之前文件夹已经存在。

4.1 BuildAssetBundleOptions (资源包构建选项)

There are several different BuildAssetBundleOptions that you can specify that have a variety of effects. See Scripting API Reference on BuildAssetBundleOptions for a table of all the options.

您可以设置不同的构建选项。 有关所有选项的表,请参阅BuildAssetBundleOptions上的脚本API文档。

While you’re free to combine BuildAssetBundleOptions as needs change and arise, there are three specific BuildAssetBundleOptions that deal with AssetBundle Compression:

您可以根据需求的变化自由组合BuildAssetBundleOptions,我们提供三个BuildAssetBundleOptions选项对资源包压缩进行配置:

  • BuildAssetBundleOptions.None: This bundle option uses LZMA Format compression, which is a single compressed LZMA stream of serialized data files. LZMA compression requires that the entire bundle is decompressed before it’s used. This results in the smallest possible file size but a slightly longer load time due to the decompression. It is worth noting that when using this BuildAssetBundleOptions, in order to use any assets from the bundle the entire bundle must be uncompressed initially. 
    Once the bundle has been decompressed, it will be recompressed on disk using LZ4 compression which doesn’t require the entire bundle be decompressed before using assets from the bundle. This is best used when a bundle contains assets such that to use one asset from the bundle would mean all assets are going to be loaded. Packaging all assets for a character or scene are some examples of bundles that might use this. 
    Using LZMA compression is only recommended for the initial download of an AssetBundle from an off-site host due to the smaller file size. Once the file has been downloaded, it will be cached as a LZ4 compressed bundle.

BuildAssetBundleOptions.None:此选项使用LZMA格式压缩,这是一个压缩的LZMA序列化数据文件流。LZMA压缩要求在使用之前对整个包进行解压缩。这导致文件大小尽可能小,但解压缩导致加载时间略长。值得注意的是,如果使用此BuildAssetBundleOptions,为了使用捆绑包中的任何一个资源,都要先解压缩整个资源包
一旦资源包被解压,它将使用LZ4压缩在磁盘上重新压缩,这不需要在使用捆绑包中的资源之前解压缩整个捆绑包。如果使用一个资源需要加载资源包中的所有资源时最好使用这种压缩方式。打包角色或场景的所有资源可能会用这种压缩算法。
由于生成的文件较小,建议仅从远程主机初次下载AssetBundle时使用LZMA压缩。下载文件后,它将被缓存为LZ4压缩包。

  • BuildAssetBundleOptions.UncompressedAssetBundle: This bundle option builds the bundles in such a way that the data is completely uncompressed. The downside to being uncompressed is the larger file download size. However, the load times once downloaded will be much faster.

BuildAssetBundleOptions.UncompressedAssetBundle:此选项以完全不压缩数据的方式构建资源包。 不压缩的缺点是文件比较大。 但是,下载后的加载时间会快得多。

  • BuildAssetBundleOptions.ChunkBasedCompression: This bundle option uses a compression method known as LZ4, which results in larger compressed file sizes than LZMA but does not require that entire bundle is decompressed, unlike LZMA, before it can be used. LZ4 uses a chunk based algorithm which allows the AssetBundle be loaded in pieces or “chunks.” Decompressing a single chunk allows the contained assets to be used even if the other chunks of the AssetBundle are not decompressed.

BuildAssetBundleOptions.ChunkBasedCompression:此捆绑选项使用LZ4的压缩方法,这导致压缩文件大小比LZMA大,但不像LZMA那样需要解压整个资源包才能使用。 LZ4使用基于块的算法,允许将AssetBundle加载成块。解压缩单个块允许在其它块没有解压的情况下使用资源。

Using ChunkBasedCompression has comparable loading times to uncompressed bundles with the added benefit of reduced size on disk.

使用ChunkBasedCompression具有与未压缩资源包相近的加载时间,并具有减小文件大小的额外好处。

4.2 BuildTarget (构建的目标平台)

BuildTarget.Standalone: Here we’re telling the build pipeline which target platform we are going to be using these AssetBundles for. You can find a list of the available explicit build targets in the Scripting API Reference for BuildTarget. However, if you’d rather not hardcode in your build target, feel free to take advantage of EditorUserBuildSettings.activeBuildTarget which will automatically find the platform you’re currently setup to build for and build your AssetBundles based on that target.

BuildTarget.Standalone:这里我们告诉构建程序我们将使用这些AssetBundles的目标平台。 您可以在BuildTarget的Scripting API文档中找到可用的显式构建目标列表。 但是,如果您不想在构建目标中进行硬编码,请随意利用EditorUserBuildSettings.activeBuildTarget,它将自动找到您当前为其构建的平台,并根据该目标构建AssetBundle。

Once you’ve properly set up your build script, it’s finally time to build your bundles. If you followed the script example above, click Assets > Build AssetBundles to kick off the process.

一旦你正确设置了构建脚本,最后就可以构建你的bundle了。 如果您已经按照上面的脚本示例进行了操作,请单击Assets > Build AssetBundles以启动该过程。

Now that you’ve successfully built your AssetBundles, you may notice that your AssetBundles directory has more files than you might have originally expected. 2*(n+1) more files, to be exact. Let’s take a minute and go over exactly what the BuildPipeline.BuildAssetBundlesyields.

现在您已经成功构建了AssetBundle,您可能会注意到您的AssetBundles目录包含的文件数量超出了原先的预期。 准确地说,有2 *(n + 1)个文件。 让我们花点时间看看BuildPipeline.BuildAssetBundlesyields究竟是什么。

For every AssetBundle you specified in the editor, you’ll notice a file with your AssetBundle name and your AssetBundle name + “.manifest”.

针对您在编辑器中指定的每个资源包,您会看到一个文件命名为您的AssetBundle名称,和另一个文件名为“AssetBundle名称.manifest”。

There will be an additional bundle and manifest that doesn’t share a name with any AssetBundle you created. It, instead, is named after the directory that it’s located in (where the AssetBundles were built to). This is the Manifest Bundle. We’ll discuss more about this and how to use it in the future.

还会有一个额外的资源包和清单,它与您创建的任何AssetBundle不共享名称。 相反,它以它所在的目录(构建资源包的目录)命名。 这是Manifest Bundle。 我们将在下面讨论更多关于此以及如何使用它的内容。

4.3 The AssetBundle File (资源包文件)

This is the file that lacks the .manifest extension and what you’ll be loading in at runtime in order to load your Assets.

资源包文件是不带.manifest扩展名的文件,是在运行时加载的资源。

The AssetBundle file is an archive that contains multiple files internally. The structure of this archive can change slightly depending on if it is an AssetBundle or a Scene AssetBundle. This is the structure of a normal AssetBundle:

AssetBundle文件是一个内部包含多个文件的存档。 文档的结构可能会略有变化,具体取决于它是AssetBundle还是Scene AssetBundle。 这是普通AssetBundle的结构:

The Scene AssetBundle changes from normal AssetBundles in that it is optimized for stream loading of a Scene and its content. This image shows the internal structure of the scene bundle:

Scene AssetBundle从普通的AssetBundle修改而来,因为它针对Scene及其内容的流加载进行了优化。

4.4 The Manifest File (清单文件)

For every bundle generated, including the additional Manifest Bundle, an associated manifest file is generated. The manifest file can be opened with any text editor and contains information such as the cyclic redundancy check (CRC) data and dependency data for the bundle. For the normal AssetBundles their manifest file will look something like this:

生成的每个资源包(包括附加的Manifest Bundle)都会生成关联的清单文件。 清单文件可以使用任何文本编辑器打开。其中包含诸如循环冗余校验(CRC)数据和资源包的依赖性数据之类的信息。 对于普通的AssetBundles,它们的清单文件长得就像这样:

ManifestFileVersion: 0
CRC: 2422268106
Hashes:
  AssetFileHash:
    serializedVersion: 2
    Hash: 8b6db55a2344f068cf8a9be0a662ba15
  TypeTreeHash:
    serializedVersion: 2
    Hash: 37ad974993dbaa77485dd2a0c38f347a
HashAppended: 0
ClassTypes:
- Class: 91
  Script: {instanceID: 0}
Assets:
  Asset_0: Assets/Mecanim/StateMachine.controller
Dependencies: {}

Which shows the contained assets, dependencies, and other information.

The Manifest Bundle that was generated will have a manifest, but it’ll look more like this:

ManifestFileVersion: 0
AssetBundleManifest:
  AssetBundleInfos:
    Info_0:
      Name: scene1assetbundle
      Dependencies: {}

This will show how AssetBundles relate and what their dependencies are. For now, just understand that this bundle contains the AssetBundleManifest object which will be incredibly useful for figuring out which bundle dependencies to load at runtime. To learn more about how to use this bundle and the manifest object, see documentation on Using AssetBundles Natively.

这显示了AssetBundles如何关联以及它们的依赖关系。现在,只需要了解这个bundle包含AssetBundleManifest对象,这对于确定在运行时加载哪些bundle依赖项非常有用。 要了解有关如何使用此资源包和清单对象的更多信息,请参阅Using AssetBundles Natively。

5 AssetBundle Dependencies (资源包依赖)

AssetBundles can become dependant on other AssetBundles if one or more of the UnityEngine.Objects contains a reference to a UnityEngine.Object located in another bundle. A dependency does not occur if the UnityEngine.Object contains a reference to a UnityEngine.Object that is not contained in any AssetBundle. In this case, a copy of the object that the bundle would be dependant on is copied into the bundle when you build the AssetBundles. If multiple objects in multiple bundles contain a reference to the same object that isn’t assigned to a bundle, every bundle that would have a dependency on that object will make its own copy of the object and package it into the built AssetBundle.

如果一个或多个UnityEngine.Objects包含对位于另一个资源包中的UnityEngine.Object的引用,则称一个资源包依赖于另一个资源包。 如果某个UnityEngine.Object引用了任何AssetBundle都没有包含的UnityEngine.Object,则不会发生依赖关系,在这种情况下,构建AssetBundle时,资源包所依赖对象的副本将复制到资源包里。 如果多个包中的多个对象都引用同一个没有分配给包的对象,则每个对该对象具有依赖关系的包 都将创建其这个对象的副本。

Should an AssetBundle contain a dependency, it is important that the bundles that contain those dependencies are loaded before the object you’re attempting to instantiate is loaded. Unity will not attempt to automatically load dependencies.

如果AssetBundle包含依赖项,则在加载您尝试实例化的对象之前,必须加载包含这些依赖项的资源包。Unity不会自动加载依赖项

Consider the following example, a Material in Bundle 1 references a Texture in Bundle 2:

In this example, before loading the Material from Bundle 1, you would need to load Bundle 2 into memory. It does not matter which order you load Bundle 1 and Bundle 2, the important takeaway is that Bundle 2 is loaded before loading the Material from Bundle 1. In the next section, we’ll discuss how you can use the AssetBundleManifest objects we touched on in the previous section to determine, and load, dependencies at runtime.

 考虑以下示例,Bundle 1中的Material(材质)引用了Bundle 2中的Texture(纹理):

在此示例中,在从Bundle 1加载Material之前,您需要将Bundle 2加载到内存中。 加载Bundle 1和Bundle 2的顺序无关紧要,重要的是在从Bundle 1加载Material之前加载Bundle 2。在下一节中,我们将讨论如何使用我们在上一节中提到的AssetBundleManifest对象,在运行时确定并加载依赖项。

 6 Using AssetBundles Natively (使用本地资源包)

In Unity 5 there are four different APIs that we can use to load AssetBundles. Their behavior varies based on the platform the bundle is being loaded and the compression method used when the AssetBundles were built (uncompressed, LZMA, LZ4).

The four APIs we have to work with are:

在Unity 5中,我们可以使用四种不同的API来加载AssetBundle。 它们的行为根据加载bundle的平台和构建AssetBundle时使用的压缩方法(未压缩,LZMA,LZ4)而有所不同。

我们必须使用的四个API是:

6.1 AssetBundle.LoadFromMemoryAsync (资源包.异步内存加载)

AssetBundle.LoadFromMemoryAsync

This function takes an array of bytes that contains AssetBundle data. Optionally you can also pass in a CRC value if you desire. If the bundle is LZMA compressed it will decompress the AssetBundle while it’s loading. LZ4 compressed bundles are loaded in their compressed state.

Here’s one example of how to use this method:

此函数的参数是包含AssetBundle数据的字节数组。 如果资源包是LZMA压缩的, 您也可以根据需要传递CRC值. 它将在加载时解压缩AssetBundle。经LZ4压缩的资源包以其压缩状态加载。

以下是如何使用此方法的一个示例:

    IEnumerator LoadFromMemoryAsync(string path)

    {

        AssetBundleCreateRequest createRequest = AssetBundle.LoadFromMemoryAsync(File.ReadAllBytes(path));

        yield return createRequest;

        AssetBundle bundle = createRequest.assetBundle;

        var prefab = bundle.LoadAsset.<GameObject>("MyObject");
        Instantiate(prefab);

    }

However, this is not the only strategy that makes using LoadFromMemoryAsync possible. File.ReadAllBytes(path) could be replaced with any desired procedure of obtaining a byte array.

但是,这不是使用LoadFromMemoryAsync的唯一方法。 File.ReadAllBytes(path)可以替换为能够获得字节数组的任何函数。

6.2 AssetBundle.LoadFromFile (资源包.从文件加载)

AssetBundle.LoadFromFile

This API is highly-efficient when loading uncompressed bundles from local storage. LoadFromFile will load the bundle directly from disk if the bundle is uncompressed or chunk (LZ4) compressed. Loading a fully compressed (LZMA) bundle with this method will first decompress the bundle before loading it into memory.

One example of how to use LoadFromFile:

从本地加载未压缩的包时,此API非常高效。 如果资源包未压缩或使用了压缩块(LZ4)压缩,LoadFromFile将直接从磁盘加载资源包。 使用此方法加载完全压缩(LZMA)资源包将首先解压缩捆绑包,然后再将其加载到内存中。

如何使用LoadFromFile的一个示例:

public class LoadFromFileExample extends MonoBehaviour {
    function Start() {
        var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
        if (myLoadedAssetBundle == null) {
            Debug.Log("Failed to load AssetBundle!");
            return;
        }
        var prefab = myLoadedAssetBundle.LoadAsset.<GameObject>("MyObject");
        Instantiate(prefab);
    }
}

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 is because the contents of that path will reside inside a compressed .jar file. Unity 5.4 and newer can use this API call with Streaming Assets just fine.

注意:在使用Unity 5.3或更早版本的Android设备上,尝试从Streaming Assets文件夹加载AssetBundles时,此API将失败。 这是因为该路径的内容将驻留在压缩的.jar文件中。 Unity 5.4和更新版本可以将此API方法与Streaming Assets一起使用。

6.3 WWW.LoadFromCacheOrDownload (WWW.下载或从缓存加载)

WWW.LoadFromCacheOrDownload

TO BE DEPRECATED (Use UnityWebRequest) - 即将被废弃(请使用UnityWebRequest)

This API is useful for downloading AssetBundles from a remote server or loading local AssetBundles. It is the older, and less desirable version of the UnityWebRequest API.

此API对于从远程服务器下载AssetBundle或加载本地AssetBundle非常有用。 它是UnityWebRequest API的较旧且不太理想的版本。

Loading an AssetBundle from a remote location will automatically cache the AssetBundle. If the AssetBundle is compressed, a worker thread will spin up to decompress the bundle and write it to the cache. Once a bundle has been decompressed and cached, it will load exactly like AssetBundle.LoadFromFile.

One example of how to use LoadFromCacheOrDownload:

从远程位置加载资源包时将自动缓存此资源包。 如果AssetBundle被压缩,解压缩资源包并将其写入缓存的子线程将启动。 一旦资源包被解压缩并缓存,它就会像AssetBundle.LoadFromFile一样加载。

这是使用LoadFromCacheOrDownload的一个示例:

using UnityEngine;
using System.Collections;

public class LoadFromCacheOrDownloadExample : MonoBehaviour
{
    IEnumerator Start ()
    {
            while (!Caching.ready)
                    yield return null;

        var www = WWW.LoadFromCacheOrDownload("http://myserver.com/myassetBundle", 5);
        yield return www;
        if(!string.IsNullOrEmpty(www.error))
        {
            Debug.Log(www.error);
            yield return;
        }
        var myLoadedAssetBundle = www.assetBundle;

        var asset = myLoadedAssetBundle.mainAsset;
    }
}

Due to the memory overhead of caching an AssetBundle’s bytes in the WWW object, it is recommended that all developers using WWW.LoadFromCacheOrDownload ensure that their AssetBundles remain small - a few megabytes, at most. It is also recommended that developers operating on limited-memory platforms, such as mobile devices, ensure that their code downloads only a single AssetBundle at a time, in order to avoid memory spikes.

由于在WWW对象中缓存AssetBundle字节的内存开销,建议所有使用WWW.LoadFromCacheOrDownload的开发人员确保他们的AssetBundles保持较小 - 最多只有几兆字节。还建议在有限内存平台(如移动设备)上运行的开发人员确保他们的代码一次只下载一个AssetBundle,以避免内存飙升。

If the cache folder does not have any space for caching additional files, LoadFromCacheOrDownload will iteratively delete the least-recently-used AssetBundles from the Cache until sufficient space is available to store the new AssetBundle. If making space is not possible (because the hard disk is full, or all files in the cache are currently in use), LoadFromCacheOrDownload() will bypass Caching and stream the file into memory.

如果缓存文件夹没有任何用于缓存其他文件的空间,LoadFromCacheOrDownload将迭代地从缓存中删除最近最少使用的AssetBundle,直到有足够的空间来存储新的AssetBundle。 如果无法创建空间(因为硬盘已满,或者当前正在使用缓存中的所有文件),LoadFromCacheOrDownload()将绕过缓存并将文件流式传输到内存中。

In order to force LoadFromCacheOrDownload the version parameter (the second parameter) will need to change. The AssetBundle will only be loaded from cache if the version passed to the function matches the version of the currently cached AssetBundle.

为了强制LoadFromCacheOrDownload,需要更改版本参数(第二个参数)。如果传递给函数的版本与当前缓存的AssetBundle的版本匹配,则只会从缓存加载AssetBundle。

6.4 UnityWebRequest (Unity网络请求)

UnityWebRequest

The UnityWebRequest has a specific API call to deal with AssetBundles. To begin, you’ll need to create your web request using UnityWebRequest.GetAssetBundle. After returning the request, pass the request object into DownloadHandlerAssetBundle.GetContent(UnityWebRequest). This GetContent call will return your AssetBundle object.

UnityWebRequest有一个特定的API调用来处理AssetBundles。 首先,您需要使用UnityWebRequest.GetAssetBundle创建Web请求。 返回请求后,将请求对象传递给DownloadHandlerAssetBundle.GetContent(UnityWebRequest)。 此GetContent调用将返回您的AssetBundle对象。 

You can also use the assetBundle property on the DownloadHandlerAssetBundle class after downloading the bundle to load the AssetBundle with the efficiency of AssetBundle.LoadFromFile.

下载资源包后,您还可以在DownloadHandlerAssetBundle类上使用assetBundle属性,和使用AssetBundle.LoadFromFile加载AssetBundle一样高效。 

Here’s an example of how to load an AssetBundle that contains two GameObjects and Instantiate them. To begin this process, we’d just need to call StartCoroutine(InstantiateObject());

这是一个如何加载包含两个GameObject并实例化它们的AssetBundle的示例。 要执行这个函数,我们只需要调用StartCoroutine(InstantiateObject()); 

IEnumerator InstantiateObject()

    {
        string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
        UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
        yield return request.Send();
        AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
        GameObject cube = bundle.LoadAsset<GameObject>("Cube");
        GameObject sprite = bundle.LoadAsset<GameObject>("Sprite");
        Instantiate(cube);
        Instantiate(sprite);
    }

The advantages of using UnityWebRequest is that it allows developers to handle the downloaded data in a more flexible manner and potentially eliminate unnecessary memory usage. This is the more current and preferred API over the UnityEngine.WWW class.

使用UnityWebRequest的优点是它允许开发人员以更灵活的方式处理下载的数据,并可能消除不必要的内存使用。 这是UnityEngine.WWW类中当前和首选的API。

6.4.1 Loading Assets from AssetBundles (从资源包中加载资源)

Now that you’ve successfully downloaded your AssetBundle, it’s time to finally load in some Assets.

Generic code snippet:

现在您已经成功下载了AssetBundle,现在是时候最终加载一些Assets了。

通用代码段:

T objectFromBundle = bundleObject.LoadAsset<T>(assetName);

T is the type of the Asset you’re attempting to load.

T是你想加载的资源的类型.

There are a couple options when deciding how to load Assets. We have LoadAssetLoadAllAssets, and their Async counterparts LoadAssetAsync and LoadAllAssetsAsync respectively.

决定如何加载资源时有几个选项, 我们提供LoadAsset、LoadAllAssets及其对应的异步函数LoadAssetAsync和LoadAllAssetsAsync。

This is how to load an asset from an AssetBundles synchronously:

这是同步加载资源包的方式:

To load a single GameObject:(载入一个单独的GameObject)

GameObject gameObject = loadedAssetBundle.LoadAsset<GameObject>(assetName);

To load all Assets: (载入所有资源)

Unity.Object[] objectArray = loadedAssetBundle.LoadAllAssets();

Now, where as the previously shown methods return either the type of object you’re loading or an array of objects, the asynchronous methods return an AssetBundleRequest. You’ll need to wait for this operation to complete before accessing the asset. To load an asset:

现在,在前面展示的函数返回您要加载的对象类型或对象数组,而异步方法返回AssetBundleRequest。 在访问资源之前,您需要等待此操作完成。 要加载资源: 

AssetBundleRequest request = loadedAssetBundleObject.LoadAssetAsync<GameObject>(assetName);
yield return request;
var loadedAsset = request.asset;

And

AssetBundleRequest request = loadedAssetBundle.LoadAllAssetsAsync();
yield return request;
var loadedAssets = request.allAssets;

Once you have loaded your Assets you’re good to go! You’re able to use the loaded objects as you would any Object in Unity.

加载资源后,您就可以开始了! 您可以像使用Unity中的任何对象一样使用加载的对象。

6.4.3 Loading AssetBundle Manifests (加载资源包清单)

Loading AssetBundle manifests can be incredibly useful. Especially when dealing with AssetBundle dependencies.

To get a useable AssetBundleManifest object, you’ll need to load that additional AssetBundle (the one that’s named the same thing as the folder it’s in) and load an object of type AssetBundleManifest from it.

Loading the manifest itself is done exactly the same as any other Asset from an AssetBundle:

加载资源包清单可能非常有用。 特别是在处理资源包依赖时。

要获得可用的AssetBundleManifest对象,您需要加载另外的资源包(与其所在的文件夹名称相同的那个资源包),并从中加载一个AssetBundleManifest类型的对象。

加载清单本身与加载资源包中的其他资产完全相同:

AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

Now you have access to the AssetBundleManifest API calls through the manifest object from the above example. From here you can use the manifest to get information about the AssetBundles you built. This information includes dependency data, hash data, and variant data for the AssetBundles.

现在,您可以通过上面示例中的清单对象访问AssetBundleManifest API。 从这里,您可以使用清单获取有关您构建的AssetBundle的信息。 此信息包括AssetBundles的依赖关系数据,哈希数据和变量数据。

Remember in the earlier section when we discussed AssetBundle Dependencies and how, if a bundle had a dependency on another bundle, those bundles would need to be loaded in before loading any Assets from the original bundle? The manifest object makes dynamically finding a loading dependencies possible. Let’s say we want to load all the dependencies for an AssetBundle named “assetBundle”.

在前面的部分中我们讨论过AssetBundle依赖, 以及如果资源包对另一个资源包有依赖关系,那么在从原始资源包加载资源之前,那些资源包应该怎样被加载? 清单对象可以动态地查找加载依赖项。 假设我们想要为名为“assetBundle”的AssetBundle加载所有依赖项。

AssetBundle assetBundle = AssetBundle.LoadFromFile(manifestFilePath);
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] dependencies = manifest.GetAllDependencies("assetBundle"); //Pass the name of the bundle you want the dependencies for.
foreach(string dependency in dependencies)
{
    AssetBundle.LoadFromFile(Path.Combine(assetBundlePath, dependency));
}

Now that you’re loading AssetBundles, AssetBundle dependencies, and Assets, it’s time to talk about managing all of these loaded AssetBundles.

现在您正在加载资源包,资源包依赖项和资源,现在是时候讨论管理所有这些已加载的AssetBundle了。 

6.5 Managing Loaded AssetBundles (管理加载的资源)

See also: Unity Learn tutorial on Managing Loaded AssetBundles

参见: Unity 学习教程之"管理加载的资源包"

Unity does not automatically unload Objects when they are removed from the active scene. Asset cleanup is triggered at specific times, and it can also be triggered manually.

It is important to know when to load and unload an AssetBundle. Improperly unloading an AssetBundle can lead to duplicating objects in memory or other undesirable circumstances, such as missing textures.

从场景中删除对象时,Unity不会自动卸载对象。 资源清理在特定时刻触发,也可以手动触发。

了解何时加载和卸载AssetBundle非常重要。 不正确地卸载AssetBundle会导致在内存中复制对象或其他不良情况,例如缺少纹理。

The biggest thing to understand about AssetBundle management is when to call

最重要的事情是理解资源包管理什么时候触发

AssetBundle.Unload(bool); and if you should pass true or false into the function call. Unload is a non-static function that will unload your AssetBundle. This API unloads the header information of the AssetBundle being called. The argument indicates whether to also unload all Objects instantiated from this AssetBundle.

AssetBundle.Unload(bool); 你应该给函数传递TRUE或FALSE。 卸载是一个非静态函数,可以卸载您的资源包。 此API卸载正在调用的资源包的标头信息。 参数指示是否还卸载从此资源包实例化的所有对象。

If you were to use AssetBundle.Unload(true) the objects that you loaded from the AssetBundle, even if they’re being currently used in the active scene. This is what can cause textures to go missing, as we mentioned earlier.

如果您要使用AssetBundle.Unload(true)卸载从资源包加载的对象,即使它们当前正在活动场景中使用。 正如我们前面提到的,这可能导致纹理丢失。

Let’s assume Material M is loaded from AssetBundle AB as shown below.

If AB.Unload(true) is called. Any instance of M in the active scene will also be unload and destroyed.

If you were instead to call AB.Unload(false) it would break the chain of the current instances of M and AB.

If AB is loaded again later and AB.LoadAsset() is called, Unity will not re-link the existing copies of M to the newly loaded Material. There will instead be two copies of M loaded.

Generally, using AssetBundle.Unload(false) does not lead to an ideal situation. Most projects should use AssetBundle.Unload(true) to keep from duplicating objects in memory.

Most projects should use AssetBundle.Unload(true) and adopt a method to ensure that Objects are not duplicated. Two common methods are:

  • Having well-defined points during the application’s lifetime at which transient AssetBundles are unloaded, such as between levels or during a loading screen.

  • Maintaining reference-counts for individual Objects and unload AssetBundles only when all of their constituent Objects are unused. This permits an application to unload & reload individual Objects without duplicating memory.

If an application must use AssetBundle.Unload(false), then individual Objects can only be unloaded in two ways:

If you’d rather not manage loading Asset Bundes, dependencies, and Assets yourself, you might find yourself in need of the AssetBundle Manager.

7 AssetBundle Manager (资源包管理器)

The AssetBundle Manager, which can be downloaded here, is a tool made by Unity to make using AssetBundles more streamlined.

Downloading and importing the AssetBundle Manager package not only adds a new API calls for loading and using AssetBundles but it adds some Editor functionality to streamline the workflow as well. This functionality can be found under the Assets menu option.

资源包管理器可以在这里下载,它是Unity制作的工具,可以更加简化AssetBundles。

下载和导入AssetBundle Manager软件包不仅会加载和使用资源包添加新的API调用,还会添加一些编辑器功能来简化工作流程。 可以在“资源”菜单选项下找到此功能。

This new section will contain the following options:

7.1 Simulation Mode (模拟模式)

Enabling Simulation Mode allows the AssetBundle Manager to work with AssetBundles but does not require the bundles themselves actually be built. The editor looks to see what Assets have been assigned to AssetBundles and uses the Assets directly, instead of actually pulling them from an AssetBundle.

The main advantage of using Simulation Mode is that Assets can be modified, updated, added, and deleted without the need to re-build and deploy the AssetBundles every time.

It is worth noting that AssetBundle Variants do not work with Simulation Mode. If you need to use variants, Local AssetBundle Server is the option you need.

7.2 Local AssetBundle Server (本地资源包服务器)

The AssetBundle Manager can also start a Local AssetBundle Server which can be used to test AssetBundles in the editor or in local builds (including Mobile).

The stipulation to getting the Local AssetBundle Server to work is that you must create a folder called AssetBundles in the root directory of your project which is the same level as the Assets folder. Such as:

After you create the folder you’ll need to build your AssetBundles to this folder. To do this, select Build AssetBundles from the new menu options. This will build them to that directory for you.

Now you have your AssetBundles built (or have decided to use Simulation Mode) and are ready to start loading AssetBundles. Let’s look at the new API calls available to us through the AssetBundle Manager.

7.3 AssetBundleManager.Initialize()

This function loads the AssetBundleManifest object. You’ll need to call this before you start loading in Assets using the AssetBundle Manager. In a very simplified example, initializing the AssetBundle Manager could look like this:

IEnumerator Start()

{
    yield return StartCoroutine(Initialize());
}
IEnumerator Initialize()
{
    var request = AssetBundleManager.Initialize();
if (request != null)
    yield return StartCoroutine(request);
}

The AssetBundle Manager uses this manifest you load during the Initialize() to help with a number of features behind the scenes, including dependency management.

7.4 Loading Assets

Let’s get right down to it. You’re using the AssetBundle Manager, you’ve initialized it, and now you’re ready to load some Assets. Let’s take a look at how to load the AssetBundle and instantiate an object from that bundle:

IEnumerator InstantiateGameObjectAsync (string assetBundleName, string assetName)

{
    // Load asset from assetBundle.
    AssetBundleLoadAssetOperation request = AssetBundleManager.LoadAssetAsync(assetBundleName, assetName, typeof(GameObject) );
    if (request == null)
        yield break;
    yield return StartCoroutine(request);
    // Get the asset.
    GameObject prefab = request.GetAsset<GameObject> ();
    if (prefab != null)
        GameObject.Instantiate(prefab);
}

The AssetBundle Manager performs all of it’s load operation asynchronously so it returns a load operation request that loads the bundle upon calling yield return StartCoroutine(request); From there all we need to do is call the GetAsset<T>() to load a game object from the AssetBundle.

7.5 Loading Scenes

If you’ve got an AssetBundle name assigned to a scene and you need to load that scene in you’ll need to follow a slightly different code path. The pattern is relatively the same, but with slight differences. Here’s how to load a scene from an AssetBundle:

IEnumerator InitializeLevelAsync (string levelName, bool isAdditive)

{
    // Load level from assetBundle.
    AssetBundleLoadOperation request = AssetBundleManager.LoadLevelAsync(sceneAssetBundle, levelName, isAdditive);
    if (request == null)
        yield break;
    yield return StartCoroutine(request);
}

As you can see, loading scenes is also an asynchronous and LoadLevelAsync returns a load operation request which will need to be passed to a StartCoroutine in order to load the scene.

7.6 Load Variants

Loading variants using the AssetBundle Manager doesn’t actually change the code need to load in the scenes or assets. All that needs to be done is set the ActiveVariants property of the AssetBundleManager.

The ActiveVariants property is an array of strings. Simply build an array of strings containing the names of the variants you created during assigning them to the Assets. Here’s how to load a scene AssetBundle with the hd variant.

IEnumerator InitializeLevelAsync (string levelName, bool isAdditive, string[] variants)

{
    //Set the activeVariants.
    AssetBundleManager.ActiveVariants = variants;
    // Load level from assetBundle.
    AssetBundleLoadOperation request = AssetBundleManager.LoadLevelAsync(variantSceneAssetBundle, levelName, isAdditive);
    if (request == null)
        yield break;
    yield return StartCoroutine(request);
}

Where you’d pass in the string array you built up elsewhere in your code (perhaps from a button click or some other circumstances). This will load the bundles that match the set active variants if it is available.

8 Patching with AssetBundles

Patching AssetBundles is as simple as downloading a new AssetBundle and replacing the existing one. If WWW.LoadFromCacheOrDownload or UnityWebRequest are used to manage an application’s cached AssetBundles, passing a different version parameter to the chosen API will trigger a download of the new AssetBundles.

The more difficult problem to solve in the patching system is detecting which AssetBundles to replace. A patching system requires two lists of information:

  • A list of the currently downloaded AssetBundles, and their versioning information
  • A list of the AssetBundles on the server, and their versioning information

The patcher should download the list of server-side AssetBundles and compare the AssetBundle lists. Missing AssetBundles, or AssetBundles whose versioning information has changed, should be re-downloaded.

It is also possible to write a custom system for detecting changes to AssetBundles. Most developers who write their own system choose to use an industry-standard data format for their AssetBundle file lists, such as JSON, and a standard C# class for computing checksums, such as MD5.

Unity builds AssetBundles with data ordered in a deterministic manner. This allows applications with custom downloaders to implement differential patching.

Unity does not provide any built-in mechanism for differential patching and neither WWW.LoadFromCacheOrDownload nor UnityWebRequestperform differential patching when using the built-in caching system. If differential patching is a requirement, then a custom downloader must be written.

9 Troubleshooting

This section describes several problems that commonly appear in projects using AssetBundles.

Asset Duplication

Unity 5’s AssetBundle system will discover all dependencies of an Object when the Object is built into an AssetBundle. This is done using the Asset Database. This dependency information is used to determine the set of Objects that will be included in an AssetBundle.

Objects that are explicitly assigned to an AssetBundle will only be built into that AssetBundle. An Object is “explicitly assigned” when that Object’s AssetImporter has its assetBundleName property set to a non-empty string.

Any Object that is not explicitly assigned in an AssetBundle will be included in all AssetBundles that contain 1 or more Objects that reference the untagged Object.

If two different Objects are assigned to two different AssetBundles, but both have references to a common dependency Object, then that dependency Object will be copied into both AssetBundles. The duplicated dependency will also be instanced, meaning that the two copies of the dependency Object will be considered different Objects with a different identifiers. This will increase the total size of the application’s AssetBundles. This will also cause two different copies of the Object to be loaded into memory if the application loads both of its parents.

There are several ways to address this problem:

  1. Ensure that Objects built into different AssetBundles do not share dependencies. Any Objects which do share dependencies can be placed into the same AssetBundle without duplicating their dependencies.

    • This method usually is not viable for projects with many shared dependencies. It can produce monolithic AssetBundles that must be rebuilt and re-downloaded too frequently to be convenient or efficient.
  2. Segment AssetBundles so that no two AssetBundles that share a dependency will be loaded at the same time.

    • This method may work for certain types of projects, such as level-based games. However, it still unnecessarily increases the size of the project’s AssetBundles, and increases both build times and loading times.
  3. Ensure that all dependency assets are built into their own AssetBundles. This entirely eliminates the risk of duplicated assets, but also introduces complexity. The application must track dependencies between AssetBundles, and ensure that the right AssetBundles are loaded before calling any AssetBundle.LoadAsset APIs.

In Unity 5, Object dependencies are tracked via the AssetDatabase API, located in the UnityEditor namespace. As the namespace implies, this API is only available in the Unity Editor and not at runtime. AssetDatabase.GetDependencies can be used to locate all of the immediate dependencies of a specific Object or Asset. Note that these dependencies may have their own dependencies. Additionally, the AssetImporter API can be used to query the AssetBundle to which any specific Object is assigned.

By combining the AssetDatabase and AssetImporter APIs, it is possible to write an Editor script that ensures that all of an AssetBundle’s direct or indirect dependencies are assigned to AssetBundles, or that no two AssetBundles share dependencies that have not been assigned to an AssetBundle. Due to the memory cost of duplicating assets, it is recommended that all projects have such a script.

Sprite Atlas Duplication

The following sections describe a quirk of Unity 5’s asset dependency calculation code when used in conjunction with automatically-generated sprite atlases.

Any automatically-generated sprite atlas will be assigned to the AssetBundle containing the Sprite Objects from which the sprite atlas was generated. If the sprite Objects are assigned to multiple AssetBundles, then the sprite atlas will not be assigned to an AssetBundle and will be duplicated. If the Sprite Objects are not assigned to an AssetBundle, then the sprite atlas will also not be assigned to an AssetBundle.

To ensure that sprite atlases are not duplicated, check that all sprites tagged into the same sprite atlas are assigned to the same AssetBundle.

Unity 5.2.2p3 and older

Automatically-generated sprite atlases will never be assigned to an AssetBundle. Because of this, they will be included in any AssetBundles containing their constituent sprites and also any AssetBundles referencing their constituent sprites.

Because of this problem, it is strongly recommended that all Unity 5 projects using Unity’s sprite packer upgrade to Unity 5.2.2p4, 5.3 or any newer version of Unity.

For projects that cannot upgrade, there are two workarounds for this problem:

  1. Easy: Avoid using Unity’s built-in sprite packer. Sprite atlases generated by external tools will be normal Assets, and can be properly assigned to an AssetBundle.

  2. Hard: Assign all Objects that use automatically atlased sprites to the same AssetBundle as the sprites.

    • This will ensure that the generated sprite atlas is not seen as the indirect dependency of any other AssetBundles and will not be duplicated.

    • This solution preserves the workflow of using Unity’s sprite packer, but it degrades developers’ ability to separate Assets into different AssetBundles, and forces the re-download of an entire sprite atlas when any data changes on any component referencing the atlas, even if the atlas itself is unchanged.

Android Textures

Due to heavy device fragmentation in the Android ecosystem, it is often necessary to compress textures into several different formats. While all Android devices support ETC1, ETC1 does not support textures with alpha channels. Should an application not require OpenGL ES 2 support, the cleanest way to solve the problem is to use ETC2, which is supported by all Android OpenGL ES 3 devices.

Most applications need to ship on older devices where ETC2 support is unavailable. One way to solve this problem is with Unity 5’s AssetBundle Variants. (Please see Unity’s Android optimization guide for details on other options.)

To use AssetBundle Variants, all textures that cannot be cleanly compressed using ETC1 must be isolated into texture-only AssetBundles. Next, create sufficient variants of these AssetBundles to support the non-ETC2-capable slices of the Android ecosystem, using vendor-specific texture compression formats such as DXT5, PVRTC and ATITC. For each AssetBundle Variant, change the included textures’ TextureImporter settings to the compression format appropriate to the Variant.

At runtime, support for the different texture compression formats can be detected using the SystemInfo.SupportsTextureFormat API. This information should be used to select and load the AssetBundle Variant containing textures compressed in a supported format.

More information on Android texture compression formats can be found here.

iOS File Handle Overuse

The issue described in the following section was fixed in Unity 5.3.2p2. Current versions of Unity are not affected by this issue.

In versions prior to Unity 5.3.2p2, Unity would hold an open file handle to an AssetBundle the entire time that the AssetBundle is loaded. This is not a problem on most platforms. However, iOS limits the number of file handles a process may simultaneously have open to 255. If loading an AssetBundle causes this limit to be exceeded, the loading call will fail with a “Too Many Open File Handles” error.

This was a common problem for projects trying to divide their content across many hundreds or thousands of AssetBundles.

For projects unable to upgrade to a patched version of Unity, temporary solutions are:

  • Reducing the number of AssetBundles in use by merging related AssetBundles
  • Using AssetBundle.Unload(false) to close an AssetBundle’s file handle, and managing the loaded Objects’ lifecycles manually

 

10 Unity Asset Bundle Browser tool

NOTE: This tool is extra functionality to Unity’s standard functionality. To access it, you have to download it from GitHub and install it separately from the standard Unity Editor’s download and install.

This tool enables the user to view and edit the configuration of asset bundles for their Unity project. It will block editing that would create invalid bundles, and inform you of any issues with existing bundles. It also provides basic build functionality.

Use this tool as an alternative to selecting assets and setting their asset bundle manually in the inspector. It can be dropped into any Unity project with a version of 5.6 or greater. It will create a new menu item in Window > AssetBundle Browser. The bundle configuration and build functionality are split into two tabs within the new window.

Requires Unity 5.6+

Usage - Configure

Note: this utility is in a pre-release state, and accordingly we recommend creating a backup of your project before using it.

This window provides an explorer like interface to managing and modifying asset bundles in your project. When first opened, the tool will parse all bundle data in the background, slowly marking warnings or errors it detects. It does what it can to stay in sync with the project, but cannot always be aware of activity outside the tool. To force a quick pass at error detection, or to update the tool with changes made externally, hit the Refresh button in the upper left.

The window is broken into three sections: Bundle List, Asset List, and Asset Details. 

Bundle List

Left hand pane showing a list of all bundles in the project. Available functionality:

  • Select a bundle or set of bundles to see a list of the assets that will be in the bundle in the Asset List pane.

  • Bundles with variants are a darker grey and can be expanded to show the list of variants.

  • Right-click or slow-double-click to rename bundle or bundle folder.

  • If a bundle has any error, warning, or info message, an icon will appear on the right side. Mouse over the icon for more information.

  • If a bundle has a scene in it (making it a scene bundle) and anything else explicitly included, it will be marked as having an error. This bundle will not build until fixed.

  • Bundles with duplicated assets will be marked with a warning (more information on duplication in Asset List section below)

  • Empty bundles will be marked with an info message. For a number of reasons, empty bundles are not very stable and can dissapear from this list at times.

  • Folders of bundles will be marked with the highest message from the contained bundles.

  • To fix the duplicated inclusion of assets in bundles, you can:

    • Right click on a single bundle to move all assets determined to be duplicates into a new bundle.

    • Right click on multiple bundles to either move the assets from all selected bundles that are duplicates into a new bundle, or only those that are shared within the selection.

    • You can also drag duplicate assets out of the Asset List pane into the Bundle List to explicitly include them in a bundle. More info on this in the Asset List feature set below.

  • Right click or hit DEL to delete bundles.

  • Drag bundles around to move them into and out of folders, or merge them (if none are scene bundles).

  • Drag assets from the Project Explorer onto bundels to add them.

  • Drag assets onto empty space to create a new bundle.

  • Right click to create new bundles or bundle folders.

  • Right click to “Convert to Variant”

    • This will add a variant (initially called “newvariant”) to the selected bundle.

    • All assets currently in selected bundle will be moved into the new variant

    • ComingSoon: Mismatch detection between variants.

Icons indicate if the bundle is a standard or a scene bundle.

Icon for standard bundle

Icon for standard bundle

Icon for scene bundle

Icon for scene bundle

Bundle Details

Lower left hand pane showing details of the bundles(s) selected in the Bundle List pane. This pane will show the following information if it is available:

  • Total bundle size. This is a sum of the on-disk size of all assets.

  • Bundles that the current bundle depends on

  • Any messages (error/warning/info) associated with the current bundle.

Asset List

Upper right hand pane providing a list of assets contained in whichever bundles are selected in the Bundle List. Available functionality:

  • View all assets anticipated to be included in bundle. Sort asset list by any column header.

  • View assets explicitly included in bundle. These are assets that have been assigned a bundle explicitly. The inspector will reflect the bundle inclusion, and in this view they will say the bundle name next to the asset name.

  • View assets implicitly included in bundle. These assets will say auto as the name of the bundle next to the asset name. If looking at these assets in the inspector they will say None as the assigned bundle.

    • These assets have been added to the selected bundle(s) due to a dependency on another included asset. Only assets that are not explicitly assigned to a bundle will be implicitly included in any bundles.

    • Note that this list of implicit includes can be incomplete. There are known issues with materials and textures not always showing up correctly.

    • As multiple assets can share dependencies, it is common for a given asset to be implicitly included in multiple bundles. If the tool detects this case, it will mark both the bundle and the asset in question with a warning icon.

    • To fix the duplicate-inclusion warnings, you can manually move assets into a new bundle or right click the bundle and selecting one of the “Move duplicate” options.

  • Drag assets from the Project Explorer into this view to add them to the selected bundle. This is only valid if only one bundle is selected, and it is not a scene bundle

  • Drag assets (explicit or implicit) from the Asset List into the Bundle List (to add them to different bundles, or a newly created bundle).

  • Right click or hit DEL to remove assets from bundles (does not remove assets from project).

  • Select or double-click assets to reveal them in the Project Explorer.

A note on including folders in bundles. It is possible to assign an asset folder (from the Project Explorer) to a bundle. When viewing this in the browser, the folder itself will be listed as explicit and the contents implicit. This reflects the priority system used to assign assets to bundles. For example, say your game had five prefabs in Assets/Prefabs, and you marked the folder “Prefabs” as being in one bundle, and one of the actual prefabs (“PrefabA”) as being in another. Once built, “PrefabA” would be in one bundle, and the other four prefabs would be in the other.

Asset Details

Lower right hand pane showing details of the asset(s) selected in the Asset List pane. This pane cannot be interacted with, but will show the following information if it is available:

  • Full path of asset

  • Reason for implicit inclusion in bundles if it is implicit.

  • Reason for warning if any.

  • Reason for error if any.

Troubleshooting

  • Can’t rename or delet a specific bundle. This is occasionally caused when first adding this tool to an existing project. Please force a reimport of your assets through the Unity menu system to refresh the data.

Usage - Build

The Build tab provides basic build functionality to get you started using asset bundles. In most profressional scenarios, users will end up needing a more advanced build setup. All are welcome to use the build code in this tool as a starting point for writing their own once this no longer meets their needs. Interface:

  • Build Target - Platform the bundles will be built for

  • Output Path - Path for saving built bundles. By default this is AssetBundles/. You can edit the path manually, or by selecting “Browse”. To return to the default naming convention, hit “Reset”.

  • Clear Folders - This will delete all data from the build path folder prior to building.

  • Copy to StreamingAssets - After the build is complete, this will copy the results to Assets/StreamingAssets. This can be useful for testing, but would not be used in production.

  • Advanced Settings

    • Compression - Choose between no compression, standard LZMA, or chunk-based LZ4 compression.

    • Exclude Type Information - Do not include type information within the asset bundle

    • Force Rebuild - Rebuild bundles needing to be built. This is different than “Clear Folders” as this option will not delete bundles that no longer exist.

    • Ignore Type Tree Changes - Ignore the type tree changes when doing the incremental build check.

    • Append Hash - Append the hash to the asset bundle name.

    • Strict Mode - Do not allow the build to succeed if any errors are reporting during it.

    • Dry Run Build - Do a dry run build.

  • Build - Executes build.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值