2015-03-31 90 views
1

我正在爲我的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; 

    ... 
} 

最後其中I保持大塊:

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; 

    ... 
} 

我現在面臨的問題是,我無法弄清楚w將這些塊正確地存儲到磁盤上,然後在遍歷關卡時(我只想將最接近的塊加載到遊戲實體)逐一讀取它們。到目前爲止,我已經嘗試過:

  • 將每個塊存儲在單獨的文件中。然而,對於更大的世界來說,文件數量變得太大了,例如4096(爲了儘可能地更新最少的遊戲實體,我必須保留小尺寸的塊)。

  • 將所有塊存儲到一個單獨的文本文件,但我無法弄清楚如何獲得我需要的特定塊的快速方法。

  • 我已經看過Fast-serialization,但不能解決如何只讀取文件中的特定塊。在使用快速序列化和序列化時,我也遇到了一些內存問題。

理想情況下,我想將所有塊放在單個文件中,以便我可以輕鬆指定要加載哪些塊。有沒有任何圖書館或特定的方法來做到這一點?

回答

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; 
     ... 
    } 
} 

當然,你可能會添加一些範圍檢查和適當的異常處理!

+0

HEADER_SIZE變量是否在一切之前爲地圖添加額外數據?如果我忽略這個變量,一切似乎都可以正常工作,除非文件很大,只保存一個塊就會生成一個1.25KB的文件。也許有一些方法可以將壓縮應用於此? – Edd 2015-04-01 09:16:53

+0

我已經想出了尺寸問題,Tile.SIZE = 16是用於繪製的,我爲Tile類中的每個字節創建了一個不同的變量DATA = 5。雖然對於更多的塊大小仍然相當大,所以我仍然在尋找壓縮方法。 – Edd 2015-04-01 10:28:23

+0

我認爲你應該爲你的遊戲文件添加一個標題,它包含一些元信息,例如版本號,總尺寸(如果尺寸可能不同),總播放時間,當前播放器位置/標題等。 – isnot2bad 2015-04-01 16:50:54