FC2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム » Unity »【Unity】【C#】Addressable Assets でキー(アドレス)の存在(登録)を調べる

【Unity】【C#】Addressable Assets でキー(アドレス)の存在(登録)を調べる  


 新しいリソースの管理のシステムである Addressable Assets をちょっといじってみた。しかしなぜか、素材のアドレス(キー)が存在しないときに出る InvalidKeyException が try~catch で捕捉できないので、登録の有無の検出ができなかった…(掲載時点:Addressables System 0.5.3-preview)。


InvalidKeyException encounterd in operation UnityEngine.ResourceManagement.CompletedOperation`1[UnityEngine.Texture], result='', status='None', valid=True, location=..
UnityEngine.AsyncOperation:InvokeCompletionEvent()

InvalidKeyException: Exception of type 'UnityEngine.AddressableAssets.InvalidKeyException' was thrown., Key=hogehoge
UnityEngine.AsyncOperation:InvokeCompletionEvent()

 まだ preview 版なので、単なるバグなのかも知れないが、少し不便と感じたのでググってみたら、フォーラムにも同じ内容があった。

Can I ask Addressables if a specified key (addressable name) is valid?

 まぁそのうち、ちゃんとエラー捕捉できるようになったり、「Addressables.HasKey()」みたいなのができそうな気がするが、今使うには簡単なものを用意しておくのも良いだろう。



(※) Unity 2018.3.2f1 / Addressables System 0.5.3-preview / Windows10(x64) で確認



■Addressable Assets にアドレス(キー)が存在するか否か?を返すメソッドを定義

 フォーラムにある「AddressableResourceExists」でも判別可能ではあったが、そのすぐ下に Unity の中の人からのアドバイスが書かれていたので、試しにやってみた。

What you have above probably could work. But the thing I would actually recommend is to just do Addressables.LoadAsset<IResourceLocation>("key");

This will not load your asset, but will load the location that points to your asset. If your key is valid, then you'll get a valid location back. Otherwise you will not. You can keep and use that location (doing LoadAsset<GameObject>(myNewLocation)) or you can just discard it and continue to load with key once needed.

 Google翻訳すれば『これはアセットをロードするのではなく、アセットを指す場所をロードします。キーが有効であれば、有効な場所に戻ります』となるが、要するに「存在位置が示されればアセットは存在する」ということだろう。

●Addressable Assets にアドレス(キー)が存在するか否か?
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;

public static class AddressablesUtil { //※クラス名は任意

// (参考) https://forum.unity.com/threads/can-i-ask-addressables-if-a-specified-key-addressable-name-is-valid.574033/
// http://fantom1x.blog130.fc2.com/blog-entry-319.html
/// <summary>
/// Addressable Assets にアドレス(キー)が存在するか否か?
/// </summary>
/// <param name="key">アドレス(キー)</param>
/// <returns>true = 存在する / false = 存在しない</returns>
public static bool Exists(string key)
{
return Addressables.LoadAsset<IResourceLocation>(key).Status == AsyncOperationStatus.Succeeded;
}
}

 やってみたら、どうやら存在しないキー(アドレス)を指定したときには「AsyncOperationStatus.Failed」になるみたいなので(まだ何もしてないときは None)、これだけで存在有無は確認できそうだ。Addressables.LoadAsset() の戻値:IAsyncOperation<IResourceLocation> は null は出ないみたいなので、チェックは省略した。

 使用例を簡単に書くと以下のようになる。

●Exists() の使用例(Addressable Assets からテクスチャを読み込んで RawImage に入れるサンプル)
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;

public class AddressablesTest : MonoBehaviour { //※クラス名は任意

public RawImage image;

void Start () {
string key = "hogehoge"; //アセットのアドレス(キー) ※任意

if (AddressablesUtil.Exists(key))
{
Addressables.LoadAsset<Texture>(key).Completed += op => {
image.texture = op.Result;
};
}
else
{
Debug.LogWarning("Invalid key = " + key);
}
}
}




■Task と連携して非同期で読み込むメソッドを定義

 ついでに前述した「Exists」と以下の拡張メソッドを組み合わせて、動作を Task 化し、アドレスの存在検出して、有れば素材を、無ければ default(この場合は基本的に null)が返ってくる関数を定義してみよう。これを使うとかなり楽に非同期ロードができるようになる。Task 化メソッドは以下の記事(IAsyncOperationExtensions.GetAwaiter<T>)をまるっとコピーして欲しい。
 
【Unity】Addressable Asset Systemのリソース読み込みをasync/await対応する

●アドレス(キー)が存在するならロードし、無ければ default (= null) を返す
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;
using System.Threading.Tasks; //※Task ならこっち
//using UniRx.Async; //※UniTask ならこっち

public static class AddressablesUtil { //※クラス名は任意

// (参考) https://qiita.com/toRisouP/items/e03b53e8eb6af06fbcbf (※IAsyncOperationExtensions.GetAwaiter<T> を利用)
// http://fantom1x.blog130.fc2.com/blog-entry-319.html
/// <summary>
/// アドレス(キー)が存在するならロードし、無ければ default (= null) を返す
/// </summary>
/// <typeparam name="T">素材の型</typeparam>
/// <param name="key">アドレス(キー)</param>
/// <returns>取得した素材</returns>
public static async Task<T> LoadOrDefault<T>(string key) where T : class
{
if (Exists(key)) //※前述のメソッド
return await Addressables.LoadAsset<T>(key); //※IAsyncOperationExtensions.GetAwaiter<T> が必要
return default;
}
}

 もちろん、Task を UniTask(UniRx が必要)に置き換えることも可能だ。

 簡単な使い方としては以下のようにしても良いだろう(※かなり適当なので、好きに書き換えて(笑))。

●LoadOrDefault()の使用例(Addressable Assets からテクスチャを読み込んで RawImage に入れるサンプル)
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;
using System.Threading.Tasks; //※Task ならこっち
//using UniRx.Async; //※UniTask ならこっち

public class AddressablesTest : MonoBehaviour {

public RawImage image;

void Start () {
string key = "hogehoge"; //アセットのアドレス(キー) ※任意
LoadImage(key); //※Task なら警告が出る
//LoadImage(key).Forget(); //※UniTask なら警告を消せる
}

async Task LoadImage(string key)
{
var tex = await AddressablesUtil.LoadOrDefault<Texture>(key);
if (tex != null)
{
image.texture = tex;
}
else
{
Debug.LogWarning("Invalid key = " + key);
}
}

}

 もちろんこれも UniTask(UniRx が必要)に置き換えても良い。

 待機したいなら、async/await を付ければ良い(※この例ではあまり意味がないが(笑))。
async void Start () {
string key = "hogehoge"; //アセットのアドレス(キー) ※任意
await LoadImage(key);
}



 まだ、Addressable Assets はプレビュー版だからか、使い勝手が微妙な所もあるが、いずれは Resources の代わりに使われるようになるだろう。Addressable Assets ははじめから非同期ロードだったり、プリロード機能もあったりして便利なので、今から慣れておくのも良いかも知れない。





(関連記事)
【Unity】【C#】AssetBundleManager を WebGL で使う・エラー対処法
【Unity】【C#】アセットバンドルのキャッシュを調べて不要なものを消す


関連記事
スポンサーサイト



category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityトラブルシューティング  C# 
tb: 0   cm: --


トラックバック

トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/319-a80b67ba
この記事にトラックバックする(FC2ブログユーザー)

プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR