ページ 11

セーブ・ロードの方法・・

Posted: 2007年6月28日(木) 18:52
by 黒猫
セーブ・ロードの方法がまったくわかりません。
セーブ・ロードの概念みたいなものを
どなたか教えていただけませんか?

Re:セーブ・ロードの方法・・

Posted: 2007年6月29日(金) 01:08
by 管理人
何のデータをセーブロードするかによると思いますけど、もっとも簡単な方法はテキスト形式でファイル出力、読み込みする方法ではないでしょうか?
例えばRPGのセーブ・ロードだとして書きます。

体力、レベル、現在のエリア番号、現在の座標x、現在の座標y

こんな風にデータの順番を仕様として決めておきます。そして例えば
現在体力が230,レベルが13,エリア番号が3,x=10,y=30だとすると

230,13,3,10,30

こんな風にファイル出力すればいいですよね。
ファイルについてはfopen関数を利用するとよいでしょう。

http://www9.plala.or.jp/sgwr-t/c/sec17.html

ファイルに出力したら、今度は読み込みです。
fgetsなどで、

230,13,3,10,30

のデータを読み込んだら、それぞれの値をゲームのデータとして使ってやればいいわけです。
特にゲームプログラミングに限った業ではなく、普通にCの標準関数を利用して出来ると思いますよ。

Re:セーブ・ロードの方法・・

Posted: 2007年6月29日(金) 02:24
by Justy
>セーブ・ロードの方法がまったくわかりません
 プログラミング用語としてはシリアライズ・デシリアライズと言いますが、
この手の話は結構奥が深いです。

 特にどこまで考慮するのか、によって実装方法や難易度が変わってきます。
 例えば、テキスト形式にするのかバイナリ形式にするのか、
異なるプラットフォームでも読めるようにするのか、
バージョン互換をどこまでとるのか、とか。

 そんな事情もあって、いろんな人たちがいろんな方法を考案しています。


 で、基本的にシリアライズはテキスト形式かバイナリ形式かのどちらかになります。
 それぞれの利点・欠点は以下の通りです。

・ テキストの場合
 テキストエディタで中身を見られる。しかも内容を理解しやすい。
 異なるプラットフォームでも読みやすい。
 データを解釈するのに(文字列から数値への変換などで)若干時間がかかる
 データの改ざんが容易である。

・ バイナリ形式の場合
 中身を見るのにバイナリエディタが必要。
 当然データの改ざんするにもバイナリエディタが必要。
 (普通のバイナリエディタでは 16進数表示なので)intなどの数値はそれなりに判るが、
float/double型はぱっと見てもそれが一体幾つなのか判りづらい。
 異なるプラットフォームでは(エンディアンなどの問題で)そのままでは
正しく読み込めない可能性がある。
 比較的高速に読める。


 状況や工夫次第でそれぞれの利点・欠点は解消・緩和・消失したりするので
必ずしも上の通りにはならないのですが、概ねそんな感じです。


 簡単な例として既に構造体を理解されているようでしたら、バイナリ形式でばっさりと
ファイルに保存してしまうのが簡単で、構造体のメンバが増減しても
(古いデータを読もうとさえしなければ)何もする必要はありません。

[color=#d0d0ff" face="monospace]#include <stdio.h>
#include <string.h>

//  対象のデータ
typedef struct Data
{
    int year;
    int month;
    int day;
    float pi;
    char name[0x10];
} Data;

//  書き込み
static int save_data(const Data *data)
{
    //  書き込み用バイナリファイルとして開く
    FILE *fp;
    if((fp = fopen("serialize.dat", "wb")) == NULL)
        return 0;
    
    //  一気に書き込む
    fwrite((const void *)data, sizeof(Data), 1, fp);
    
    fclose(fp);
    return 1;
}

//  読み込み
static int load_data(Data *data)
{
    //  読み込み用バイナリファイルとして開く
    FILE *fp;
    if((fp = fopen("serialize.dat", "rb")) == NULL)
        return 0;
    
    //  dataの中身を空(0)にしておく
    memset((void *)data, 0, sizeof(Data));
    
    //  一気に読み込む
    fread((void *)data, sizeof(Data), 1, fp);
    
    fclose(fp);
    return 1;
}

//  data1の中身をファイルに書き出し、
//  そのファイルから data2に読み込み
int main(void)
{
    static const Data data1 = { 2007, 6, 29, 3.14159f, "test"};
    Data data2;
    
    //  data1をファイルに書き出す
    if(save_data(&data1))
    {
        //  data2にファイルから読み出す
        if(load_data(&data2))
        {
            //  双方の表示してみる
            printf("data1 = %d/%d/%d (%f) %s\n",
                data1.year, data1.month, data1.day,
                data1.pi, data1.name);
            printf("data2 = %d/%d/%d (%f) %s\n",
                data2.year, data2.month, data2.day,
                data2.pi, data2.name);
        }
    }
    return 0;
}[/color]

Re:セーブ・ロードの方法・・

Posted: 2007年6月29日(金) 21:27
by 黒猫
なるほど・・・。

つまりファイルを出力がセーブの役割をしていて、
出力したファイルを読み込むことがロードの役割をしているのですね!

いままで構造体の使いどころを理解していなかったので(というか使ったことあったっけなぁ・・w)
構造体をより理解できるようにしたいと思います。