The Addressable Asset System (Addressables) is a content management system that is built on AssetBundles.
As Unity suggests:
With Addressables, content is cataloged, packaged into AssetBundles, and stored either with the player or remotely on a server. Content stored remotely can then be delivered to users’ projects using either a content delivery network (CDN) or a web server. Content Updates can then be performed automatically, removing the need for users to download updates from their app store or game service.
So I wondered, how does Addressables differentiate from using AssetBundles? Well, Addressables are actually built on AssetBundles and it is just an updated version of AssetBundles, which is more efficient and easier to use.
AssetBundles are used for separating some content from the application install data, and enabling the user(s) to download the relative data on the runtime: decreases the efforts of the user and the developer by removing the mandatory asset store usage for content downloading/updating; by enabling the user download data within the application from a remote server.
“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.” — Unity
Without a doubt, the implementation of the AssetBundles is not an easy task, and that is the precise reason that Unity has introduced Addressable Asset System. By tagging an asset as Addressable, we can easily reference, load and unload any asset (or asset group) during runtime dynamically. Briefly, Addressables makes the content management easier, faster and more efficient.
Why Do We Need Addressables?
If you are struggling with a small project, it is likely that memory usage may not be a crucial issue for you. However, it is not the case as your projects get larger and complicated. I was actually pretty surprised once I have learnt that the Prefabs assigned from the inspector are loaded in the memory even if they have not been instantiated in the scene just yet, given the fact that the prefabs are actually a dependency of the object that is referenced by. Thus, even a few large prefabs may result in remarkable unnecessary memory usage. With Addressables, we can mark an asset or asset group as addressable. By referencing the address of the asset(s), we can load and instantiate them once they are needed, and unload them once they are no longer needed. As Unity suggests: “By packing asset bundles more efficiently and reducing iteration time, Addressables provides a simple way to make your game more dynamic.”
Introduction To Addressables
By installing the “Addressables” package from the Package Manager, you will notice that everything that our assets are now containing a clickable “Addressable” attribute. We can either select folder(s) or individual item(s) to tag as Addressable. Once we check the Addressable attribute box, it will create an unique address for the relevant asset; making a part of the Addressable Group. All of the dependencies of the asset will also have a generated Addressable address once it is tagged as Addressable.
Once we tag an asset as “Addressable” it becomes a part of the Addressable Groups and automatically moved to Default Local Group. By default, Unity will assign the path of the asset as the Addressable name. However, we are free to assign a custom Addressable name (to be honest, I have no idea regarding a proper naming convention for this):
Addressable assets can be loaded by their addresses or by their labels. It is possible to assign multiple labels to an asset. You will also notice that, a new folder is created within the Project window once we tag an asset as Addressable; which includes the AddressableAsset Settings and Asset Group Settings for each Bundle:
In order to view the Addressable Groups, we can simply click the “Select” button on the right side of an Addressable asset or by clicking Window — Asset Management — Addressables — Addressables Groups.
If you somehow have some assets that you want to mark as Addressable in your Resources folder, Unity automatically generates a new folder called “Resources_moved” if we mark an asset within the Resources folder as Addressable.
We can customize the assets into different groups, with different group settings.
Grouping the assets in a proper way will prevent the usage of duplicated assets. Rather than having a large bundle of assets that are grouped together in one Asset Bundle, we can create smaller AssetBundles. Certainly, this is not enough for making sure that we have no duplicate assets in the memory, but it is a good way to eliminate the problem of having not used assets running in the memory just because they are within the same AssetBundle.
Now that we have some familiarity with Addressables, it is time for scripting. As download time depends on internet speed, loading an asset bundle during runtime is an asynchronous operation. Thus, we need access to both Addressables and AsyncOperations libraries:
First, we need to reference the asset type. Just as we can use the generic AssetReference class, we can restrict the AssetReference:
The asset reference will be declared as that we can drag and drop the desired asset in the inspector. Unlike normal prefabs, these assets will not be holding unnecessary memory until we want them to (in this case, until we tell the game to load them). As the loading of the addressables is async and the implementation time is always unknown, we also need an operation handle for the asynchronous loading callback function.
public AssetReferenceSprite newSprite;
private AsyncOperationHandle<Sprite> _spriteOperation
In the example below, I will be changing a moving soldier sprite to a hitman sprite once I click on space button (thanks Kenney.nl for free sprites). I have created an empty game object as “Loader” and attached a new script “AddressableSpriteLoader”.
Once Space is pressed, we simply tell the handle of AssetReferenceSprite to implement LoadAssetAsync method (well, just telling Unity to load the specified asset and Unity will load it along with its dependencies). By declaring a new method of “SpriteLoaded” we register to the AsyncOperation.Completed event. Once the operation is completed, the SpriteLoaded method will be called. The operation loading will either succeed or fail:
If the operation succeeds, it calls the soldier method of Change Sprite, which just accesses the sprite renderer to change the sprite.
In order to test your code, make sure that Play Mode Script in the Addressables Groups setting is set to “Use Asset Database”, which allows us to load and test the Addressables on the play mode.
Despite you will realize that the sprite changes successfully, we are not done just yet. Even if we change the sprite of the object one more time, the previous sprite will still be held in the memory, until we release it. Here, you shall not forget that we each LoadAsset command will load instances to the memory. Likewise, release command will decrement one asset from the memory.
Since the sprite on my example will be active until the object is destroyed, I will be releasing it in the OnDestroy method. And that is how easy it is to load a sprite using the Addressables in Unity.
Loading Addressables Using Their Addresses
As mentioned earlier, we can also load the assets by using their customizable addresses. The only difference we need to make is to add a string variable for the address and call it on the hit of the Space. So, the Update method on the previous example is updated as:
_spriteOperation = Addressables.LoadAssetAsync<Sprite>(spriteAddress);
_spriteOperation.Completed += SpriteLoaded;
Then, the only thing left is to fill the related field in the inspector.
Instantiating Game Objects Using Addressables
As suggested by Unity, there 2 common ways to instantiate a game object using the Addressables: Direct instantiation and Load&Instantiate method, just like the previous sprite loading example.
Direct instantiation using Addressables.InstantiateAsync(“key”):
Addressables.InstantiateAsync(“Prefabs/OldMan”, Vector3.zero, Quaternion.identity);
The line above instantiates the Addressable asset with the address “Prefabs/OldMan” on the zero point. Despite it seems like a direct instantiation, Unity handles the asset and the dependency loading on the background, before instantiating the object.
Loading & Then Instantiating
This instantiation way is similar to the sprite.
private AsyncOperationHandle<GameObject> _objOperation;private GameObject _objToSpawn;
Update Method on Press Space:
_objOperation = Addressables.LoadAssetAsync<GameObject>(“Prefabs/OldMan”);
objOperation.Completed += SpawnObj;
Lastly, do not forget to release the memory on destroy:
For more details, you can always check the Unity Manual on Addressables following this link.