Tiling in DirectX: Part 1
by Martin Estevao (lpsoftware)

Prerequisites

With a good amount of C/C++ and basic DirectX knowledge, the reader should be able to go through this tutorial and be able to pick up a few things, I hope. I assume that the reader knows enough DirectX to set up DirectDraw and can load a bitmap from a file to an off-screen surface. I will not be describing how to load bitmaps in this article.

Throughout the article, I will be using Windows/DirectX terminology, but for those of you programming for DOS or some other platform, don’t worry; all the methods presented are somewhat portable : )

Note: My code may not be the most bug-free in the world, and my techniques may not be the most efficient, but I’m trying my best. Enjoy!

What the Heck is a Tile?

A tile is a small bitmap that is bit-block-transferred, or "blitted" to a surface along with other tiles of similar or different appearances to form a representation of your game world. "Tiling" saves lots of memory by creating virtual bitmaps, as opposed to using a single bitmap for your game. Nowadays, the common tile size is 32*32 or 16*16 pixels, with maps ranging from a few tiles to a few hundred tiles.

During game initialization or setup, maps are loaded from ASCII text files in a format quite like this, where "1" stands for one particular tile, "2" stands for another, and so on.

Maps can also be declared within the code as char arrays, but it is not really preferred. In the tutorial, I’ll be using this format even though I strongly suggest using file i/o to load maps from separate files.

Many programmers like to represent their tiled worlds with a tile class or struct, which may include flags for various "walkable" properties (solid vs. non-solid for example), extra items to be placed on specific tiles, animated tiles, and multiple tile layers, to name a few. But for our uses, putting the tiles on the screen, a tile class would be over-doing it a little.

We’ll define our tile world like this, a 12 * 12 tile map in a 2D char array.

char map[12][12] = { {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}};

In this format, we can access any tile by map[x_tile][y_tile]. In this example, a tile defined as "2" is a wall, or a solid tile that the game characters cannot cross over. A tile with an ID# of "1" is a walkable area. We can redefine a tile’s ID# by doing map[x_tile][y_tile] = new_id;

Next, we have to create a bitmap that will store each tile’s graphic. You can either create your own tiles, OR you can steal them from your favorite RPG : ) Set it up something like this.

Note: In the tile drawing function, the RECT’s are set up so that this format will work. If you would prefer to set up your tiles in the bitmap differently, set up the RECT’s accordingly.

Finally, we can now create a function to turn that little char array filled with 1’s and 2’s into a graphical, DirectX display. Make sure you have DirectX already set up and running. I will go through each piece of code "NeHe style," since he has inspired me to write a tutorial and because his tutorials are always the easiest to understand.

#define TILE_SIZE 32 #define WORLD_SIZEX 12 #define WORLD_SIZEY 12

Here we defined the tile size as 32*32 pixels, and the world size with 12 tiles high and 12 tiles wide.

void draw_tiles(void) { int tile; int x; int y; RECT tile_src;

tile is going to be used later in determining if the tile map[y][x], for example, has an ID# of 1 or 2 when we go through the loop of the map array. x and y are the two placeholder variables used when looping through the array and drawing the tile at its appropriate location. The RECT tile_src is going to specify which graphic is going to be used at each tile location, pointing at the offscreen surface where the tile graphic is kept.

for (y = 0; y < WORLD_SIZEY; y++) { for (x = 0; x < WORLD_SIZEX; x++) { tile = map[y][x]; // tile now stores the ID of this particular tile

In this piece of code, two "for" loops are established that go through our map array and capture the ID# for each tile, which is stored in tile.

Note: Our function goes through each tile one by one and blits each tile one by one. It is because of page flipping that it seems as if all of them are being blitted at the same time.

tile_src.left = (tile – 1) * TILE_SIZE; tile_src.top = 0; tile_src.right = tile * TILE_SIZE; tiel_src.bottom = TILE_SIZE;

The tile_src RECT is now set up, depending on the tile ID stored in tile for the tile at map[y][x];

BltFast(x * TILE_SIZE, y * TILE_SIZE, lpddsoffscreen, &tile_src, NULL); } } }

Now we blit the tile at the correct screen coordinates, which would be the x and y variable positions * 32 pixels. I used lpddsoffscreen as the name of the DirectX surface where my bitmap is loaded to. Yours might be loaded to a differently named surface.

Conclusion

This is my first article for GameDev.net and I plan to write more on the future. I’ll be happy if this article helps anyone who’s having trouble with these tiling methods or is new to DirectX. If something’s wrong with the article, or you want to say you liked it (or hated it), please email me at lpsoftware@home.com. Also, if the article helped to create a game, please tell me.

The next article

The next article will be building on this one and will possibly include scrolling with bigger worlds, clipping the tiles, collision detection, and animated tiles.

This article is © 2000 Martin Estevao. This article may not be re-printed without the author’s consent.

Discuss this article in the forums


Date this article was posted to GameDev.net: 7/24/2000
(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!