Unity – Asset Bundles

For many stand-alone games, all the resources of the game are often released together with the game body, and the resources do not need to be independent. But for large-scale commercial projects, game products still need to be maintained and updated after release, which leads to the concept of Unity asset package

1. Asset Bundles

In fact, generally speaking, as long as the resources are placed in the appropriate folder, Unity will handle them properly. However, for large-scale commercial projects, resource packaging and management are issues that have to be considered. The main reasons are as follows:

  1. Resource files must be unbound from the program body. Resources can be easily modified individually while the main body of the program remains unchanged.
  2. Resource files must be individually compressed and encrypted
  3. After the resource file exists independently, it can not be released together with the main body of the program, but can be downloaded online when the user uses it. This will help reduce installation file statistics and facilitate subsequent version updates.

Asset Bundles exist to better solve resource management problems. The following uses a simple example to illustrate its use.

1. Create asset package

  1. Create a new project
  2. Create a ball and a block, create a material, and assign the material to the ball and block
  3. Import any picture, create two sprite objects Sprite, specify the same picture, and name them icon1 and icon2 respectively.
  4. Drag 4 objects into the Project window respectively as 4 prefabricated objects. After doing this, you will have 4 prefabs, 1 material and a picture
  5. Delete 4 objects in the scene and restore them later using the asset pack
  6. Create a folder under the Assets folder and name it Editor. Note that the capitalization and pinyin should be exactly the same, so that the folder can be recognized as an editor-specific folder. In this folder create the script BuildAssetBundle.

Script BuildAssetBundle:

using UnityEditor;
using System.IO;

public class BuildAssetBundle
{
    //Add options to the main menu
    [MenuItem("Asset Bundles/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        //The name of the folder to be created
        string dir = "AssetBundles";
        //If the folder does not exist, create it
        if (Directory.Exists(dir) == false)
        {
            Directory.CreateDirectory(dir);
        }
       // This asset package is used to publish resources for the Windows platform
            BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
    }
}

This script is different from the general script component, it is an editor script. First, it should appear in the editor-specific folder (that is, in Editor), and second, it references UnityEdittor. The MenyItem attribute in the brackets at the beginning of the code will modify the main menu of the Unity editor.

After saving, switch to Unity. After correct compilation, there will be an Asset Bundles option in the main menu, as shown in the figure

a519da1e4fc34bcd8f688960e1879a0e.png

Then click Build AssetBundles, and a new AssetBundles folder will be created outside the Assets folder. c41f78a780dc45e7a7751a591c0af9e9.png

But it has not yet been set which resources are included in which packages, so there is no actual effect yet. Next set up the asset package to which each asset belongs.

Select Cube and you will see a preview window in the lower right corner of the editor. There are two menus below the preview window. These two menus are related to the Douyu asset package. Click the button on the left and select New to name the asset package, such as ab. Then confirm that the asset package to which prefab belongs has been set as the ab asset package.

a06c34cab61c4ab2936e085b3c81b0ed.png

Similarly, select the other 3 prefabs and set the asset packages they belong to to ab. But there is no need to set up the asset package of pictures and materials, and it will not affect whether it is set or not.

With the tool script and the asset package set up, the preparations are complete. Then click AssetBundles->BuildAssetBundles in the main menu, and the editor will automatically package it.

After packaging, find the AssetBundles folder in the project folder of the resource manager (outside the Assets folder). You can see that there are two files without extensions, of which ab is the specified asset package, and ab.mainfest is the asset. related information. Note that similar to META files, both need to be used together.

9b59d0ff4a4745eaa652e99c5bcc1f4d.png

Unity places the root directory of the asset package outside the Assets file by default. This means that the asset package can exist independently and no longer needs to be managed by the engine like ordinary resources. It can be placed anywhere on the hard disk.

2. Load and use asset packages

In the past, there were only two options for using prefabs, either using public variables to directly reference the prefabs, or using Resources.Load to dynamically load the prefabs, but now there is a third, more flexible method – loading resources from the asset package.

Create a new script TestLoadAB with the following content:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestLoadAB : MonoBehaviour
{
  
    void Start()
    {
        //Load into AssetBundles from file
        AssetBundle ab = AssetBundle.LoadFromFile(E:/unitytest/Asset Bundles/AssetBundles/ab);//Note, if this is your own file path
        //Load 4 prefabricated resources respectively
        GameObject prefab1 = ab.LoadAsset<GameObject>("Cube");
        GameObject prefab2 = ab.LoadAsset<GameObject>("Sphere");
        GameObject prefab3 = ab.LoadAsset<GameObject>("icon1");
        GameObject prefab4 = ab.LoadAsset<GameObject>("icon2");
        //The above 4 sentences can be replaced by the following sentence
        //GameObject[] prefabs = ab.LoadAllAssets<GameObject>();

        Instantiate(prefab1, new Vector3(0, 0, 0), Quaternion.identity);
        Instantiate(prefab2, new Vector3(1, 0, 0), Quaternion.identity);
        Instantiate(prefab3, new Vector3(2, 0, 0), Quaternion.identity);
        Instantiate(prefab4, new Vector3(3, 0, 0), Quaternion.identity);

    }

   
}

The above code is loaded from the file into the asset package ab. Note that the path must be exactly the same as the actual location.

After loading into the resource package, the resources need to be obtained from the package. You can use the LoadAsset method to obtain them individually, or you can use the LoadAllAssets method to obtain a batch of resources.

2. Common paths of resources

In the above code, the path is written as an absolute path. Butabsolute paths cannot be used in actual game development,because the folder structure of each computer and each mobile phone may be different, so the path must be specified indirectly. Moreover, since the file structures of operating systems such as Windows, Mac, Android, and IOS are different, you should use the method provided by Unity to indirectly specify the folder. There are three main types of commonly used system paths.

