【Unity】Addressables asset systemって結局どう使うんだ
概要
UnityにおけるAddressables asset system を活用した実践的なアセット管理フローの考察。
Unity ver:2021.3.3
Addressables ver:1.19.19
前置き
どうもUnityでスクリプトからアセット管理をするにはAddressablesというものがいいらしいというのは、ググれば一瞬で出てきます。(Resourcesは簡単ですが非推奨らしいですね)
ところが探せど探せど出てくる例文は、一つのアセットを読み込んで、リリース。読み込んで、リリース。私のサーチスキルではそれが限界でした。これだけでゲームは作れまいて。
ということで、コピペ芸はそろそろ卒業して自分でスクリプトを書く努力をと思い至った次第です。
私が思い描いていた理想は以下のようなものです。
- シーンの初めに必要なアセットを複数読み込む。
- ゲームのループ中それを保持し続け、必要に応じて呼び出し、操作する。
- ループの終了時に読み込んだアセットを全てアンロードする。
これらを実装するために、構造体を作り、アセットをリストで管理する方法を考えました。ご意見はじゃんじゃんお待ちしています。
リストの構造
使いたいアセットは全てprefubにしておきます。
まず、prefubを管理するclassを作ります。
今回は二つの構造体を作りました。
~~~ 使用例 ~~~ ~~~~~~~~~~~
public class PrefubManage
{
struct ItemInfo{
GameObject Object;
PrehubInfo Info;
AsyncOperationHandle
}
public struct PrefubInfo{
public string Key;//インスタンス化したオブジェクトを呼び出すためのキー
public string AssetAddress;//addressablesのaddress
public float X;
public float Y;
}
}
|
また、プレハブを格納するリストは以下です。
List<ItemInfo> PrefubList = new List<ItemInfo>();
PrefubInfo構造体型の情報リストを、メソッドに渡すことで、class内のPrefubListにインスタンス化したオブジェクトを格納していくようにします。
リストに入れる
まず、渡した複数のプレハブ情報に基づいて、全てのプレハブがロードされインスタンス化されるまで待機したいです。
つまり同期的な実装がしたいということです。
よって、asyncを付けたメソッドの中で、インスタンス化を行うTask型メソッドを繰り返し呼びたいと思います。
forが終了した後、actionなどのデリゲートなりでイベントを発火させると、全てのプレハブのロードが終わった後に処理を続けることが出来ます。
保持の時のミソは、インスタンス化したオブジェクトと、ロードを実行した際にaddressablesが返してくるAsyncOperationHandle
こうすることで、後にオブジェクトにアクセスして操作したり、削除することが可能になります。
public async void createPrefubs(List<PrefubInfo> list, Action action) { for (var i = 0; i < list.Count; i++) { //プレハブを一つ一つ順番にロード、インスタンス化し、その間待機する await addPrf(list[i]); } //デリゲート action(); } async Task addPrf(PrefubInfo info) { //同期的にロード。まだインスタンス化はされていない AsyncOperationHandle<GameObject> o = Addressables.LoadAssetAsync<GameObject>(info.AssetAddress); //待機 await o.Task; if (o.Result != null)//ロードが出来ていれば、オブジェクトはResultに入っている { // ロードしたものをインスタンス化 var obj = UnityEngine.Object.Instantiate(o.Result); ItemInfo ii = new ItemInfo(); ii.Info = info; ii.Object = obj; ii.handle = o; //リストに追加 PrefubList.Add(ii); } } ~~~ 呼び出し例 ~~~ prefubManage = new prefubManage(); List<prehubInfo> list = new List<prehubInfo>(); list.Add(new PrefubInfo("key", "address", 0,0); prefubManage.createPrefubs(list, action); void action(){ Debug.Log("OK"); } ~~~~~~~~~~~~~~~~
リストから取り出す
次にインスタンス化したオブジェクトを操作します。
今回は、PrefubInfoに入れておいたX、Yの項目を使って、オブジェクトの位置を変更してみたいと思います。
初めに、設定したKeyを使ってリストの中からオブジェクトを探し出し、次にそのオブジェクトからgetconponentでtransformやrecttransformを呼び出すといった流れです。
他にも、サイズを変更したり、Buttonにイベントをアタッチしたりなど、様々なことに応用できます。
public GameObject getObj(string key) { for (var i = 0; i < PrefubList.Count; i++) { if (PrefubList[i].Info.Key == key) { return PrefubList[i].Object; } } return null; } public void setPosition(string key, UnityEngine.Vector3 pos) { getObj(key).transform.GetComponent<RectTransform>().localPosition = pos; } ~~~ 呼び出し例 ~~~ setPosition(info.Key, new Vector3(info.X, info.Y, 0f)); ~~~~~~~~~~~~~~~~
リストから消す
addressablesでロードしたアセットは、単にオブジェクトをデストロイするだけではなく、リリースが必要です。
リリースを怠ると、次にロードするのが同じアセットだとしてもどんどんメモリに積み重なっていきます。
その後、リストからも削除します。
そのために、ハンドルを取得するメソッドと、リストのインデックスを取得するメソッドを作成します。
インスタンス化から削除までの間、
window -> asset management -> Addressables -> event viewer
でメモリの使用状況などチェックしてみるといいと思います。
なお、event viewerでaddressablesのオブジェクトをチェックするためには、
window -> asset management -> Addressables -> setting
などでAddressableAssetSettings.assetに飛び、
Diagnostics -> Send Profiler Events
を有効化する必要があります。
public void removePrefub(string key) { GameObject.Destroy(getObj(key)); Addressables.Release(getHandle(key)); PrefubList.RemoveAt(getIndex(key)); } int getIndex(string key) { for (var i = 0; i < PrefubList.Count; i++) { if (PrefubList[i].Info.Key == key) { return i; } } return -1; } AsyncOperationHandle<GameObject> getHandle(string key) { for (var i = 0; i < PrefubList.Count; i++) { if (PrefubList[i].Info.Key == key) { return PrefubList[i].handle; } } return new AsyncOperationHandle<GameObject>(); }
後書き
ひとまず直感的に組んでみたスクリプトです。
何か穴がありそうな気もしますが、今のところはいい感じに動いてます。
おすすめの本です↓
- 価格: 5060 円
- 楽天で詳細を見る
無料相談アリ!プロから学びたい方はこちら↓
TechAcademy [テックアカデミー]