我正在为我的2D游戏重新创建关卡数据结构。以前我已经为这些级别使用了大型2D字节数组,因此我能够毫无问题地将它们保存在内存中,但现在我正在扩展游戏并且无法将所有数据存储在内存中。所以我重新创建了这样的关卡结构。
单个磁贴的代码:
public class Tile {
public static final int SIZE = 16;
private short id;
private short health;
private boolean solid;
...
}
我没有将所有图块存储到一个单独的数组中,而是将大数组拆分成更小的数组 - 块:
public class Chunk {
public static final int WIDTH = 16;
public static final int HEIGHT = 16;
private Tile[][] tiles;
private int chunkX;
private int chunkY;
...
}
最后我保留了这些块:
public class Map {
public static final int EXTRA_DRAW_WIDTH = 0;
public static final int EXTRA_DRAW_HEIGHT = 0;
private Chunk[][] chunks;
private int width;
private int height;
...
}
我现在面临的问题是,我无法弄清楚如何将这些块正确存储到磁盘上,然后在我遍历关卡时逐个读取它们(我只想加载最近的块游戏实体)。到目前为止,我已经尝试过:
将每个块存储在单独的文件中。然而,对于较大的世界,文件数量变得太大,例如4096(我必须保持小尺寸的块以便尽可能地更新游戏实体)。
将所有块存储到单个文本文件中,但我无法找到如何获取所需特定块的快速方法。
我已查看过Fast-serialization,但无法解决如何仅从文件中读取特定块的问题。使用快速序列化和序列化时,我也遇到了一些内存问题。
理想情况下,我希望将所有块放在一个文件中,以便我可以轻松指定要加载的块。是否有任何图书馆或具体方法可以做到这一点?
答案 0 :(得分:1)
如果您可以确保每个Tile
和每个Chunk
在磁盘上具有相同的尺寸,则可以将Chunk
直接映射到文件中的特定位置。
示例:
SeekableByteChannel channel;
ByteBuffer chunkBuffer;
public void open(Path path) {
channel = Files.newByteChannel(path, EnumSet.of(READ, WRITE, SPARSE)));
chunkBuffer = ByteBuffer.allocate(Chunk.SIZE);
}
public void close() {
channel.close();
chunkBuffer = null;
}
public void write(Chunk chunk) {
int index = chunkIndex(chunk.getX(), chunk.getY());
chunkBuffer.clear();
chunk.saveInto(chunkBuffer);
chunkBuffer.flip();
channel.position(HEADER_SIZE + Chunk.SIZE * index);
channel.write(chunkBuffer);
}
public Chunk read(int x, int y) {
int index = chunkIndex(x, y);
chunkBuffer.clear();
channel.position(HEADER_SIZE + Chunk.SIZE * index);
if (channel.read(chunkBuffer) < 0) {
/* end-of-file or chunk at given index not written yet */
return null;
} else {
chunkBuffer.flip();
return Chunk.loadFrom(chunkBuffer);
}
}
/** compute linar index of chunk at position x/y */
private int chunkIndex(int x, int y) {
return y * MAX_CHUNKS_X + x;
}
保存并加载Chunk
个对象:
public class Chunk {
public static final int WIDTH = 16;
public static final int HEIGHT = 16;
public static final int SIZE = WIDTH * HEIGHT * Tile.SIZE;
private Tile[][] tiles;
public void saveInto(ByteBuffer buf) {
for (int x = 0; x < WIDTH; ++x) {
for (int y = 0; y < HEIGHT; ++y) {
tiles[x][y].saveInto(buf);
}
}
}
public static Chunk loadFrom(ByteBuffer buf) {
Chunk chunk = new Chunk();
for (int x = 0; x < WIDTH; ++x) {
for (int y = 0; y < HEIGHT; ++y) {
tiles[x][y] = Tile.loadFrom(buf);
}
}
}
...
}
保存并加载Tile
个对象:
public class Tile {
public static final int SIZE = 16;
private short id;
private short health;
private boolean solid;
public void saveInto(ByteBuffer buf) {
buf.putShort(id);
buf.putShort(health);
buf.put(solid ? 1 : 0);
...
// make sure to always write the same tile size!
// fill up with placeholder if necessary!
}
public static Tile loadFrom(ByteBuffer buf) {
Tile tile = new Tile();
tile.id = buf.getShort();
tile.health = buf.getShort();
tile.solid = buf.get() == 1;
...
}
}
当然,您可以添加一些范围检查和正确的异常处理!