Unity(C#)初心者・入門者向けチュートリアル ひよこのたまご

AndroidやiOS向けアプリを簡単に作れるゲーム開発環境Unity(ユニティ)の使い方を、チュートリアル方式で一緒に学びましょう!

【Unity】ISerializationCallbackReceiverを使いJsonUtilityでDictionaryを実現

Unity 2019.2.0f1 Personal(2019年8月)
UnityのJsonUtilityはほとんどの型をシリアル化できますが、
残念ながらDictionary型は対象外です。
が、ISerializationCallbackReceiverというインターフェイスを使うことで、
Dictionaryを実現することができます。

ISerializationCallbackReceiver

UnityEngine.ISerializationCallbackReceiver - Unity スクリプトリファレンス

ISerializationCallbackReceiverインターフェイスに備わっているメソッドは
OnBeforeSerializeとOnAfterDeserializeです。
OnBeforeSerializeはToJsonでクラスをJsonへシリアル化する前に、
OnAfterDeserializeはFromJsonでJsonをクラスへデシリアライズした後に呼ばれます。
この2つのメソッドを使い、Dictionaryを実現することができます。

今回はDictionaryのkeyにID(1,2,3)、valueにスキル名(fire,thunder,water)
を、Skillクラスで実現します。

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

[Serializable]
public class Skill : ISerializationCallbackReceiver
{
    public List<int> keys = new List<int> {1,2,3};
    public List<string> values = new List<string> {"fire", "thunder", "water"};
    public Dictionary<int, string> skillDictionary = new Dictionary<int, string>();

    public Skill()
    {
        for (int i = 0; i != Math.Min(keys.Count, values.Count); i++)
        {
            skillDictionary.Add(keys[i], values[i]);
        }
    }

    // // ToJsonでクラスデータをJsonに変換する前
    public void OnBeforeSerialize()
    {
        Debug.Log("OnBeforeSerialize");

        keys.Clear();
        values.Clear();

        foreach (var s in skillDictionary)
        {
            keys.Add(s.Key);
            values.Add(s.Value);
        }
    }

    //// FromJsonでクラスデータを読み込んだ後
    public void OnAfterDeserialize()
    {
        Debug.Log("OnAfterDeserialize");

        skillDictionary = new Dictionary<int, string>();

         // Math.Minで最小値を抽出
        for (int i = 0; i != Math.Min(keys.Count, values.Count); i++)
        {
            skillDictionary.Add(keys[i], values[i]);
        }
    }
}

Skill.cs

JsonUtilityの対象なのでクラスに[Serializable]の属性をつけます。
また先に説明したISerializationCallbackReceiverインターフェイスを実装します。

JsonUtilityはList型はシリアライズできるので、
keysとvaluesのList型変数を用意します。
更にskillDictionaryというDictionary型変数を用意します。
こちらはシリアライズ化できません。

OnBeforeSerializeメソッドはJsonUtility.ToJsonが実行される前に呼ばれます。
クラスデータがJsonに変換される前に、skillDictionaryのKeyとValueを
keys, valuesの各List型変数に移します。
これらはToJsonが実行された時にシリアライズされます。

OnAfterDeserializeメソッドはJsonUtility.FromJsonが実行された後に呼ばれます。
実行されるのはJsonデータがクラスデータに戻された後です。
skillDictionaryを初期化し、keys, valuesの各List型変数から値を抽出していきます。
これでデシリアライズ後にDictionary型変数を使用できるようになりました。

実行

それでは実際にDictionary型変数をシリアライズ/デシリアライズしてみます。

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

public class Manager : MonoBehaviour
{

    void Start()
    {
        Skill profile = new Skill();
        var json = JsonUtility.ToJson(profile);
        Debug.Log(json);
        var newProfile = JsonUtility.FromJson<Skill>(json);
        foreach (var p in newProfile.skillDictionary)
        {
            Debug.Log(p.Key +":"+p.Value);
        }
    }
}

Manager.cs

ToJsonでシリアライズし、FromJsonでデシリアライズしているだけです。
f:id:hiyotama:20190830133635p:plain

ToJsonでシリアライズされたDictionaryデータは、
List型変数keys, valuesとして保存されています。

またFromJsonでデシリアライズされた後は
Dictionary型のskillDictionaryとして使用されています。

今回はここまでです、ありがとうございました〜