【OpenSiv3D】OpenSiv3Dで独自で定義したクラスや構造体のシリアライズ・デシリアライズを行う


【はじめに】

Militumです。

今回はOpenSiv3Dを使用して、
独自で定義したクラスのシリアライズ・デシリアライズする方法を紹介したいと思います。

【OpenSiv3Dのバージョン】

Windows Desktop 0.3.1

【サンプルコード】

#include <Siv3D.hpp>

namespace
{
    struct Character
    {
        uint32 id_;    // 識別用ID
        String name_;  // 名前
        int32 hp_;     // 体力
        int32 attack_; // 攻撃力

        template <class Archive>
        void SIV3D_SERIALIZE(Archive& archive)
        {
            archive(
                id_,
                name_,
                hp_,
                attack_
            );
        }
    };
}

void Main()
{
    // バイナリファイルへ書き込み①
    {
        const Character character{ 1000, U"Siv3Dくん", 100, 20 };
        Serializer<BinaryWriter> writer(U"OpenSiv3D-Character.bin");
        writer(character);
        writer.getWriter().close();
    }

    // バイナリファイルへ書き込み②
    {
        const Character character{ 1001, U"Siv3Dくん", 200, 10 };
        Serializer<BinaryWriter> writer(U"OpenSiv3D-Character2.bin");
        writer(character.id_);
        writer(character.name_);
        writer(character.hp_);
        writer(character.attack_);
        writer.getWriter().close();
    }

    // バイナリファイルの読み込み①
    {
        Character character;
        Deserializer<BinaryReader> reader(U"OpenSiv3D-Character.bin");
        reader(character);
        reader.getReader().close();

        Print(character.id_);
        Print(character.name_);
        Print(character.hp_);
        Print(character.attack_);
    }

    Print(U"-----"); // 仕切り線

    // バイナリファイルの読み込み② 変数別に格納
    {
        Character character;
        Deserializer<BinaryReader> reader(U"OpenSiv3D-Character2.bin");
        reader(character.id_);
        reader(character.name_);
        reader(character.hp_);
        reader(character.attack_);
        reader.getReader().close();

        Print(character.id_);
        Print(character.name_);
        Print(character.hp_);
        Print(character.attack_);
    }

    // 旧Siv3DのWaitKeyに当たる関数が見当たらなかったので終了イベントを任意のキーに指定
    System::SetExitEvent(WindowEvent::AnyKey);
    while (System::Update())
    {
    }
}

実行結果

補足

独自で定義したクラスのシリアライズ/デシリアライズを行う場合、
サンプルで構造体内に実装した下記の関数が肝となります。
SIV3D_SERIALIZE は、OpenSiv3Dで用意されたマクロで、Serializer経由で呼び出せばシリアライズ、
Deserializer経由で呼び出せばデシリアライズ用の関数として機能します。

template <class Archive>
void SIV3D_SERIALIZE(Archive& archive)
{
    archive(
        id_,
        name_,
        hp_,
        attack_
    );
}

組み合わせられる

サンプルコードでは、構造体のシリアライズ関数を通してシリアライズしたデータ、
個々のパラメータを別々にシリアライズしたデータを書き込む際と読み込む際にペアとしていますが、
これらは組み合わせを変えても問題ありません。(書き込みは①で出力し、読み込みは②を使用するなど)
この挙動は、Windows Desktop 0.3.1時点のOpenSiv3Dの仕様の可能性もあるので、
今後のバージョンでは使えなくなるかもしれません。


次回は、今回紹介した処理を応用しつつ、
規定フォーマットのCSVファイルを使用して、ツールでシリアライズしたデータを出力し、
OpenSiv3Dのアプリケーションでデシリアライズする処理を紹介予定です。

参考