Unity

UnityのInspectorで扱えるDictionary

More than 5 years have passed since last update.

UnityのInspectorViewはうまく使えば、新しくスクリプトを作らずにオブジェクトの動作をかえることができて便利ですが、変数によっては表示できないものがあり、そのなかで一番困るのがDictionaryだったりします。

unityのInspectorViewではジェネリッククラスはList以外は扱えないので、型をジェネリックスで与えるDictionaryは表示出来ません。

そこで、簡単にInspectorで扱えるように工夫してみました。


SerializableDictionary.cs

using UnityEngine;

using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Serialize {

/// <summary>
/// テーブルの管理クラス
/// </summary>
[System.Serializable]
public class TableBase<TKey, TValue, Type> where Type : KeyAndValue<TKey, TValue>{
[SerializeField]
private List<Type> list;
private Dictionary<TKey, TValue> table;

public Dictionary<TKey, TValue> GetTable () {
if (table == null) {
table = ConvertListToDictionary(list);
}
return table;
}

/// <summary>
/// Editor Only
/// </summary>
public List<Type> GetList () {
return list;
}

static Dictionary<TKey, TValue> ConvertListToDictionary (List<Type> list) {
Dictionary<TKey, TValue> dic = new Dictionary<TKey, TValue> ();
foreach(KeyAndValue<TKey, TValue> pair in list){
dic.Add(pair.Key, pair.Value);
}
return dic;
}
}

/// <summary>
/// シリアル化できる、KeyValuePair
/// </summary>
[System.Serializable]
public class KeyAndValue<TKey, TValue>
{
public TKey Key;
public TValue Value;

public KeyAndValue(TKey key, TValue value)
{
Key = key;
Value = value;
}
public KeyAndValue(KeyValuePair<TKey, TValue> pair)
{
Key = pair.Key;
Value = pair.Value;
}

}
}


このままジェネリックスを使っても表示できないので、利用するときにはこれらのクラスを継承して使います


SerializableTest.cs

using UnityEngine;

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

/// <summary>
/// ジェネリックを隠すために継承してしまう
/// [System.Serializable]を書くのを忘れない
/// </summary>
[System.Serializable]
public class SampleTable : Serialize.TableBase<string, Vector3, SamplePair>{

}

/// <summary>
/// ジェネリックを隠すために継承してしまう
/// [System.Serializable]を書くのを忘れない
/// </summary>
[System.Serializable]
public class SamplePair : Serialize.KeyAndValue<string, Vector3>{

public SamplePair (string key, Vector3 value) : base (key, value) {

}
}

public class SerializableTest : MonoBehaviour {

//Inspectorに表示できるデータテーブル
public SampleTable sample;

void Awake () {
//内容を列挙
foreach (KeyValuePair<string, Vector3> pair in sample.GetTable()) {
Debug.Log ("Key : " + pair.Key + " Value : " + pair.Value);
}
}

}


DictionaryではなくList型でいったんデータを保持し、利用時にはList型のデータをDictionary型に流し込むことで実現しています

利用するときは

1, Serialize.KeyAndValueを継承して、KeyとValueの型を指定したクラスを作る

(KeyとValueを引数に持つコンストラクタを作らないといけない)

2, Serialize.TableBaseを継承して、KeyとValueに加えて1で作成したクラスを指定したクラスを作る

3, 2で作ったクラスを利用したいMonoBehaviourのスクリプトに変数定義

ss.png

これによってInspector上でDictionary(のようなもの)を操作することができます

また、スクリプト側でTableを取得するには

sample.GetTable()

と記述すれば、Dictionaryを取得することができます

追記

シリアライズできるので、BinaryFomatterでバイナリファイルに保存することもできて便利かも