0

我以二进制格式将游戏地图保存到文件中。文件的一般结构是:

  • (4byte) 宽度
  • (4byte) 高度
  • 宽*高:
    • (1byte) 平铺
  • 宽*高:
    • (4byte) 数据

为了减小文件的大小,我决定将所有内容保存在字符中,因为我知道我想要读取的数字的确切大小。我做了 2 个函数,getByte 和 makeInt:

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();
}

瓷砖(字符)保存和加载良好,一切正常。但是 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() 节省了任何空间吗 - 我很确定你的代码会简单得多 - 除非你打算将文件存储在一台机器上,否则将它们发送到另一个具有不同字节顺序的,然后将它们加载到那里的代码中,一次存储一个字节需要做很多额外的工作。虽然我确信这是一个很好的学习练习。至少编写一个函数来一次存储一个 int 可能有助于清理代码。

于 2012-12-23T21:30:13.143 回答