Addressables で ScriptableObject からデータをロードする
はじめに
Unity の Addressables と ScriptableObject を用いて、ゲーム内に定義したアセットを任意のタイミングでロードするフローを確認します。
動作環境
- Unity 2022.3.20f1
- Addressables 1.21.20
Addressables とは
Unity におけるアセット管理システムであり、 Package Manager からインストール出来ます。事前にアセットをロード可能な対象としてグルーピングしておくことで、グルーピングされたアセットの中からいつでもアセットをロードし使うことが出来るようになります。(アセットには、ゲーム画像やテクスチャ、マテリアル、ゲーム音源など様々なものがあります)
ScriptableObject とは
ゲーム内のアイテムや敵パラメータ等のデータを作るために使うことが出来るシリアライズ可能なクラスです。アイテムや敵パラメータといったデータを ScriptableObject クラスからアセット化しておくことで、先に挙げた Addressables を介してロードすることが出来ます。
動作確認
Addressables のインストール
Unity の Package Manager を介して、Addressables をインストールします。
Package Manager を開き、Packages: Unity Registry
になっている状態で Addressables
を検索すると以下のようなパッケージが表示されるかと思います。これが表示されれば、右上に「Install」といったボタンが出ていると思うので、そこからインストールが可能です。
インストールが完了したら、Unity Editor の Window
から以下の Groups
をクリックします。
Groups
クリック後に表示されるウィンドウにある Create Addressables Settings
をクリックします。これを行うと、Assets
フォルダ直下に AddressableAssetsData
という名前のフォルダが自動的に生成されます。このフォルダ内に Addressables に関する設定が格納されているようです。
ScriptableObject からアセットを作成
ScriptableObject を使ってデータアセットを作成します。
今回は、カードゲームにおけるカードデータをアセットとして管理することを想定し、以下のような CardAsset
クラスを ScriptableObject で定義します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "CardAsset", menuName = "MyAssets/CardAsset")]
public class CardAsset : ScriptableObject
{
public string cardID;
public string cardName;
public int cardCost;
public int cardPower;
public int cardLife;
}
クラス定義が出来たら、Unity Editor 側で以下のようにカードデータをアセットとして作成します。今回は Assets/Scripts/Data/CardAssets/
というフォルダを作り、その中に 3 つのカードアセットを作成してみました。
アセットを Addressables に登録
先ほど作成したカードアセットを Addressables に登録してみます。Addressables へのアセット登録は 1 つずつでもフォルダ単位でも可能です。今回はフォルダごとまとめて登録します。
Project ウィンドウから Assets/Scripts/Data/CardAssets/
を Addressables Groups
にドラッグ&ドロップすればOKです。
また登録後、シンプルな識別子でアセットをロード出来るようにするために、Simplify Addressable Names
をクリックしておきましょう。
こうすると、今回取得したいアセットに対して CardAssets/card_1.asset
というようなアドレスでアクセス可能となります。
アセットをロードする Script を作成
登録したアセットを Script から取得してみます。
以下の Script を作成しました。
AddressablesTest.cs
using System.Collections;
using System.Collections.Generic;
using Frontier.Data;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class AddressablesTest : MonoBehaviour
{
private PureAssetLoader pureAssetLoader;
private void Awake()
{
pureAssetLoader = new();
}
private void Start()
{
pureAssetLoader.Load("card_1.asset");
}
}
PureAssetLoader.cs
using System.Collections;
using System.Collections.Generic;
using Frontier.Data;
using UnityEngine;
using UnityEngine.AddressableAssets;
public class PureAssetLoader
{
private const string BASE_ADDRESS = "CardAssets";
async public void Load(string assetAddress)
{
string _address = $"{BASE_ADDRESS}/{assetAddress}";
CardAsset cardAsset = await Addressables.LoadAssetAsync<CardAsset>(_address).Task;
Debug.Log(cardAsset.cardName);
Addressables.Release(cardAsset);
}
}
空のオブジェクトを作り、AddressablesTest.cs
をそこに Add します。
AddressablesTest
が PureAssetLoader
の Load
メソッドを呼び出し、引数で指定されたアドレスに対応するカードアセットを取得します。Generics により CardAsset
の型情報を与えられるため、Addressables.LoadAssetAsync
の返り値は自身で定義した CardAsset
のインスタンスとして受け取ることが出来ます。
実行
この状態で Play Mode に入ると、CardAssets/card_1.asset
のアセットが読み込まれ、その cardName がログ出力されるかと思います。
終わりに
Addressables を使うことで、プロジェクト内の好きなアセットを一元管理し、好きなタイミングでロードできるため便利に感じました。今回は ScriptableObject のアセットを手動で作成・登録するフローにより動作検証を行いましたが、例えば、外部からアセットリストを取得 -> リストにあるアセットを全て Addressables に登録 -> 登録したアセットをまとめて取得、といった使い方も面白そうですね。
また今回取り上げませんでしたが、 Addressables は外部URLにあるアセットを直接取得することも出来るようなので、Unity プロジェクト内を変更することなく、外部リソースだけ更新といった使い方も出来るみたいです。便利ですね。
参考
Discussion