Best way to save maps (2D) and how to achieve it

I have been looking around at how people are able to save maps in games and i have came across 3 diffrent ways.

  1. saving each tile as a pixel on a image: this way is basic and easy to do but there are some limitations. 1, filesize can get large if you try and save data in the gray scale value and you can only render a game from x0 - ~ and y0 - ~ and you cant use -1 quadrants, so this wont alow you to make a fully freerome game because 2 up and left will be limited.

2)Hard coding levels: i have found this only works with small puzzle type games and such and has the same flaws as the first type.

  1. lastly, a map file, this would allow you to use things such as (1,-2){} to pull specific quadrates and get information on the tile type, metadata etc.

I am looking to use the 3rd method in a game i am working on but i cant find a good, small libery for saving and loading tiles, dose anyone have any suggestions? and alos allow me to not only save the tile ID but also meta data.

  • John

You could try to generate a xml file, This way you can easily read all the tiles and rebuild it when loading the map.

What would be the best way to format it? and how efficient is it handling a few thousand tiles? or groups of tiles

I would try to only save the absolute minimum, so maybe a tile ID, and an ID of what kind of tile is is.
So lets say stone is ID 3, and the tile’s ID is 127

You would only have to save 3 & 127
than you can calculate it’s position using the tile’s id with the total world width and height.


Map<Point, Tile> tileMap; // example data structure

public void serialize(Map<Point, Tile> map, DataOutputStream out) {
    int numTiles = map.size();
    out.writeInt(numTiles);

    for(Entry<Point, Tile> e : map) {
        out.writeInt(e.getKey().x);
        out.writeInt(e.getKey().y);
        byte[] data = e.getValue().toBytes(); // Tile provides a toBytes method
        out.writeInt(data.length);
        out.write(data, 0, data.length);
    }
    out.close();
}

// alternatively, use Scanner
public Map<Point, Tile> deserialize(DataInputStream in) {
    int numTiles = in.readInt();
    Map<Point, Tile> map = new HashMap<>(numTiles);    

    for (int i = 0; i < numTiles; i++) [
        Point p = new Point(in.readInt(). in.readInt());
        byte[] b = new byte[in.readInt()];
        in.readFully(b, 0, b.length);
        map.put(p, new Tile(b)); // also provides a constructor from byte data
    }
    in.close();
    return map;
}

EDIT: And, since DataInput/OutputStreams wrap around other streams, you could wrap them around DeflaterOutput/Input / GZip Streams and get compression for free!

Alternatively you could use Readers and Writers to output raw String data, one tile per line, etc.
Or use Kryo.