Unity の ScriptableObject を用いてカードのデータを管理する

Unity ではデータを管理する手法の一つとして ScriptableObject というものがある。 Grow Up Monsters ではいくつものカードのデータを作成管理を行わなければならない。そこで Unity の ScriptableObject の使い方についてまとめていきたいと思う。

1.ScriptableObject とは

「ScriptableObject はスクリプトインスタンスから独立した大量の共有データを格納できるクラスです。SerializedObject と混同しがちですが、こちらはエディタークラスであり、目的も違うものです。例えば 百万の配列をもつスクリプトでプレハブ作ったとします。配列は 4 MB のメモリを占有し、プレハブがオーナーとなります。プレハブをインスタンス化するごとに、その配列が複製されます。ゲームオブジェクトを 10 個作成した場合、10 インスタンス合計で 40 MB の配列のデータとなります。

すべてのプリミティブ型、文字列、配列、リスト、Unity に特有の Vector 3 などの型や、カスタムクラスを Unity は serialize 属性により宣言されたオブジェクトに属する複製としてシリアライズします。例えば SerializableObject を作成して integer が 1 万個だけ格納した場合、配列はそのインスタンスに格納されます。インスタンスは個別のデータのオーナーとして扱われます。ScriptableObject のフィールドや任意の UnityEngine.Object フィールドである MonoBehaviour、Mesh、GameObject 等は値でなく参照が格納されます。ScriptableObject は配列を格納します。ScriptableObject への参照があるプレハブのインスタンスが 10 個あり、4 MB のデータを保有する場合、合計はあくまで 4 MB となり前例のように 40 MB とはなりません。

ScriptableObject を使用する場面は、値の複製をさけることでメモリ消費を節約するときですが、プラグ可能なデータセットを定義することにも使用できます。例をあげると RPG における NPC キャラクターのショップです。例えばカスタムの ShopContents ScriptableObject で複数のアセットを作成して、それぞれで購入可能なアイテムを定義できます。ゲームに 3 つのゾーンがあると仮定すると、それぞれのゾーンで異なるレベルのアイテムを提供できます。ショップのスクリプトの中で ShopContents オブジェクトを参照して利用可能なアイテムを定義できます。サンプルについてはスクリプトリファレンスを参照してください。

ScriptableObject 派生のクラスに付けることのできる CreateAssetMenu によって簡単にカスタムアセットを作成することができます。」

Unity のホームページからそのままコピペ。サイトについてはこちらを参照してほしい。

私の感覚で言うと「いくら複製しても大丈夫なデータベース」位の感覚でいると良いかもしれない。

使い方についてはこちらのサイト様を参考にさせていただいた。

2.ScriptableObject の使い方

ScriptableObject は普段継承して使用している「MonoBehaviour」を「ScriptableObject 」に変更することで使用できる。現在開発中の Grow Up Monsters のカードデータを ScriptableObject を用いて作成すると以下の通りとなる。継承を「ScriptableObject」に変更し必要となるデータをグローバル変数として定義している。また、「[CreateAssetMenu(fileName = “CardData”, menuName = “CardData”)]」の部分では Unity の Assets から CardData 作成できるようにしている。

[cce_csharp]using UnityEngine;
using UnityEngine.UI;

[CreateAssetMenu(fileName = "CardData", menuName = "CardData")]
public class CardData : ScriptableObject
{
    /// < summary>
    /// カード名
    /// < /summary>
    [SerializeField]
    private string Name;
    /// < summary>
    /// カード属性
    /// < /summary>
    [SerializeField]
    private CardType AttributeType;
    /// < summary>
    /// カード画像
    /// < /summary>
    [SerializeField]
    private Image Image;
    /// < summary>
    /// カード効果
    /// < /summary>
    [SerializeField]
    private string Effect;
    /// < summary>
    /// カードの処理
    /// < /summary>
    [SerializeField]
    private AbstructCardProcess Process;
    /// < summary>
    /// カード名の取得
    /// < /summary>
    /// < returns>カード名< /returns>
    public string GetName()
    {
        return Name;
    }
    /// < summary>
    /// カード属性の取得
    /// < /summary>
    /// < returns>カード属性< /returns>
    public CardType GetAttributeType()
    {
        return AttributeType;
    }
    /// < summary>
    /// カード画像の取得
    /// < /summary>
    /// < returns>カード画像< /returns>
    public Image GetImage()
    {
        return Image;
    }
    /// < summary>
    /// カード効果取得
    /// < /summary>
    /// < returns>カードの効果< /returns>
    public string GetEffect()
    {
        return Effect;
    }
    /// < summary>
    /// カード処理クラスの取得
    /// インスタンスの生成を行い、カード処理インスタンスを返却する
    /// < /summary>
    /// < returns>カード処理インスタンス< /returns>
    public AbstructCardProcess GerProcess()
    {
        return Process.CreateInstance();
    }
}[/cce_csharp]

具体的には以下のように 「アセット」 > 「作成」 > 「CardData」 が行えるようになる。新規に作成すると画面右側のようにインスペクターに設定する項目が表示されるので、あとはこの機能を用いて1カードづつ作成していけばカードのデータベースは半自動的に作成されるようになる。

CardData の追加
%d人のブロガーが「いいね」をつけました。