Sharp Coder is reader-supported, meaning when you buy through links on our site, we may earn an affiliate commission.
HomeBlogUnity

Asset Bundle Usage in Unity 3D

2561

Unity has many useful features, one of them is support for Asset Bundles.

What Are Asset Bundles?

Asset Bundles are files that contain game assets (from simple assets such as 3D Models, Textures, Audio Clips to more complex such as Scenes).

Scripts however cannot be included in Asset Bundles, only their references, so be careful when renaming or moving them, as it will break the connection and you'll need to rebuild the Asset Bundles to make them work again.

Why Use Asset Bundles?

When building the game in Unity, all assets are included in the build, and when the game size is relatively small (under 50MB) it does not pose any issues (players can download it rather fast), but imagine the game size is in triple digits (ex. 300MB) or higher. Users would still be able to download it relatively fast with modern internet, but having to re-download the whole game whenever a new update is released will add up quickly.

That's where Asset Bundles come in handy, instead of including all the assets in the build, they are packed into separate files, that way players only need to download them once, then they get stored in the cache.

Exporting Asset Bundles

Exporting is done in two steps: assigning Asset Bundle names, then building them using Editor script.

Assigning Asset Bundle names:

Assigning Asset Bundle name is done by selecting the asset in the Project view (this could be Prefab, Texture, or even a Scene), then in the Inspector view at the very bottom click on dropdown menu then click 'New...' (or click on the existing Asset Bundle name to attribute this asset to it).

Assigning the same bundle name to multiple assets will pack them together in the same Asset Bundle. It's advised to pack Scenes separately from the rest of the assets.

Also, you don't have to assign an Asset Bundle name to every asset. Typically you only need to assign the bundle name to the main prefab or asset, the rest of the dependencies will be included automatically.

Building Asset Bundles:

  • Create a new folder called Editor (if you do not have any)
  • Create a new script inside the Editor folder, name it BuildAssetBundles then paste the code below inside it:

BuildAssetBundles.cs

using UnityEngine;
using UnityEditor;

public class BuildAssetBundles
{
    [MenuItem("Build/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        string outputFolder = "Assets/__Bundles";

        //Check if __Bundles folder exist
        if (!AssetDatabase.IsValidFolder(outputFolder))
        {
            Debug.Log("Folder '__Bundles' does not exist, creating new folder");

            AssetDatabase.CreateFolder("Assets", "__Bundles");
        }

        BuildPipeline.BuildAssetBundles(outputFolder, BuildAssetBundleOptions.ChunkBasedCompression, EditorUserBuildSettings.activeBuildTarget);
    }
}

After saving it you'll notice it will add a menu button (Build -> Build AssetBundles). Clicking it will build the Asset Bundles and place them in "__Bundles" folder.

Importing Asset Bundles

To import the Asset Bundle we first need to download it using UnityWebRequest then load it using a special function. Generally, there are 2 types of Asset Bundles, those that contain assets and those that contain Scenes.

Loading Assets From The Asset Bundles:

The code below downloads Asset Bundle named "fpsplayer" then extracts the Prefab named "FPSPlayer" and instantiates it in Scene:

        int assetBundleVersion = 1; // Changing this number will force Asset Bundle reload
        string assetBundlePath = "file://" + Application.dataPath + "/__Bundles/" + "fpsplayer"; // Path to Asset Bundle file
        using (UnityEngine.Networking.UnityWebRequest www = UnityEngine.Networking.UnityWebRequestAssetBundle.GetAssetBundle(assetBundlePath, (uint)assetBundleVersion, 0))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.LogError("AssetBundle Error: " + www.error);
                yield return null;
            }
            else
            {
                // Get downloaded Asset Bundle
                AssetBundle assetBundle = UnityEngine.Networking.DownloadHandlerAssetBundle.GetContent(www);
                // Extract Prefab named "FPSPlayer" from the Asset Bundle
                GameObject playerPrefab = assetBundle.LoadAsset("FPSPlayer") as GameObject;
                // Instantiate Player Prefab
                Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
                // Unload Asset Bundle from memory (but do not destroy the existing instance(s))
                assetBundle.Unload(false);
            }
        }

Loading Scenes From The Asset Bundles:

Loading Scene from the Asset Bundle is done slightly differently.

The code below will download the Asset Bundle with a Scene and will make it available for load:

        int assetBundleVersion = 1; // Changing this number will force Asset Bundle reload
        string assetBundlePath = "file://" + Application.dataPath + "/__Bundles/" + "testscene"; // Path to Asset Bundle file
        using (UnityEngine.Networking.UnityWebRequest www = UnityEngine.Networking.UnityWebRequestAssetBundle.GetAssetBundle(assetBundlePath, (uint)assetBundleVersion, 0))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError || www.isHttpError)
            {
                Debug.LogError("AssetBundle Error: " + www.error);
                yield return null;
            }
            else
            {
                // Get downloaded Asset Bundle (This will make the Scene available for load)
                AssetBundle assetBundle = UnityEngine.Networking.DownloadHandlerAssetBundle.GetContent(www);
                // Load the Scene extracted from the Asset Bundle
                UnityEngine.SceneManagement.SceneManager.LoadScene("TestScene");
            }
        }