Unity

Unityでシリアライズ可能なDateTimeを作ってみた

時間をエディタ上で操作したい、ということはままあると思う。

  • プログラムではDateTimeで扱いたい
  • ただそのままだとDateTimeはシリアライズ出来ないので、文字列で定義してDateTimeへパースする
  • もしくはエディタ拡張で時間操作可能なGUIを表示する、等

ずっとなんかスマートに出来ないかなぁ、と思ってたので、「エディタ上では文字列で操作出来て」「プログラムではDateTimeをそのまま使える」クラスを作ってみた。

SerializableDateTime.cs

using UnityEngine;
using System;
#if UNITY_EDITOR
using UnityEditor;
#endif

[Serializable]
public class SerializableDateTime : ISerializationCallbackReceiver
{
    const string Format = "yyyy-MM-dd HH:mm:ss";

    public DateTime Value;

    [SerializeField] string text;

    public SerializableDateTime() : this(new DateTime()) { }

    public SerializableDateTime(DateTime value)
    {
        Set(value);
    }

    public static implicit operator SerializableDateTime(DateTime value)
    {
        return new SerializableDateTime(value);
    }

    void Set(DateTime value)
    {
        Value = value;
        text  = ToString();
    }

    public void OnAfterDeserialize()
    {
        DateTime newValue;
        if(DateTime.TryParse(text, out newValue))
        {
            Set(newValue);
        }
        else
        {
            Set(Value);
        }
    }

    public void OnBeforeSerialize() { }

    public override string ToString()
    {
        return Value.ToString(Format);
    }
}

#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(SerializableDateTime))]
class SerializableDateTimeDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.PropertyField(position, property.FindPropertyRelative("text"), label);
    }
}
#endif

Test.cs

using UnityEngine;
using System;

public class Test : MonoBehaviour
{
    [SerializeField] SerializableDateTime startTime = new DateTime(2018, 3, 9);
    [SerializeField] SerializableDateTime endTime   = new DateTime(2018, 9, 2);

    void Start()
    {
        DateTime t0 = startTime.Value;
        DateTime t1 = endTime.Value;
    }
}

原理としては、文字列のシリアライズ変数(text)を定義して、エディタ拡張でそれを操作するGUIを表示する。
textの値がエディタ上で変更された場合、クラスのシリアライズ処理が呼ばれるので、そのコールバック内でDateTimeの値を更新する。
ISerializationCallbackReceiver がシリアライズ時に呼ばれるコールバックインターフェイス。

型変換演算子(implicit)を定義してるので、定義時にDateTimeをそのまま使えるようにしてる。
ValueがDateTimeの値。
エディタ上では時間にパース可能な文字列が指定された場合は変更される。
変な文字列を入力した場合は、変更不可能(変更前の値に戻す)。

最後に

全然関係ないけど、最近Go言語を触ってて、これが結構いい感じ♪
GAEとGo言語でアプリのサーバを作ってみようかと考えてるこの頃(´・ω・`)

【エビでもわかる】オセロプログラミング
〜オセロを作りながらゲームのプログラムを学ぼう〜
「Unityで初めてゲームを作ってみたい!」

そんな人のためにこの本を作りました。
オセロを一から作りながら実践形式でプログラムを学べる本です。
すでに完成したプロジェクトを説明するのではなく、実際に作りながら説明していきます。
一緒に手を動かしながら、プログラムを覚えていきましょう🌟