Tileset file format
Revision 1.0
by Dino M. Gambone

Introduction

If you are reading this article, then you probably know what an isometric tile is. Most isometric games store the tile images in a single bitmap and simply bitblt the tile image from the tile bitmap to the destination surface. There is nothing wrong with this method except that the tile information is fixed. There is very little room for changing tile attributes on the fly. The following article proposes a file, called a tileset, which stores the tile images along with some properties of the tiles. Tilesets make maps more robust since different maps can have different tilesets and be more dynamic than traditional isometric map games.

The Tileset Anatomy

The tileset is broken up into 3 basic sections. These sections are as follows:

  1. Header
    Contains information about the entire tileset itself.

  2. Tile Entry Index Table
    An array that contains the byte location of each tile entry.

  3. Tile Entry List
    An array of all the tiles in the tileset and their images. NOTE: Tile 0 is usually reserved to indicate no tile.

The Tileset Header

Every file, no matter how simplistic or complex, should always have a header section. This is simply just good practice. The tileset file is no exception. The tileset header should contain information about the tileset itself and common information about the tiles in the tileset. Some recommended members of the tileset header are: file version, tileset engine name, tileset codename, and tileset description. These along with some custom header values should be enough to create a stable tileset file.

The Tile Entry Index Table

A tileset should not have the restriction that the tiles in it are stored in sequential order. In fact, to enforce such a rule would be too time consuming and inefficient since tile images can vary in size. It is easier, faster, and more efficient if the tileset had an internal 'table of contents'. That is what the Tile Entry Index Table is for. It is simply an array of unsigned longs which indicate the byte location of the tile in the tileset. A value of0 would indicate that there is no tile for that tile ID. With the Entry Table, one can quickly find the byte index of the image.

The Entry List

The tile entry list is a back-to-back tile entries. These entries do not have to be in sequential order. This is the meat of the tileset. Every entry can be represented by the following struct:
(See the article on Isometric Tiles for info on some of the TILEENTRY members)

struct TSFILEENTRY{
    unsigned char TileID;      //Unique numeric tile ID
    unsigned char TileLength;	 //Length of the tile
    unsigned char TileWidth;   //Width of the tile
    unsigned char TileHeight;  //The 'altitude' of the tile
    char BaseOffset;           //Location of tile base
    unsigned int ImgSize;      //Size of the actual tile image
    char *ImgData;             //An array of byte that is the image
};

Tileset Maintainance

Now that you know how a tileset file is structured, it is important to cover some key issues needed to maintain a tileset.

  • Tile Addition
    Tileset files begin with absolutely no tile data in it. Someone has to add the tile in order for that tile to be in the tileset. It's quite simple to add a tile to a tileset. Since we have a Tile Entry Index Table, there is no need for the tile entries to be in sequential order. To add a tile, first get the size of the tileset file. This will be the start position of the new tile entry. Append the tile entry to the tileset file, since there is not file footer that we will have to worry about, and save that file size we got earlier in the Tile Entry Index Table. Here's some code to do that:

    NOTE: This is pseudo-code.
    
    bool AddTile(unsigned char TileID, TSFILEENTRY *NewEntry){
        //Adds/replaces a tile in the tileset file
        //  TileID    - The unique Tile ID;
        //  NewEntry	- The tile information
        //  Returns True if successful
        unsigned long file_size;
    
        file_size = GetFileSize(hTSFile);
        if(!AppendEntry(NewEntry)) return false;
        if(!SetTileIdx(TileId, file_size)) return false;
    
        return true;
    }
    
    
    This function should be easy enough to understand. First we get the tileset file size and store it in a variable. Then we try and append the new tile entry. If that is successful, we record where the tile entry was added to. That is all there is to it.

  • Tile Deletion
    People are going to add tiles to the tileset and then later change their minds about the tile and want to remove them. The quick and easy to 'remove' a tile from this tileset is to simply set the tile's index in the Entry Index Table to 0. This will fool the tileset engine to believe that there is no tile. The drawback to this is that the tileset will always contain that information, but it would be 'lost' in the tileset. After a few add and deletes, the tileset will begin to grow in size.

  • Tileset Compacting
    Since the tileset will grow with the more add/deletes done, there needs to be a way to clear out all the unused data in the tileset. This is done through a compacting methods. What compact does is it first copies the tileset header to a temporary file. It then walks through the Tile Entry Index Table and copies the tile entries referred to there into the temporary file. Any entrynot referred to in the Tile Entry Index Table will not be copied. The result is a clean tileset where all the tiles have an index.

We got a file... now what?

We got a file... now what? The next logical step is to create the engine that reads and writes to the tileset file and returns the tile attributes on demand. Be sure that your tileset engine is open-ended enough so that you can encapsulate it in game specific map engine. You got the tile image and the tile information. Most people will load the tile images to a single bitmap and remember where the image is located at. I highly recommend this method, but you may have a better way of showing your tiles. From here on... it's up to you! :)

Conclusion

All ideas in this document were developed by me for a particular map engine in mind. I don't claim them to be the greatest and best way of doing things. I offer these article as a means to share ideas with others so that they may develop an even better way of doing things. If you have any questions, feel free to email me at the above email address.

Discuss this article in the forums


Date this article was posted to GameDev.net: 9/16/1999
(Note that this date does not necessarily correspond to the date the article was written)

See Also:
General

© 1999-2011 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
Comments? Questions? Feedback? Click here!