0

ゲームマップをバイナリ形式でファイルに保存しています。ファイルの一般的な構造は次のとおりです。

  • (4byte) 幅
  • (4byte) 高さ
  • 幅高さ:
    • (1byte) タイル
  • 幅高さ:
    • (4byte) データ

ファイルのサイズを小さくするために、読みたい数値の正確なサイズがわかっているので、すべてを文字で保存することにしました。getByte と makeInt の 2 つの関数を作成しました。

unsigned char getByte(int src, short int c) //get byte number c from src
{
    return ((char*)(&src))[c];
}

int makeInt(char src[4]) //build int from src
{
    int r=0;
    for (int i=3; i>=0; i--)
        r+=(r<<8)+((unsigned char*)(src))[i];
    return r;
} 

マップを保存してロードする方法は次のとおりです。

void Map::save(const char *fname)
{
    ofstream f;
    f.open(fname,fstream::out | fstream::binary);

    for (int i=3; i>=0; i--)
        f.put(getByte(W,i));
    for (int i=3; i>=0; i--)
        f.put(getByte(H,i));

    for (int i=0; i<W; i++)
        for (int j=0; j<H; j++)
            f.put(tiles[i][j]);

    for (int i=0; i<W; i++)
        for (int j=0; j<H; j++)
            for (int k=3; k>=0; k--)
                f.put(getByte(data[i][j],k));

    f.close();
}

void Map::load(const char *fname)
{
    ifstream f;
    f.open(fname,fstream::in | fstream::binary);

    char bytes[4];

    for (int i=3; i>=0; i--)
        f.get(bytes[i]);    
    W=makeInt(bytes);

    for (int i=3; i>=0; i--)
        f.get(bytes[i]);
    H=makeInt(bytes);

    for (int i=0; i<W; i++)
        for (int j=0; j<H; j++)
            f.get(tiles[i][j]);

    for (int i=0; i<W; i++)
        for (int j=0; j<H; j++)
        {
            for (int k=3; k>=0; k--)
                f.get(bytes[k]);
            data[i][j]=makeInt(bytes);
        }

    f.close();
}

タイル (char) は適切に保存およびロードされ、すべて問題ありません。しかし、int はそうではありません。奇妙なバグのため、256 を保存すると 257 が読み込まれます。予想される 512 の代わりに、514 が読み込まれます。汚い方法 (r-=r/256) にしたくありません...兆候、そしてそれがおそらくこれがすべて起こる理由です。符号なしキャストを追加する前は、127 の後は -127、-126、-125 などでした。これが役立つ場合、マップクラスは次のとおりです。

class Map
{
    public:
        int W;
        int H;

        char tiles[MW][MH]; //MW and MH are macros, now they are 64.
        int data[MW][MH];

        void save(const char *fname);
        void load(const char *fname);

    /* moar code */
};

このパターンでマップを生成してテストしました:

for (int i=0; i<64; i++)
    for (int j=0; j<64; j++)
        map.data[i][j]=(i*64+j);
4

2 に答える 2

1

これは正しくありません (関数 makeInt(char[4])):

r+=(r<<8)+((unsigned char*)(src))[i];

あなたがしたいr = r<<8 + ...。そのままでは、値を複数回累積しています。

于 2012-12-23T21:29:45.203 に答える
1

r+=(r<<8)+((unsigned char*)(src))[i];する必要がありますr=(r<<8)+((unsigned char*)(src))[i];

さて、私の一般的な懸念は、あちこちでバイトを節約することについてあまり心配するべきではないということです。本当にスペースを節約したい場合は、ハフマンコーディング、バイトペアなどの適切な圧縮技術を使用してください。

f.write() と f.read() を使用するよりもスペースを節約できますか? - あなたのコードはもっと簡単になると確信しています - そして、1 台のマシンにファイルを保存するつもりがない限り、それらをバイトオーダーが異なる別のファイルを作成し、そこにコードをロードすると、一度に 1 バイトを格納するのに多くの余分な作業が必要になります。私はそれが良い学習運動だと確信していますが。少なくとも一度に 1 つの int を格納する関数を作成すると、コードをクリーンアップするのに大いに役立つでしょう。

于 2012-12-23T21:30:13.143 に答える