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


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.


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:

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