ひとりでのアプリ開発 - fineの備忘録 -

ひとりでアプリ開発をするなかで起こったことや学んだことを書き溜めていきます

Unity - CSVファイルのデータを Scriptable Object に流し込む -

初めに

 Unity では Scriptable Object と呼ばれるデータが保存されたオブジェクトを作ることができます。本記事は CSVファイルのデータから Scriptable Object を生成する方法についての記事になります。

Scriptable Object

Scriptable Object

docs.unity3d.com

 上の画像のように、データを保存することができるオブジェクトになります。データを取得する際、毎回CSVファイルなどからデータを読み込むと処理が重くなります。そこであらかじめ Scriptable Object にデータを流し込み、保存しておくことでメモリの節約につながります。

Scriptable Object のチュートリアル

learn.unity.com

 Unity Learn に Scriptable Object 入門があります。時間がある方はぜひ。

CSVファイルのデータを Scriptable Object に流し込む

CSV ファイルのデータを読み込む

 まず、CSV ファイルのデータを読み込む必要があります。以前、記事にまとめましたので、そちらをご覧ください。

fineworks-fine.hatenablog.com

スクリプトの用意

 次の2つのスクリプトを用意します。以前の記事では、 [System.Serializable]属性をつけたクラス(CharaData のクラス)を同じスクリプト内に書いていましたが、今回は別のスクリプトに分けています。


〇ScriptableObjectになるクラスを定義、[System.Serializable]属性をつけたクラスを記述したスクリプト

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharaDataBase : ScriptableObject {
    public CharaData[] datas;
}

[System.Serializable]
public class CharaData
{
    public string name;
    public int Hp;
    public int Power;
}


CSVファイルを読み込み、Scriptable Object を生成、更新するためのスクリプト

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

#if UNITY_EDITOR
public class PostProcessingTest : AssetPostprocessor
{
  static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
  {
    foreach (string str in importedAssets)
    {
      // IndexOfの引数は"/(読み込ませたいファイル名)"とする。
      if (str.IndexOf("/CSVTestData.csv") != -1)
      {
        Debug.Log("CSVファイルがあった!!!");
        // Asset直下から読み込む(Resourcesではないので注意)
        TextAsset textasset = AssetDatabase.LoadAssetAtPath<TextAsset>(str);
        // 同名のScriptableObjectファイルを読み込む。ない場合は新たに作る。
        string assetfile = str.Replace(".csv", ".asset");
        CharaDataBase cd = AssetDatabase.LoadAssetAtPath<CharaDataBase>(assetfile);
        if (cd == null){
          cd = new CharaDataBase();
          AssetDatabase.CreateAsset(cd, assetfile);
        }

        cd.datas = CSVSerializer.Deserialize<CharaData>(textasset.text);
        EditorUtility.SetDirty(cd);
        AssetDatabase.SaveAssets();
      }
    }
  }
}
#endif

 MonoBehaviour ではなく AssetPostprocessor のコンポーネントを利用しています。これは、Project 内のファイルに変更があった場合に呼び出されます。OnPostprocessAllAssets は Assets 内のファイルがインポート、削除、移動した場合に呼び出されるため、そこに CSVファイルの読み込み、Scriptable Object に保存する処理を書いています。

docs.unity3d.com

Scriptable Object に保存したデータが消える

 The associated script can not be loaded. と表示され、保存したデータが消えることがおきました。その原因は ”スクリプト名と Scriptable Object継承クラス名が一致していないかったから" でした。
 本記事では、CharaDataBase で統一しなければいけなかった。

machinemaker.hatenablog.com

Scriptable Object の生成

 CSVファイルを Assets 直下にインポートしてみましょう。自動的に Scriptable Object が生成されます。


Scriptable Object のデータをスクリプトから取得する

 Scriptable Object のデータを取得し、コンソールにログを表示してみます。

 次のスクリプトをゲームオブジェクトにつけます。

 Scriptable Object は Scriptable Object継承クラス名を public もしくは SerializeField で取得します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharaTestScript : MonoBehaviour
{
    //Scriptable Object を取得
    [SerializeField] CharaDataBase charabase;

    // Start is called before the first frame update
    void Start()
    {
      for(int i = 0; i < charabase.datas.Length; i++)
      {
        Debug.Log("Name:" + charabase.datas[i].name + ", Hp:" + charabase.datas[i].Hp + ", Power:" + charabase.datas[i].Power);
      }
    }
}

  あとは、ドラッグ&ドロップをし、実行すれば ok です。

(実行結果)

最後に

 CSVファイルのデータから Scriptable Object を作ってみました。データ量が膨大になると必要になる場面が出てくると思います。なお、Scriptable Object は JSON など別のファイルからも生成できます。