Programming Serendipity

気まぐれに大まかに生きるブログ

ScriptableObjectの中にScriptableObjectを入れる方法

この記事はさいたまげーむす Advent Calendar 2016 11日目の記事です。

通常、ScriptableObjectにはSerializableなものを格納することができますが、ほかのクラスオブジェクトは一度は入れることはできるものの、一度再生してしまうと情報を失ってしまいます。

そのため、ScriptableObejctの中にクラスごとデータを入れたい場合、そのクラスもScriptableObjectにする必要があります。その手法を紹介しましょう。

using UnityEngine;
using System.Linq;
using UnityEditor;
using System.Collections.Generic;

class ObjA : ScriptableObject
{
    public int blah1;
    public bool blah2;
    public string blah3;
}

class ObjB : ScriptableObject
{
    public List<ObjA> objs = new List<ObjA>();
}


[MenuItem("Tools/Create SO")]
public static void CreateScriptableObject()
{
    const string path = "Assets/B.asset";

    var b = ScriptableObject.CreateInstance<ObjB>();
    for (int i = 0; i < 10; ++i)
    {
        var a = ScriptableObject.CreateInstance<ObjA>();
        // プロジェクトビューで表示される名前
        a.name = string.Format("a[{0}]", i);
        b.objs.Add(a);
    }

    // create
    AssetDatabase.CreateAsset(b, path);

    // アセットとして作成済みのものに対して追加する
    for (int i = 0; i < 10; ++i)
    {
        AssetDatabase.AddObjectToAsset(b.objs[i], path);
    }

    // アセットを再インポートして反映させる(これをしない場合、プロジェクトを保存するまで反映されない)
    AssetDatabase.ImportAsset(path);
}

このスクリプトをEditorフォルダ内に入れてTools > Create SOを実行してみてください。これなら何度実行しても情報は失われません。

一度アセットとして書き出して、そこに追加する形ですね。

解説は大体コードのコメントに書きました。いつか使う時が来るかもしれない。