[Unity][C#] XMLファイルとしてデータを保存する

ゲームで使用しているオブジェクトのデータをファイルに保存する方法のメモ書きです。

ファイルに保存する方法はいろいろありますが、C#に備わっているシリアライズ/デシリアライズの機能を用いると便利です。
.NET FrameworkにてXMLとしてシリアライズ/デシリアライズできるXmlSerializerクラスが用意されています。
今回はこれを用いてゲームデータの保存・読み出しを行ってみたいと思います。

シリアライズ/デシリアライズ

XmlSerializerを用いてシリアライズ/デシリアライズする処理は以下のようになります。

using System.IO;
using System.Xml;
using System.Xml.Serialization;

public class XmlUtil {
    // シリアライズ
    public static T Seialize<T>(string filename, T data) {
        using ( var stream = new FileStream(filename, FileMode.Create) ) {
            var serializer = new XmlSerializer(typeof(T));
            serializer.Serialize(stream, data);
        }

        return data;
    }

    // デシリアライズ
    public static T Deserialize<T>(string filename) {
        using ( var stream = new FileStream(filename, FileMode.Open) ) {
            var serializer = new XmlSerializer(typeof(T));
            return (T)serializer.Deserialize(stream);
        }
    }
}

XmlSerializerはnewでインスタンス化することで使えるようになります。

var serializer = new XmlSerializer(typeof(T));

XMLへのシリアライズはXmlSerializer.Serialize()により行います。

serializer.Serialize(stream, data);

第1引数にシリアライズされたXMLデータを出力するストリーム、第2引数にシリアライズするデータを指定します。
ここで、dataのデータ型はシリアライズ可能な型でなければなりません。
構造体やArray、Listなどはシリアライズできますが、Dictionaryはシリアライズできません。

デシリアライズはXmlSerializer.Deserialize()により行います。

(T)serializer.Deserialize(stream);

引数にはシリアライズされたXMLデータを受け取るストリームを指定します。
このメソッドを実行するとデシリアライズされたデータが返却されます。

使ってみる

実際にXMLにゲームデータを保存してみましょう。
構造体変数のデータをシリアライズ/デシリアライズする処理は以下のようになります。

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

public class SerializeTest : MonoBehaviour {
    // テスト用のシリアライズデータフォーマット
    [System.Serializable]
    public struct TestData {
        public string playerName;
        public Vector3 playerPos;
        public Vector3[] shotPos;
        public List<Vector3> enemyPos;
    };

    public TestData testData;           // シリアライズ/デシリアライズするデータ
    private string serializeDataPath;   // シリアライズされるファイル名

    // テストデータ初期化
    void Start() {
        serializeDataPath = Application.dataPath + "/SerializeData.xml";

        // 適当なデータを作成
        testData = new TestData() {
            playerName = "Player1",
            playerPos = new Vector3(Random.value, Random.value, Random.value),
            shotPos = new Vector3[] {
                new Vector3(Random.value, Random.value, Random.value),
                new Vector3(Random.value, Random.value, Random.value),
                new Vector3(Random.value, Random.value, Random.value),
            },
            enemyPos = new List<Vector3>() {
                new Vector3(Random.value, Random.value, Random.value),
                new Vector3(Random.value, Random.value, Random.value),
            },
        };
    }

    // シリアライズ・デシリアライズ
    void Update() {
        if ( Input.GetKeyDown(KeyCode.S) ) {
            XmlUtil.Seialize<TestData>(serializeDataPath, testData);
        }
        if ( Input.GetKeyDown(KeyCode.D) ) {
            testData = XmlUtil.Deserialize<TestData>(serializeDataPath);
        }
    }
}

Sキーでシリアライズ、Dキーでデシリアライズします。
シリアライズしたデータを開いてみると、以下のようにきちんとXML形式でデータが保存されていることが確認できます。

<?xml version="1.0" encoding="shift_jis"?>
<TestData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <playerName>Player1</playerName>
  <playerPos>
    <x>0.658014953</x>
    <y>0.884079933</y>
    <z>0.8437089</z>
  </playerPos>
  <shotPos>
    <Vector3>
      <x>0.542741358</x>
      <y>0.171121612</y>
      <z>0.112001911</z>
    </Vector3>
    <Vector3>
      <x>0.215804726</x>
      <y>0.168900743</y>
      <z>0.9638424</z>
    </Vector3>
    <Vector3>
      <x>0.9928707</x>
      <y>0.004624248</y>
      <z>0.009210945</z>
    </Vector3>
  </shotPos>
  <enemyPos>
    <Vector3>
      <x>0.660212934</x>
      <y>0.682383239</y>
      <z>0.561078</z>
    </Vector3>
    <Vector3>
      <x>0.820451</x>
      <y>0.0625197962</y>
      <z>0.9366993</z>
    </Vector3>
  </enemyPos>
</TestData>

あらゆる型の変数に対応しているため、簡単なファイル保存用途にはこの方法で十分対応できるでしょう。