Tile Game File Formats

Author: Amit Patel

Someone asked me about storing variable-sized tiles in a file. The problem is that if you are keeping only part of your map in memory, you have to be able to easily figure out where in the file the tiles you want are. Tiles can be a variable size if you have a linked list of objects on them, instead of limiting a tile to have only one object.

Here is (most of) my reply:

This is a good question. I have not written a tile map game before but I have often thought about how I would do it, and I had decided the best thing would be to organize tiles into NxN “blocks” and then keep a linked list per block of all the objects in that area.

Storing this format in a file, however, becomes complicated, because the blocks have variable size -- if you have more objects, the block is larger.

What I came up with was that there would be TWO files with map data. (Plus one file with indexing data, which I’ll describe later.) One file would contain the fixed array and one file would contain the linked lists. To load a block of tiles, I can easily figure out where in the fixed-array file to go, and I can load the block from there. THEN that block would contain the location in the other file, of where the linked list goes. The way the linked list file would be stored would be similar to how memory allocation (malloc library) works in C/C++. You’d have to keep track of which parts of the file have data and which do not, and when you want to save your linked list, you would find a place in the file that has enough space for the list.

I am not sure if that made sense, so here are some more details:

A block would be a structure:

    Block:
	int object_file_pos;  // where in the linked-list file to go
	int num_objects;      // how many to read from that file

	Tile tiles[64][64];   // all the tiles in this block

The first file (TILE) would be a file of Blocks.

The second file (OBJ) would be a file of Objects that go in linked lists.

The third file (INDEX) would keep track of what’s in the second file. (It’s a bit vector of all empty areas in the OBJ file.)

LOADING:

To load a block, you’d first load the appropriate block from the TILE file. Since all the blocks are the same size, you can figure out where to read.

Now we have a block, which tells us where in the OBJ file to read. We can read num_objects objects from the OBJ file.

SAVING:

To save a block is easy because we know where it goes in the TILE file, but we don’t want to save it yet because object_file_pos and num_objects are going to change.

However, saving the objects may be harder. First we “deallocate” the objects from the OBJ file. Let’s say for example that the bit vector telling us what areas are free looks like this:

	          1         2
	0         0         0   <- position in OBJ file
	-         -         -
	111010011110000001110   <- 1 means there's something there

If object_file_pos is 7 and num_objects is 4, then to “deallocate” the objects, we set those bits to 0:

	          1         2
	0         0         0
	-         -         -
	111010000000000001110
	       ~~~~

Now we need to “allocate” a space in the OBJ file for the new objects. First we count how many things are in the linked list and put that into num_objects. Then we look in the bit vector to find a place where num_objects objects can fit. For example, let’s say that there are now 6 objects. We have to find a place where there are six 0’s in a row. The first place this happens is at position 5, so let’s “allocate” 6 objects at position 5 by changing those 0’s into 1’s:

	          1         2
	0    5    0         0
	-    -    -         -
	111011111110000001110
	     ~~~~~~

Now we can go through the list and save the objects at positions 5, 6, 7, 8, 9, 10 in the OBJ file. When the player saves or quits the game, you can save the bit vector into the INDEX file.

An alternative would be to store objects anywhere there’s space in the OBJ file, without putting them all close to each other. Then you’d be able to fill the ‘0’ at position 3, for example. This approach lets you save space (because the file doesn’t become fragmented) but loading tiles will be slower because the objects won’t be together.

- Amit

Email me , or tweet @redblobgames, or comment: