Unity5系でのAsset Bundle使い方まとめ

こちらは[qnote Advent Calendar](http://qiita.com/advent-calendar/2015/qnote) 16日目の記事となります。

最近Asset Bundleを使うことが多い（ってか必須になってる）ので、使ったことない人向けにざっくりと使い方をまとめてみました。

# Asset Bundleの概念
Unityでゲーム開発する際、アプリのアップデート無しにコンテンツを増やしたい場合はAsset Bundleを使うと便利です。

画像とか音声とかテキストとかのファイル（Asset）をUnityで固めて「Asset Bundle」にします。
こいつをサーバに配置し、ゲーム中にDL・展開して使います。

# Asset Bundleを固めてみよう
まずはAsset Bundleを固めてみましょう。

※ちなみに、本記事はAndroid/iOSアプリ向けを想定しています。
（他OSアプリの場合、Asset Bundleビルド時のプロパティを変える必要があります）

## Assetの準備
![cat.png](https://qiita-image-store.s3.amazonaws.com/0/74903/d1e3fe0c-9612-c7be-bce6-bf852892b5b9.png)をcat.pngとして保存、Unityにインポートします。
今回は、Texture TypeはSpriteにします。
<img width="603" alt="スクリーンショット 2015-12-16 0.09.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/74903/c09da779-9e67-c378-7880-5d79b647e5db.png">

## Asset Bundleの登録
cat.pngのInspectorの↓を見てみると、Asset Bundleのプルダウンがあります。
プルダウンでNew...を選択し、新しくAsset Bundleを作成します。
今回は「catbundle」にしました。
<img width="305" alt="スクリーンショット 2015-12-16 0.12.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/74903/95b2aafe-5890-3d20-57c3-2b0c6f5b50d2.png">

ちなみに、ひとつのAsset Bundleには複数のAssetを含ませることが可能です。

## Asset Bundle作成用のスクリプトを準備
公式ドキュメント
http://docs.unity3d.com/ja/current/Manual/BuildingAssetBundles5x.html
に記載はありますが、ちとわかりにくい＆Android/iOS向けにはカスタムする必要があります。
ってことで、下記を使えばOKです。

```csharp:CreateAssetBundles.cs
using UnityEditor;

public class CreateAssetBundles
{
    [MenuItem("Assets/Build AssetBundles")]
    static void BuildAllAssetBundles()
    {
        // Android用
        BuildPipeline.BuildAssetBundles("Assets/AssetBundles/Android", BuildAssetBundleOptions.None, BuildTarget.Android);
        // iOS用
        BuildPipeline.BuildAssetBundles("Assets/AssetBundles/iOS", BuildAssetBundleOptions.None, BuildTarget.iOS);
    }
}
```
こいつをAssetsディレクトリに配置すると、Assetsメニューに「Build AssetBundles」の項目が追加されます。
<img width="399" alt="スクリーンショット 2015-12-16 0.22.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/74903/049d1cd7-2f3c-9314-b490-c085df06e0e4.png">

## Build AssetBundles実行
Asset Bundle出力用に下記2つのディレクトリを作成してから、「Build AssetBundles」を実行してみてください。

```
Assets/AssetBundles/Android
Assets/AssetBundles/iOS
```

こんな感じで、各OS用のAsset Bundle「catbundle」が作成されました。
<img width="306" alt="スクリーンショット 2015-12-16 0.28.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/74903/996b66f8-9493-29cb-cc26-0cfa2883f517.png">

ちなみに、catbundleに含まれているファイルは、同ディレクトリに生成されたcatbundle.manifestに記載されています。

# Asset Bundleをサーバに配置する
上記で生成されたAndroid/iOS用「catbundle」をサーバに配置します。
DropBoxでもParseでも、好きなところに置いてください。

# Asset Bundleを使用する
Asset Bundleを使用するには、

- ダウンロード
- 読み込み

の手順が必要です。

## Asset Bundleを管理するスクリプト
ダウンロード後はキャッシュしておいた方が扱いやすいので、そのあたりの処理を超シンプルにするとこんな感じです。

```csharp:AssetBundleManager.cs
using UnityEngine;
using System;
using System.Collections;

public class AssetBundleManager : MonoBehaviour
{
    // AssetBundleのキャッシュ
    private AssetBundle assetBundleCache;

    // Asset Bundleをロードするコルーチンです
    public IEnumerator LoadAssetBundleCoroutine()
    {
        // Asset BundleのURL
        var url = "";
        #if UNITY_ANDROID
        url = "http://Android用catbundleを配置したURL";
        #else
        url = "http://iOS用catbundleを配置したURL";
        #endif

        // ダウンロード処理
        var www = WWW.LoadFromCacheOrDownload(url, 1);
        while (!www.isDone)
        {
            yield return null;
        }

        // TODO エラー処理とか

        // Asset Bundleをキャッシュ
        assetBundleCache = www.assetBundle;

        // リクエストは開放
        www.Dispose();
    }

    // Asset BundleからSpriteを取得します
    public Sprite GetSpriteFromAssetBundle(string assetName)
    {
        try
        {
            return assetBundleCache.LoadAsset<Sprite>(string.Format("{0}.png", assetName));
        }
        catch (NullReferenceException e)
        {
            Debug.Log(e.ToString());
            return null;
        }
    }
}
```

サンプルなので極力シンプルに書きましたが、本来は

- Asset BundleのURLをサーバから取得するように
- Asset Bundleを複数管理可能に
- Asset Bundleのバージョン管理も可能に（バージョンが変わっている場合のみダウンロード）

などの処理を入れた方が良いです。

## Asset Bundleを使う側の処理
Asset Bundleを使う側はこんな感じです。

```csharp:SceneController.cs
using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class SceneController : MonoBehaviour
{
    public AssetBundleManager assetBundleManager;
    public Image image;

    public IEnumerator Start() {
        // Asset Bundleのロード処理
        yield return StartCoroutine(assetBundleManager.LoadAssetBundleCoroutine());
        // ロード完了後、Assetが取り出せるようになる
        image.sprite = assetBundleManager.GetSpriteFromAssetBundle("cat");
    }
}
```

## 実行してみる
シーンにUnity UIのImageオブジェクトを配置します。
その後、Canvasに「AssetBundleManager」「SceneController」をアタッチします。
SceneControllerのプロパティに、AssetBundleManagerとImageをひも付けておきます。
<img width="1130" alt="スクリーンショット 2015-12-16 1.49.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/74903/dc26a5e2-d6c5-49cf-57d7-bd8b02448f42.png">

実行してみると、Imageにcat.pngが反映されました！
Asset Bundleバッチリ使えてますね〜
<img width="665" alt="スクリーンショット 2015-12-16 1.53.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/74903/32fd1507-3d01-a10b-5fbf-83eb112821e7.png">

# まとめ
Asset Bundle、Unityでそこそこの規模のゲームを作る場合は必ず使うことになるかと思います。
制御は意外と簡単ですので、ぜひチャレンジしてみてください。