AseetBundle Manager & Example Scenes で AssetBundle の取扱について学習する

# はじめに

* AssetBundle を使ったことがなかったので Unity 社が出している AssetBundle Manager & Example Scenes というアセットを試しながら AssetBundle の取り扱い方について学習していく
* AssetBundle Manager & Example Scenes については http://tsubakit1.hateblo.jp/entry/2016/04/01/184607 が詳しいしこの記事で知った

# AssetBundle を取り扱うにあたってどんな項目があるか

* Asset に AssetBundle 名などを設定する
* AssetBundle をビルドする
* AssetBundle をサーバーにアップロードする
* AssetBundle をダウンロードする
* ダウンロードした AssetBundle から Asset を取得する
* ダウンロードした AssetBundle を破棄する

# AssetBundle Manager はなにをしてくれるのか

* AssetBundle 同士の依存を自動で解決してよしなにロードしてくれる
* 自動で unload してくれる
  * unload 自体は利用する側から明示的に実行する必要がある
  * 重複してロードされている場合に全てのロード箇所から unload された際に実際に unload する
* シミュレートモードを有効にするとローカルファイルをロードしてくれるのでファイルのアップロードが不要になる
  * UnityEditor 実行時のみ有効
  * Variant には対応していない
* ローカルサーバーを立ててそこからロードしてくれる
* UnityEditor のメニューから AssetBundle のビルドができる
* コマンドラインからプロジェクトのビルドができる
  * BuildPipeline.BuildPlayer を使ってコマンドラインからプロジェクトのビルドができるようにしている
  * 実行プラットフォームによって出力ファイル名を調整などしている
* 同じ AssetBundle 名でも更新されていたら新しいものを参照してくれる
  * WWW.LoadFromCacheOrDownload を使ってダウンロードする際に AssetBundle のマニフェストファイルから導出されるハッシュ値を使うので更新されていたら新しいものを取得する
* Variant を指定してロードすることができる

# AssetBundle Manager はなにをしてくれないか

* AssetBundle 名や Variant 名の設定の補助機能はないので Asset 一つ一つ設定する必要がある
  * AssetPostprocessor.OnPostprocessSprites などを使ってディレクトリ名などから自動でセットするような仕組みがほしい
* 作成した AssetBundle をサーバーにアップロードする仕組み
  * https://gist.github.com/tkyaji/115fd06c8a180cb0636af923a1894978 みたいなかんじでアップロードする仕組みがほしい
* ダウンロードした AssetBundle を適宜廃棄する仕組み
  * 明示的に AssetBundleManager.UnloadAssetBundle を実行しないと unload されないで読み込みっぱなしになる
  * 大量に load されているとメモリ使用量が増えるので適宜 unload するような仕組みが欲しくなる
* 取得したいリソースから AssetBundle 名を取得する
  * アプリの実装依存になるので当然 AssetBundle Manager ではやってくれない
  * アイテムのアイコン画像なら "item/icon/{ITEM_ID}" になるとか決めて扱う

# AssetBundle Manager を使ってみる

## AssetBundle をつくる

* インスペクタから設定する
* メニューからビルドする
  * Assets/AssetBundles/Build AssetBundles

## AssetBundle をつかう

### 準備

```cs
		#if DEVELOPMENT_BUILD || UNITY_EDITOR
    // ローカルで AssetBundle を提供するサーバーを立ち上げる
		AssetBundleManager.SetDevelopmentAssetBundleServer ();
		#else
		// Use the following code if AssetBundles are embedded in the project for example via StreamingAssets folder etc:
		AssetBundleManager.SetSourceAssetBundleURL(Application.dataPath + "/");
		// Or customize the URL based on your deployment or configuration
		//AssetBundleManager.SetSourceAssetBundleURL("http://www.MyWebsite/MyAssetBundles");
		#endif
```

### 利用する

```cs
    // 非同期でロードする
    // 非同期といいつつ yield return で終了を待てる
		AssetBundleLoadAssetOperation request = AssetBundleManager.LoadAssetAsync(assetBundleName, assetName, typeof(GameObject) );
		if (request == null)
			yield break;
		yield return StartCoroutine(request);

		// Get the asset.
		GameObject prefab = request.GetAsset<GameObject> ();

		if (prefab != null)
			GameObject.Instantiate(prefab);
```

### 廃棄する

* AssetBundleManager.UnloadAssetBundle で廃棄する
* Load される毎に参照カウントが増え、UnloadAssetBundle が Load された回数だけ呼ばれると実際に廃棄する

### Variant を使う

#### Variant とは

* インスペクタの "AssetBundle" 項目の右側のセレクトボックスで設定するもの
* 同じ AssetBundle 名で同じファイル名で Variant だけ違う物がある場合、ロード時に Variant 名を指定することで読み込むリソースを切り替えられる
* ローカライズや解像度違いの画像などに利用できる
* 詳しい解説 http://tsubakit1.hateblo.jp/entry/2016/04/25/002613

#### 使う

* AssetBundleSample/Scenes/VariantLoader で動的に Variant を選択してロードするサンプルが確認できる