TL;DR it was an awesome experience - diving into the package and understanding how to integrate it with our game’s current architecture was quite insightful!
Motivation
I recently learned about the Addressable Assets
package (still in preview), which combines the best of both Resources
and Asset Bundles
, allowing one to locate assets irrespective of them being local or remote. Curious, I put my hand into the honeypot and began investigating.
Technique
I decided to replace the direct Weapon references using AssetReference
s (the package adds on to the editor, allowing one to simply tick off the items one would want to use as Addressable Assets). The main difference from the technique in the lectures is that the assets must always be loaded asynchronously. So, I had to wrap the Equip
call within a callback, which completed when the asset finished loading.
public void LoadEquipAsync(in AssetReference weaponAsset)
{
currentWeaponAsset = weaponAsset;
currentWeaponAsset.LoadAssetAsync<Weapon>().Completed +=
(weaponHandle) => Equip(weaponHandle.Result);
}
The WeaponPickup
s would have to store AssetReference
s instead of direct references to Weapon
s. I also decided that pickups for the same weapon should be noticed as well.
public class WeaponPickup : MonoBehaviour
{
[SerializeField] AssetReference weaponAsset = null;
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
var fighter = other.GetComponent<Fighter>();
if (!fighter.IsSameWeaponAsset(weaponAsset))
{
fighter.LoadEquipAsync(weaponAsset);
Destroy(gameObject);
}
}
}
}
Now, if you’re paying attention, you might have several questions in your mind:
- How am I going to serialize the
AssetReference
s? Last I checked these aren’t serializable (though the docs say they are - again - if you’ve been paying attention)! - How on Earth do you know whether two assets are the same or not?
The answer came to me in a few precious hours after I found these two mysterious things in the AssetReference
s docs.
Bingo! All we need to do is serialize this GUID and reconstruct the AssetReference
with it! Since it’s unique for every object, it’s easy to compare AssetReferences
with!
After a miniature war with the machine, I figured out that the GUID was always wrapped [like this... yikes]
. Thus, this code came into fruition:
public static class AssetReferenceExtensions
{
public static string GetGuid(this AssetReference assetReference)
{
return assetReference != null ?
assetReference.ToString().Trim(new char[] { '[', ']' }) : "";
}
}
This code allowed me to write this.
public bool IsSameWeaponAsset(in AssetReference weaponAsset) =>
currentWeaponAsset.GetGuid().Equals(weaponAsset.GetGuid());
With a bit of C# nuance and my own idiosyncrasies, the State would now end up looking like this.
object ISaveable.State
{
get => (currentWeaponAsset ?? defaultWeaponAsset).GetGuid();
set => LoadEquipAsync(new AssetReference((string)value));
}
I maintain two AssetReference
s for easier management, but it can most definitely be one - with a bit of ingenuity - which I lack at the moment.
Summary
Suffice to say, the results are plausibly the same for both methods, but Addressable Assets
aims to do much more. A quick online search reveals blog posts, documentation, best practices - you name it!
Here’s my complete code, if you have come this far, and want to look at how I attempt to use the latest C# for doing mumbo-jumbo.
Thanks for reading!