簡単リモートアセット(Unity Addressable Asset System)を試してみた (その1)

# 前提
- unity 2018.4.7f1
- Addressables 1.1.10
- 導入から簡単に使ってみるところまで
    - アセットに含まれるプレハブとスプライトを使って、スライドショウを実行します。
- 次の記事「[簡単リモートアセット(Unity Addressable Asset System)を試してみた (その2)](https://qiita.com/tetr4lab/items/e385ebc0e7d87aec6776)」
- 関連記事「[Googleスプレッドシートを使ったUnityコラボ開発 (ScriptableObject、Addressables 対応版)](https://qiita.com/tetr4lab/items/8a52d9c74ddfd5d66876)」

# 公式ドキュメント
- [Packages documentation](https://docs.unity3d.com/Manual/PackagesList.html) (英語)
    - [Unity Addressable Asset System 1.2](https://docs.unity3d.com/Packages/com.unity.addressables@1.1/api/UnityEngine.AddressableAssets.Addressables.html#UnityEngine_AddressableAssets_Addressables_LoadAssetsAsync__1_System_Collections_Generic_IList_System_Object__System_Action___0__UnityEngine_AddressableAssets_Addressables_MergeMode_) (英語)
- [Class Addressables](https://docs.unity3d.com/Packages/com.unity.addressables@1.1/api/UnityEngine.AddressableAssets.Addressables.html#UnityEngine_AddressableAssets_Addressables_LoadAssetsAsync__1_System_Collections_Generic_IList_System_Object__System_Action___0__UnityEngine_AddressableAssets_Addressables_MergeMode_) (英語)

# 導入
- パッケージマネージャーを使ってAddressablesを導入します。
- Window (Menu) > Package Manager > Pakkages (Window) > Addressables > Install (Button)
![SS-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/f3d55bef-4f4e-77a0-56c8-14c7e8eeb408.png)

# Addressablesの初期化
- Addressablesウィンドウで初期化を実施します。
- Window (Menu) > Asset Management > Addressables (*) > Addressables (Window) > Create Addressables Settings (Button)  
※ 1.3.8だと、Groups
![SS-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/9d681e36-17ff-e96d-55e4-371e6699cd50.png)

# 設定
- Addressables (Groups)ウィンドウから設定を選び、インスペクターで設定します。
![SS-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/2e613ddd-6c01-aa9e-8dc0-4b7f139489a4.png)  
- Addressables (Window*) > Profiles Default > Inspect Profile Settings  
※ 1.3.8だと、Addressables Groups (Window)  
![SS-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/a6617952-d1a8-4b97-0abc-fbe854ea5405.png)

### カタログ
- `Player Version Override`を記入し、`Build Remote Catalog`をチェックして、`Remote Catalog Build/Load Path`をRemote Pathに設定します。  
![SS-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/8b74bead-fc1c-74dc-4115-8a3e61d690bc.png)  
これで、指定したバージョンを含む名前で、Build Pathにカタログが生成されます。
- バージョンが指定されないと、代わりにビルド日時が使われます。  
古いカタログは自動的に削除されないので、ファイルが増えていきます。  
対して、同じバージョンを指定している間は、カタログは上書きされます。
- カタログは、実行時にリモートから読み込まれ、ローカルと比較して更新の有無が判定されます。  
カタログが作られていなかったり、正しいカタログが読み込めないと、アセットファイルが新しくなっていても更新は行われません。
- アプリとアセットが必ず同時に更新されるプロジェクトであれば、カタログは不要だと思われます。  
対して、アセットだけ更新される場合は、カタログが必要です。

### リモートパス
- `RemoteBuildPath`と`RemoteLoadPath`を記入します。  
![SS-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/b416e827-29d3-a863-2363-1a256de4310f.png)
- これらは、それぞれ、「アップロードするアセットファイルを作るフォルダ」と「アップロード先(=実行時に取得する)のURL」です。
    - `[BuildTarget]`が、ビルドターゲットを表す文字列に置き換えられることで、ターゲット毎に異なるアセットに切り替わります。
    - アップロード先へは、自分でアップロードする必要があります。

### ラベル
- 新しいラベル(タグ)を作ります。  
![SS-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/8fd6df3d-a4ec-a8cf-34db-719554380f4d.png)  
![SS-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/3b271e34-7b36-af81-9b3a-57c4fe12423e.png)  
これによって、ラベル毎に一括ロードできるようになります。

# アセットの構築
### グループの作成
- Addressablesウィンドウにグループを作ります。
- Addressables (Window*) > Create New Group (Context Menu) > Packed Assets  
※ 1.3.8だと、Addressables Groups (Window)
![SS-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/b7c9d405-fb58-f89c-1848-6dad4462c08c.png)
- デフォルトグループは、コンテキストメニューから切り替え可能です。

### グループの設定
- Addressablesウィンドウで作成したグループ`Packed Assets`を選択して、インスペクターで設定します。
- `Build Path`と`Load Path`をリモートに設定します。  
![SS-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/1b19d1f6-c87e-d981-f31a-78122341396d.png)

### アセットの追加
- グループにプロジェクトウインドウからアセット(ファイルまたはフォルダ)をドラッグ&ドロップして追加します。  
- フォルダを追加すると階層ができます。  
![SS-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/a9934bba-cc66-44a6-4b45-1326c3820855.png)
- Addressablesに追加されたアセットには、マークが付きます。  
![SS-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/e32cba3a-21a1-6a2c-819f-27403660947a.png)
    - このチェックを外すと、Addressablesウィンドウからも消えます。
- 逆に、Projectウィンドウで選んだアセットに対して、インスペクターでマークすることで、デフォルトグループに加えることも可能です。
- アセットや階層には、ラベル(タグ)を付けられます。  
![SS-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/ac86ec92-4303-d974-f1af-46120aa7cb1a.png)
- アセットや階層の名前(Asset Address)は元のパス名から自動で付けられます。
- これらのアドレスは任意に変更できます。アセットや階層を選んで、コンテキストメニューから`Simplify Entry Names`を実行すると自動的に短くできます。  
![SS-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365845/e3f6133d-443a-4fe2-6cfd-e4622de60d76.png)
- アセットや階層の名前は、Addressablesウィンドウでも、インスペクターでも変更可能です。
- アセットや階層は、ドラッグ&ドロップで、あるいは、コンテキストメニューからグループ間を移動できます。

### アセット(だけ)のビルド
- Addressables (Window) > Build > Build Player Content

# アセットを使う

### アセットの参照
- アセットは、`string`(名前、ラベル)、または、`AssetReference`(インスペクター経由)で特定します。  

```cs:
// インスペクターでアセットを指定する
[SerializeField] private AssetReference SpriteAsset = default;
```

- 以降の例では、`AssetReference`は使用せず、名前とラベルを使います。

### サンプルの流れ

```cs:SampleMain.cs
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AddressableAssets;

public class SampleMain : MonoBehaviour {

	private void Start () {
		StartCoroutine (loader ());
	}

	private IEnumerator loader () {
		// ロードの開始
		var textHandle = Addressables.LoadAssetAsync<GameObject> ("Prefabs/BottomText.prefab");
		var imageHandle = Addressables.LoadAssetAsync<GameObject> ("Prefabs/FullScreenImage.prefab");
		var spriteHandle = Addressables.LoadAssetsAsync<Sprite> ("Sprites", null); // ラベルを指定して一括ロード
		// 完了の待機
		yield return new WaitUntil (() => textHandle.IsDone && imageHandle.IsDone && spriteHandle.IsDone);
		// エラーがないことを確認
		if (textHandle.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded
			&& imageHandle.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded
			&& spriteHandle.Status == UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationStatus.Succeeded) {
			// プレファブからオブジェクトを生成
			var image = Instantiate (imageHandle.Result, transform).GetComponent<Image> ();
			var text = Instantiate (textHandle.Result, transform).GetComponent<Text> ();
			// スプライトを順に切り替え
			for (var i = 0; i < spriteHandle.Result.Count; i = (i + 1) % spriteHandle.Result.Count) {
				image.sprite = spriteHandle.Result [i];
				text.text = $"{spriteHandle.Result [i].name}  <size=20>© UTJ/UCL</size>";
				yield return new WaitForSeconds (3f);
			}
		}

	}
}

```

- 非同期に処理する必要があるので、コルーチンを使います。
- プレハブは個別の名前を、スプライトは一括してラベルを指定してロードを開始します。
- 非同期ロードハンドルをチェックしてロードの完了を待ちます。
- ロードが成功したかチェックします。
- プレハブからオブジェクトを生成します。
- スプライトを順に表示します。

# プロジェクトの入手 (GitHub)
ダウンロード ⇒ [AddressableAssetsTest.unitypackage](https://github.com/tetr4lab/AddressableAssetsTest/raw/master/AddressableAssetsTest.unitypackage)
[ソースはこちらです。](https://github.com/tetr4lab/AddressableAssetsTest)

# 追補 (1.2.4)
- 先祖-子孫関係のフォルダーを双方Addressablesに加えると、ビルド時に重複エラーが生じます。しかし、エディターで実行する際には、このエラーは検出されません。
   - 所在の異なる同じ名前のフォルダーをAddressablesに加えることは可能です。
- Addressablesに加えたアセットの名前や所在を変更した際に、まれにAddressablesが追従することがあります。しかし、たいていはそのままなので、再度加え直す必要があります。

# 追補 (2020/04/04)
- Unityエディタ上では動くのに、スマホ実機(iOS/Android)で例外が発生して止まってしまうことがあります。
    - Xcodeのログで 「MissingMethodException: Default constructor not found for type UnityEngine.ResourceManagement.AsyncOperations.ProviderOperation」とか出ます。
    - まず、アドレスの不整合を疑ってみましょう。
        - "Simplify Addressable Names"を前提にしたコードなのに、"AddressablesAssets Groups"ウインドウで実施を忘れているとかないでしょうか?

# あとがき

### 気になったこと
- まだ、公式ドキュメントが英語しかないようです。
- 短期間に色々変わっているようで、ネットで調べた情報が実際と異なったりしました。
- 設定をいじっていたら、Addressablesウインドウからアセットの一部が消えてしまって復旧できなくなる…ということが2度ありました。

### 今後の予定
- 次回は「Addressablesを製品で使うとどうなるだろう」というテーマになると思います。
- 具体的な製品プロジェクトの予定が立ったら進展すると思います。

### 参考にさせていただいた記事 (Qiita)
- [Addressable Asset System を試してみました。](https://qiita.com/kamihiro/items/3e9876bd4e4462a57d1d)
- [Addressable Assets Systemを完全に理解する](https://qiita.com/k7a/items/b4fd298bcb64dc968ad1)
- [知っておきたいAddressable Asset Systemの仕組み](https://qiita.com/yukiarrr/items/2e2b21530600ccf18f70)

どうもありがとうございました。

---
[UNITY-CHAN! © Unity Technologies Japan/UCL](http://unity-chan.com/)