ゲーム製作で躓く点はいくつかあると思いますが、セーブ・ロードの実装もその一つではないでしょうか?アクションならステージのクリア状態、キャラクターの状態等、セーブに必要なデータは限られるかと思いますが、拙作の様な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
https://wakelet.com/wake/SQIOpOr2gsc0ewjZk9KHn
https://wakelet.com/wake/VA7TH4OrqH6ta_C7pe3g9
https://wakelet.com/wake/nYQb_Uv7SYVSmLFDcz19i
https://wakelet.com/wake/rAUeh7LmobVEzzyYDDYhm
https://wakelet.com/wake/lSxDjxJ3_gtq4ul-9LlT6
https://wakelet.com/wake/56K2jCrXuS1ZJkt88ki_0
https://wakelet.com/wake/0VzTcJfrcWaMh7kAQreon
https://wakelet.com/wake/7RgrME4IwL5w2EmtZ4n4I
https://wakelet.com/wake/jII1cn_JCPEgPELqQ9oBl
https://wakelet.com/wake/mWlWLq5qEc_YTobXDZo-z
https://wakelet.com/wake/Tiof1kS31mlkXG7ldi8Ze
https://wakelet.com/wake/e4P3ps3WT1STaLS_Y-PYD
https://wakelet.com/wake/b-4FMERuuwb_tgxzLlBH6
https://wakelet.com/wake/FWb8y7lF5Q3Slx3uzbNNL
https://wakelet.com/wake/ZHJDvzcDgVlpa4O9Q1MEn
https://wakelet.com/wake/2gUU_MvCDf6ZQJ69I0TYH
https://wakelet.com/wake/SNhOvzvTaigccvpQsM8Oh
https://wakelet.com/wake/iwsQKxgxFHsmMo1L8ontY
https://wakelet.com/wake/bee3IeB3x1MrfqKCY0zBE
https://wakelet.com/wake/jSQvMxl832RTciZ68uuWd
https://imgur.com/Nct6Tpv
https://imgur.com/KBCLSWX
https://imgur.com/2oX97i4
https://imgur.com/awkngWy
https://imgur.com/hQFaN5z
https://imgur.com/3yYVhuJ
https://imgur.com/sdCMoND
https://imgur.com/7EIZZ0h
https://imgur.com/ktA43ZO
https://imgur.com/HsJbQoZ
https://imgur.com/Awn49En
https://imgur.com/CNVpLXI
https://imgur.com/wyR03hU
https://imgur.com/puzJMcp
https://imgur.com/4Y7h80g
https://imgur.com/AVW2OMC
https://imgur.com/WSoc9wD
https://imgur.com/hea2K6u
https://imgur.com/HJrzfB5
https://imgur.com/yx2fmLt
https://imgur.com/rYRgFdD
https://imgur.com/kkJcENB
https://imgur.com/WWDSELN
https://imgur.com/ejkDqZU
https://imgur.com/fadAaVh
https://imgur.com/MjfUIW6
https://imgur.com/lSW0OP5
https://imgur.com/nRj7Uuw
https://imgur.com/EUSH8Qw
https://imgur.com/JhSRXMq
https://imgur.com/Yh1kbP3
https://imgur.com/JmDe701
https://imgur.com/AEzUS24
https://imgur.com/dgf2DGZ
https://imgur.com/dXFC1WI
https://imgur.com/VyeUbtQ
https://imgur.com/uipGnd2
https://imgur.com/qlMryxD
https://imgur.com/dbPIAPH
https://imgur.com/Hif1ZcM
https://imgur.com/VxRFFi2
https://imgur.com/JaWkgZu
https://imgur.com/uGiSOEy
https://imgur.com/5D7aeHD
https://imgur.com/aWoLahK
https://imgur.com/QkvCBuY
https://imgur.com/Ze7jPSj
https://imgur.com/R0Y5F3x
https://imgur.com/c1p7e0F
https://imgur.com/Nm0JWN4
https://imgur.com/kQQsFfU
https://imgur.com/ZycD24u
https://imgur.com/95gYCok
https://imgur.com/EdChGRi
https://imgur.com/j6yC1YT
https://imgur.com/xo2pFU7
https://imgur.com/sU3vNVt
https://imgur.com/4E5cD84
https://imgur.com/hLRnjlV
https://imgur.com/2fiaVvf
https://imgur.com/SjucI9M
https://imgur.com/JbgWjN2