ゲーム製作で躓く点はいくつかあると思いますが、セーブ・ロードの実装もその一つではないでしょうか?アクションならステージのクリア状態、キャラクターの状態等、セーブに必要なデータは限られるかと思いますが、拙作の様なSLGでは多岐にわたります。例えばマップのあらゆるデータ、乗客の動き、車両や関連事業の売上等々。アクションでどこでもセーブ機能を実装する事に近いかと思います。今回は、そういったセーブロードの実装を何とかしようと思います。
で、具体的に何が問題かと言うとオブジェクト設計なプログラミングにおいて「どのようにカプセル化されたメンバ変数にアクセスするのか」と言うことに尽きると思います。また、オブジェクトそのものの数も変わるなら、ロード時にそれを再現してやらなければなりません。
そこで、GoFのMementoパターンを使います。他のサイトでも扱われてますが、ここではもう少し実践的なMementoを作りましょう。MementoパターンはOriginator(ゲームクラス等)から、データを内包したMementoというオブジェクトを生成します。Mementoを取得した側(Caretaker)は中身を触る必要がないようにします。またOriginaterにそのMementoを返せば、元の状態に復元できるという仕組みです。
このMementoは(1)一定の大きさのバッファを生成し、(2)そのバッファへ相互コピーが出来る、ようにすれば汎用的なものが作れそうです。
但し、これは1オブジェクトに対してのみで、そのオブジェクトがプライベートなメンバとしてオブジェクトを持つような状態になっていれば、やはりそのメンバにアクセスできない事に違いはありません。

そこで、Memento自身にMementoを持たせるようにしましょう。Memento生成メソッドで下位のオブジェクトのMementoを取得すれば良いわけです。

こうすれば一番大元のオブジェクトからMementoを1回取得すれば全て済みます。 なにやらゴチャゴチャと子Mementoがついてるかもしれませんが、Caretakerはそれを気にする必要が有りません。
あとは、大元のMementoでどうやってシリアライズするか、つまりHDDに保存しやすいように1つの連続したバッファにデータをコピーし尚且つ元の構造に復元するのか、という問題が有ります。
これは各MementoがそのMemento自身のバッファのサイズ、及びそのMemento以下子Mementoを含めたサイズを保持すれば可能です。
バッファ構造のイメージ

ロード時におけるバッファ解析のイメージ

以下はそのシリアライズ・復元のコードです。
int CMementoTree::get_serialized(void *buffer)
{
int tsize,size;
int offset=0;
int i;
tsize = get_treesize(); //自身のバッファサイズ+子Mementoのサイズ+8byteを取得
set_treesize(buff,tsize); //然る領域に保存
size = get_size_with_header();
memcpy(buffer,buff,(size_t)size);
offset += size;
for(i=0;iget_serialized(&((char*)buffer)[offset]);
offset += mements[i]->get_treesize();
}
return 0;
}
int CMementoTree::set_serialized(void *buffer)
{
CMementoTree *m;
int tsize,size;
int offset=0;
int i;
size = get_size(buffer)+MEMENTOTREE_HEADER_SIZE;
tsize = get_treesize(buffer);
create_buffer(size);
memcpy(buff,buffer,size);
offset += size;
while(offset<tsize)
{
m = new CMementoTree();
m->set_serialized(&((char*)buffer)[offset]);
offset += m->get_treesize();
mements.push_back(m);
}
return 0;
}
オブジェクト毎に8byteずつ余分に大きくなりますが、HDDが大きくなった現在大した問題とはならないでしょう。
これによってセーブデータのフォーマットに変更があってもオブジェクト単位でフォーマットのバージョンを保持しておけば柔軟且つ細かく対応が出来ます。またクラス単位でのテストが容易になります。
ゲーム製作の一助になれば幸いです。
今回のソースコード及び使用例
mementotree.zip