simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

Unity:2018.2以降のPrefabとAssetBundleの変化を追う

ココが変わる!Unityの新しいエディターワークフロー
CEDEC2018

いつもお世話になっている「テラシュールブログ」の中の人の発表です。
これだけ Slide Share にアップされていない様子なので、記憶を頼りに
と思ったら Youtube に動画を発見した
www.youtube.com

Prefab と AssetBundle について簡単におさらい

  • Prefab

Prefab はシーン内のゲームオブジェクトをアセット化したものです。
元となるのはゲームオブジェクトなので、Prefab をもとにシーン内でゲームオブジェクトを復元するようにしてインスタンス化します。
このとき Prefab 化(アセット化)したときと同じコンポーネント構成でシーン内に登場します。

  • AssetBundle

巨大な動画、音声、画像ファイルをアセットとして外部サーバーに配置してゲームで必要になったときにダウンロードして使う仕組みで
とても一般的なゲームの実装方法ですが、共通のシステムは存在せず、各社で技術者を雇うか育てるかして独自実装してきました。
このアセットを外部サーバーに置く、必要になったらダウンロードすることを「AssetBundle」と呼びます。

今回の記事で注目するべきこと

■既存の Prefabの問題
Prefab の2 階層目以降の編集ができない
Prefab の下の階層に Prefab を配置できない
とても似ている Prefab 派生オブジェクトを一括編集できない
Prefab の編集の適用は Prefab 単位でしかできない
参照アセットは強制で一括読み込みするので、完了までゲームがフリーズする
AssetBundle に Prefab を置くと動作を確認するのに、長時間かかる(ちょっとした修正にAsset Bundle のビルドが必要)

一言でまとめると、Prefab を扱うために面倒を見るためのエンジニアやコードが必要なことが問題
もっと楽に Prefab を扱いたい

そこで新しい Prefab Workflow が登場しました。←ここが注目するべきこと

■ New Prefab Workflow
1.アイコンからゲームオブジェクトと Prefab を識別できる
2.Prefab の編集した値が太くなるだけではなく、項目の先頭が青く色付く
3.Prefab の何を編集したかを確認する UI が新しく追加される
これには項目を選択すると編集前と編集後のインスペクタを比較する機能がある
Prefab の変更の適用をフィールド単位で行えるようになった
4.Prefab を編集するシーンを開くボタンが追加された(Prefab エディター)
5.Prefab の子階層に Prefab を配置できるようになった(Nested Prefab)
値のオーバーライド(適用)では、どの階層の Prefab がオーバーライド(適用)を行うかを指定できるようになる
発表動画では詳しくデモを通して解説があり、新しく追加された3.Prefab の何を編集したかを確認する UI にて指定できる
6.Prefab の Variant (コンテキストメニューの Create > Prefab Variant を選択で作成)
Prefab なのに個別に値をオーバーライドできるようになり、つまりは、ちょっとだけ内容が違う Prefab を量産できるようになり
さらにオリジナルの変更が Variant にも反映されるので、とても似ている Prefab 派生オブジェクトを一括編集する操作が Variant を使って可能になる
7.モデルの更新でもコンポーネントを保持
今までモデルを差し替えたときにボーン構造が異なると、モデルの Prefab は初期化されてしまっていたが
Nested Prefab の仕組みが入ったので、見た目だけの更新だけで、モデルに与えていた様々なコンポーネントなどが保持されるようになった

■Addressable Asset System
これまでのアセット参照はドラッグ&ドロップだった
ただし直接参照は強制で一括読み込みするので、完了までゲームがフリーズする

既存のロード手段は三つ
・直接参照
・Resources (非推奨)
・AssetBundle (難易度高い)

新しい Unity は以下の2つに変更された
・直接参照
・Addressable Asset System

導入は Package Manager を通して Addressable System を選択して導入できる
コードは以下のように修正する

[SerializeField] GameObject player;
↓
[AssetReferanceTypeRestriction(typeof(GameObject))]
public AssetReference player;

アセットの登録は今まで通りドラッグ&ドロップ

インスタンス生成のコードが変わる

GameObject playerInstance;
playerInstance = Object.Instantiate(player);
↓
GameObject playerInstance;
player.Instantiate<GameObject>().Completed += (op) => { playerInstance = op.Result; }

インスタンス生成が非同期で行えるようになるコード例が登場
(読み込み完了後のインスタンスへの操作も、ラムダ式の中で書ける)

オブジェクトの破棄も変わったので注意

Destroy(playerInstance);
Resources.UnloadAsset(asset);
↓
Addressables.ReleaseInstance(playerInstance);
Addressables.ReleaseAsset(asset);

■Addressables ウィンドウ
AssetBundle に登録したアセットを一覧でアドレスを確認でき、検索用のタグも付けられる

var preloadOp = Addressables.PreloadDependencies("label_name", null);
yield return preloadOp;
public AssetLabelReference hazardsLabel;

var op = Addressables.LoadAssets<IResourceLocation>(hazardsLabel.labelString, null);
yield return op;
hazardLocations = new List<IResourceLocation>(op.Result);

でラベル一致のアセットを事前ロードできる書式が追加されました、便利です。

アドレスから直接オブジェクトを生成する手段もある
Addressables.Instantiate("Address");

さらにこのウィンドウではグループごとに AssetBundle を配置するパスを指定可能
ローカルパスでもサーバーのリモートパスでも可
この設定はプロファイルとして Default, Dev, Release などの名前を付けて、選択一つで切り替え可能になっています。(開発フローを意識したものです)

格納方式も選べる
1アドレスにつき1AssetBundle → pack Separately
グループを1AssetBundle → pack Together

■AssetBundle を用いた高速デバッグ
Play Mode を以下から選択できる
・Fast (AssetBundle 構築しない、AssetDatabase から直接アセット取得 なのでゲーム動作確認時に選ぶとよい)
・Virtual (AssetBundle 構築しない、しかしアセットの依存関係のみを本番と同じにできる、本番想定の関係性構築で利用する)
・Packed (AssetBundle を構築、AssetBundle からアセットを取得 なので本番想定のパフォーマンスをチェックできる)

■PM Profiler
Resource Profiler とも言う
Addressables まわりの操作で生まれたアセットのロード、開放などをプロファイリングすることができる

結論:Addressable Asset System に移行すれば、色々考えなくて良くなる