AddressableでのAssetReferenceで、任意のアセットを指定する方法についてです。
参照するアセットを絞り込んでおきたい
Addressableでアセットの遅延ロードを行いたい時、AssetReferenceでアセットを指定するというアイディアがあります。ただし、この時に登録しているアセットの数が膨大だと非常に面倒な事になります。
特にキャラクター名等、非常によく使うアドレスはテクスチャやオーディオ、その他諸々で複数登録されている事もありえるので、これを一覧から正しく選択しろというのはヒューマンエラーの元です。
これに対応する理にかなったAPIとして [AssetReferenceTypeRestriction( type )]
というAttributeがありましたが、何故かコレをver 0.6.6
で廃止してくださいやがりましたので、他のアプローチを紹介します。
AssetReferenceTを使用する
解決法としては、AssetReferenceT<T>
を継承したクラスを定義します。ジェネリックを使用したクラスはシリアライズ出来ないので、一々AssetReferenceT<T>
を継承したクラスを定義する必要があります。
例えば下のような、ゲーム内でHPパラメーターを共有するScriptableObject:GameData
クラスがあったとして…
[CreateAssetMenu] public class GameData : ScriptableObject { [SerializeField] private int originalHP; public int HP { get; set; } private void OnEnable() => HP = originalHP; // 起動時にHPを初期化 public bool IsDead() => HP < 0; // HPが0以下だったら死亡判定 public void Damage(int value) => HP -= value; // ダメージを受けたらHPを減らす }
GameData
のみを使用可能なAssetReferenceT
を用意します。
[System.Serializable] // Serializable属性が必ず必要 public class AssetReferenceGameData : AssetReferenceT<GameData> { }
あとは AssetReference
の代わりにAssetReferenceGameData
をAddressableの呼び出し元コードに設定します。
public class PlayerSpawn : MonoBehaviour { // AssetReferenceではなくAssetReferenceGameData [SerializeField] AssetReferenceGameData gameData; private void Awake() { enabled = false; gameData.LoadAsset().Completed += (data) => enabled = true; } private void OnDestroy() { gameData.ReleaseAsset(); } private void Update() { // 取得済みのアセットを使用するが、こちらはキャストが必要 ((GameData)gameData.Asset).Damage(1); } }
補足
ちなみにAssetReferenceTで指定出来る型は、UnityEngine.Objectのみみたいです。正確にはUnityEngine.Objectのアセットのみっぽく、Componentは指定出来ませんでした。ここにInterfaceが指定出来れば、色々な面で非常に楽になるんですが… ふっきゅんきゅんきゅん!
ついでにAssetReferenceLabelRestriction
属性も廃止になり、ラベルを取得するAssetReferenceUILabelRestriction
クラスになりました。こちらは悪くないです。