  1. Application.dataPath, data path. It refers to the path where the program’s data is located. For example, during the development phase, Assets is the data folder. This path is less useful on mobile platforms.
  2. Application.streamingDataPath, original data path. It corresponds to the special folder StreamingAssets, which is used to store data files that do not require compression. However, on the mobile terminal, the StreamingAssets folder is also a read-only folder and data cannot be written.
  3. Application.persistentDataPath, persistent data path. This is a readable and writable path. All game files and downloaded asset packages should be placed in this path.

If the game needs to be published to the mobile terminal and data needs to be saved, then the role of common paths must be understood. However, for commercial projects, you will encounter more complex problems. For example, the writable folder of the Android system is divided into two parts: the main storage area and the SD card area. The persistent data folder of the Apple system will be automatically backed up by iCloud. .

3. Asset dependencies

In the above example, regardless of whether the asset package to which the image and material files belong is set, it will not affect the packaging and loading effects. To confirm this, you can delete the original resource files in the Assets folder and confirm that all resources are dynamically obtained from the asset package.

On the surface, all resources that need to be included in asset packages should be set up with asset packages, but in fact, many resources without asset packages will also be included in asset packages. This is becauseUnity can identify which resources the asset package depends on< /strong>. For example, the cube and sphere require material resources, and the two sprite prefabs require images, so images and materials will be put into the asset package together.

If all assets enter the same asset package, then there will be at most one copy of each asset. But in fact, a game cannot have only one asset package. It is likely to have many asset packages. At this time, when considering dependencies, a thorny problem will arise.

For example, in the above example, 4 prefabs are entered into 4 asset packages: cube, sphere, sprite 1 and sprite 2. Both the cube and the sphere rely on material files, and both Elf 1 and Elf 2 rely on image files, but the materials and images are not packaged. What will Unity do at this time?

The answer is that in order to ensure that the asset package can be used independently, all dependencies must be added to each asset package. In other words, both the cube and sphere asset packages need to contain a material, and both image asset packages need to contain that image respectively. This solution solves the problem of independent use of asset packages, but also creates new problems of resource duplication. In some large-scale projects, the dependencies between assets are complicated, and incorrect settings may cause resources to be packaged multiple times and the resource volume to double.

Solving this problem requires a more reasonable packaging strategy. The key to solving the problem is to put common resources into separate resource packages. For example, in the example above, if both the cube and sphere prefabs need to be packaged in a separate package, then the material should also be packaged in a separate package. After doing this, Unity will find that the dependencies have been packaged separately, and the materials will not be packaged into the cube and sphere asset packages respectively, which will not cause the problem of repeated packaging of resources.

Note: When using it, be sure to load the material asset package before instantiating the sphere. If the sphere is instantiated directly without loading a material, the sphere will lose its material (displayed in purple).

In short, in order to better manage assets, you have to use asset packages. Once assets are managed individually, many problems will arise. Regarding asset management issues, many experienced development teams have accumulated complete solutions for reference. In addition, Unity officials are also actively improving asset package management methods.

4. Load resources from the network

In the above example of loading an asset bundle, the AssetBundle.LoadFromFile() method is used, which is a commonly used method to load asset bundles from local files. If the loaded file is large, this method will cause the main thread to freeze, so Unity provides another loading method using coroutines, AssetBundle.LoadFromFileAsync(), the usage is as follows

 IEnumerator LoadFileAsync()
    {
        AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path);
        yield return request;
        AssetBundle ab = request.assetBundle;
        Instantiate(ab.LoadAsset<GameObject>("CubeWall"));
    }

When using asynchronous functions, a coroutine function should be specially written, such as LoadFromFileAsync(). You only need to enable the StartCoroutine() method of the coroutine to start it. The coroutine function will not run after the first yield return before the loading is completed, but it will not affect the running of the program at the same time.

Since the asset package can be loaded from the disk, it is natural to also use the network to load the asset package. It is recommended to use UnityWebRequest.GetAssetBundle to obtain network resources. It is also an asynchronous function. The usage method is as follows

 IEnumerator UseUnityWebRequest(string path)
    {
        //Use UnityWebRequest.GetAssetBundle (path) to load resources. This path is the resource address URL and also supports local files.
        UnityWebRequest request = UnityWebRequest.GetAssetBundle(path);
        yield return request.SenWebRequest();

        //Run here to indicate that the loading is complete and the asset package is obtained from the request object.
        AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);

        //The subsequent usage is no different from local loading.
        GameObject obj = ab.LoadAsset<GameObject>("Wall");
        Instantiate(obj);
    }

It can be seen that although the method and path format of obtaining the asset package are different, the method of using the asset package is the same. The path of network resources should be represented by URL.

syntaxbug.com © 2021 All Rights Reserved.