画像などのアセットデータをプロジェクトに追加して利用する方法として、以下のような手法が主に利用されると思います。
- Resources
- Asset Bundle
- Addressables
Resources はお手軽な手法でアセットを追加できる最も手っ取り早い構築パターンで、初心者向けの参考書で利用される定番のリソース管理手法です。しかし、Resources フォルダーはそれなりのゲームを作成するとなると、もはやあまり推奨される手法ではありません。
以下の公式チュートリアルで解説があります(3章の内容です):
Don't use it. と強いメッセージが書いてあります。
Resources がダメが理由は重要なので、個人的に読んだときにメモした内容を(ミスがあるかもしれませんが)公開しています:
そうなると、AssetBundle か Addressables という話になるのですが、 歴史的には Asset Bundle のつぎに Addressables が登場しています。しかも Addressables は内部の仕組みに AssetBundle を利用しているので、まったくの別物というわけではないです。このあたりは、公式ブログの記事にて:
- Adressable アセットシステム
- Cloud Content Delivery と Addressables に関するご質問について
- アセットバンドルの使用方法を改善してメモリ消費を抑えよう
- Addressable を使用してコンテンツ管理を簡略化する
結論として 2021 年の現在は AssetBundle を管理するツールであった AssetBundle Manager が非推奨になったことから、Addressables がベターな選択になりそうです。
Addressables の難しいというのかややこしいところは、Unity のリソース管理のテクニックにも歴史が出来ていて、その歴史の中で新しい手法だ、ということ。なんで、過去の手法の欠点を補うものだったりするので、強みになっている部分の設計は丁寧/複雑な感じです。
このあたりを整理/勉強した内容をメモした記事です。
Addressables の仕組み is なに?
Addressables もリソース管理の仕組みのひとつなので「アセットを保存してカタログ化して、あとから検索して呼び出せる」機能です。
リソース管理の仕組みとして、Addressables の重要なポイントは:
- 読み込まれるアセットの内容
- アセットの読み込み元
- アセットの読み込み方法
この3つを分離することです。この拡張機能「Addressables」は、どんなアセットでも Addressables(アドレス可能)なマーク(固有の名前)を与えること、というのが一番の特徴になっています。これは「関心の分離」と説明されています。
関心の分離が何をしたいのかというと、コードを修正・変更することなく、コンテンツ(アセット)のパッケージングと配布をやりやすくすること、開発の後期までパッケージデータを保留できるようにしたい、ということです。
過去の手法は、物理的なパッケージの都合(影響)を受けやすかったということ。
ともかく「分離」というのが Addressables のキーワードになりそうです。具体的には、コンテンツをアプリのインストールからも分離できるので、アプリ公開時の OTA (over-the-air) の制限を受けずに、公開済のアプリへ定期的なコンテンツ更新をかけることができるようです。
基本的な考え方は「Addressableアセットシステム入門 - 3つのメリットと基本的な使い方を紹介」の記事がわかりやすいと思いました。
Addressables の使い方
Package Manager から Addressables をインストールします。
追加するとインスペクターウィンドウの一番上に Addressable というパラメーターが追加されます。これが「固有の名前」となるアドレスです。
デフォルトだと、アセットのパスが設定されていますが、名前空間のような規則性をつけて再設定したほうがよいと思います。
アドレスをつけたアセットは Addressables の管理用ウィンドウで確認することができます。
Window > Asset Manager > Addressables > Groups
一番重要なのは、ウィンドウの最初の列 Group Name \ Addressable Name
に表示された「固有の名前」となるアドレスです。
Addressables は、具体的な名称である AssetBundle の名前やファイルパスではなくて、アドレスを介してアセットをロードします。(なので、アドレスをデフォルトのまま、アセットパスにするのはイマイチ特徴を活かしきれないと思います)
テスト
Sprite を読み込む一例です。
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.UI; namespace Sample { public class ImageAddressaableLoader : MonoBehaviour { [SerializeField] private Image Image; [SerializeField] private AssetReference _TestCharactor; [SerializeField] private AssetLabelReference _LabelTest; private void Start() { Addressables.LoadAssetAsync<Sprite>(_TestCharactor).Completed += sprite => { Image.sprite = sprite.Result; }; Addressables.LoadAssetsAsync<Sprite>(_LabelTest, null).Completed += sprites => { foreach (var sprite in sprites.Result) { Debug.Log(sprite.name); } }; } } }
Addressables.LoadAssetAsync<Sprite>(_TestCharactor)
の部分は _TestCharactor
ではなくて、「アドレス」をテキストで直接指定してもよいです(たとえば "images.sample1" のように)が、AssetReference
を介することでインスペクターウィンドウからアセットを設定しておけます。コード指定かインスペクター指定かの違いってだけですね。
機能として、デフォルトで Async 読み込みできるのは便利なんだけど、通常の破棄ではないので注意が必要。
使い終わったときに Addressables.Release()
で開放しないとダメ。これは、アセットの開放を EventViewer で確認したほうが正確です。あとの章で Viewer を取り上げます。
開放しないとダメっていうのは、シーンを切り替えたときにリソースの開放ができているかどうかをチェックしてみました。(後述の「ロード/アンロードを可視化する」を参照)
Event Viewer
Addressables は専用の Viewer を持っています。ただ、この Viewer はプレビュー時代に名前が RM Profiler と呼ばれている時期があったみたいで、情報がすこしややこしくなっているので注意が必要です。
利用するために以下の設定が必要です:
- AddressableAssetSettings 「Send Prfiler Events」を ON
- Addressable/Groups から「Play Mode Script」を Simulate Groups に変更
設定の手順をとばすと、Viewer には何も表示されません。
ロード/アンロードを可視化する
Event Viewer を利用するケースの1つとして、シーンが切り替わったときに正しくアセットが開放されているのかチェックをすることができます。
図は、アセットの開放ができていないため、 reset.png という画像の参照数が重なっていくことがわかります。このあたりが Release()
メソッドでアセットを開放しなければいけないポイントとしてチェックすることができます。
Viewer の練習として:
- 参照カウント数の確認
- いつロード/アンロードされたかを可視化する
このあたりから始めるとよいと思いました。
徐々にアプリが重たくなる要因として、アセット(メモリー)の管理が不十分だった、というのは Unity に限らず DirectX 開発時代よりも前、ポインターから続くような古典的ミスです。十分に注意しておいて損はなさそう。