Edited at

[Odin]Unityエディタ上でディクショナリーを設定する


ディクショナリーを設定する

Unityエディタ上で、Dictionaryを設定したい場合もあると思います。

但し、標準のUnityエディタでは、ListのみサポートされているようでDictionaryは設定できません。

有料アセットOdinのSerializedMonoBehaviourを使うと、良い感じにDictionaryが設定できるようになります。


ケーススタディ

実際に、Dictionaryを設定したい場合を見てみます。

AddPointAccordingToは渡された数値に応じて、ポイントを付与する関数ですが、同じような記述が続いており無駄が多いです。動的にプロパティを呼ぶ方法もあると思いますが、可読性的にもパフォーマンス的に無駄な気がします。

ここでエディタ上でDictionaryを使えるようにしてみます。


GameParameter.cs

using UnityEngine;

public class GameParameter : MonoBehaviour
{
public int ScorePoint1;
public int ScorePoint2;
public int ScorePoint3;
public int ScorePoint4;
/* ... */
}



Score.cs

using UniRx;

using UnityEngine;
using Zenject;

public class Score : MonoBehaviour
{
[Inject] protected GameParameter _gameParameter;

private readonly ReactiveProperty<int> _score = new ReactiveProperty<int>(0);
private const int MaxScore = 999999;

public void Add(int value)
{
_score.Value = value < MaxScore ? _score.Value + value : MaxScore;
}

public void AddPointAccordingTo(int count)
{
if (count == 1)
{
Add(_gameParameter.ScorePoint1);
}
if (count == 2)
{
Add(_gameParameter.ScorePoint2);
}
if (count == 3)
{
Add(_gameParameter.ScorePoint3);
}
if (count == 4)
{
Add(_gameParameter.ScorePoint4);
}
/* ... */
}
}


上記のコードをDictionaryを使ったコードに書き換えます。

SerializedMonoBehaviourを継承するようにすれば良いです。


GameParameter.cs

using UnityEngine;

using System.Collections.Generic;
using Sirenix.OdinInspector;

public class GameParameter : SerializedMonoBehaviour
{
public Dictionary<int, int> ScorePoints;
}



Score.cs

using UniRx;

using UnityEngine;
using Zenject;

public class Score : MonoBehaviour
{
/* 省略 */

public void AddPointAccordingTo(int count)
{
Add(_gameParameter.ScorePoints[count]);
}
}


エディタ上だと下の画像のような形で設定できます。

スクリーンショット 2019-02-09 17.41.38.png


注意

エディタ上で編集可能なフィールドをリネームすると、せっかく設定した値が吹っ飛びます。ディクショナリーなどの複数の値が設定できる場合は、なかなか辛いものがあります。

FormerlySerializedAsアトリビュートを利用することで値は引き継げるので必要に応じて利用しましょう。

Riderのリファクタ→リネームだと自動でFormerlySerializedAsを設定してくれたので、IDEのリファクタ機能を使うのが安全かもしれません。