Home This Article Is Taken From The Game Programming MegaSite, A Definitive Resource For Game Developers!

Tile Based Black Book
By: Dragun

Introduction

In this tutorial, I'll cover how to make a 2D tile scrolling map and your very own map editor. I'll be talking in C but the techniques would work for any type of language. This tutorial is target for DJGPP and the Allegro graphics library but the idea of it is universal.

2D Maps

To start off, I'll talk about 2D "maps" in general. Basically they are a two-demensional array of a structure (could be a regular integer but that's kind of boring and inflexible). The structure would hold the bitmap information, any tile attributes, and any damn thing you could think of. Sort of like this:

(Note that this can be used for a straight up rectangler tile map or a isometric map)


	typedef struct
	{
	   char			bmp_info; 
	   unsigned char	bitflag_1;	/* stuff to tell you if it's a animated tile or not */
	   unsigned char	bitflag_2;	/* other attributes */
	   unsigned char	bitflag_3;	/* other attributes */
	   unsigned char	bitflag_4;	/* other attributes */
	} map_data;

Then you would declare the array like this:


	map_data map[100][100];	/* a map that is 100x100 */

I'll explain why it is in array for those of you who are confused. Skip this part if you want. If you ever played chess, you'll notice the board is a two-demensional array, with squares going up and across both sides of the rectangle. Let's just say that you're on the first square at the top, making your array position map[0][0]. Since you're a damn rook and assuming that the knigh next to ya is dead, you want to move right one tile. Move right and so now your position will be map[0][1]. Wait a minute you might ask. Why increase the number in the right braket instead of the left? Well, since it is faster to blit a ROW of tiles then a COLUMN of tiles on some computers, we'll do it this way. In tile based games, instead of each member of map being a chess board square, it would be a tile of graphics.

Example of a map array

You could make the array three-demensional for multi-layered maps. Why? So the map would look better and have more variety. You could have the first layer for the base tile, which is the ground. The second layer would be for masked tiles, like when the grass fades into dirt. The third layer could be for objects and such. Multi-layered may be slower to draw to the screen but it has more flexibility. You really dont want to draw each damn fade for each tile combination. That's stupid.


	map_data map[3][100][100];	/* a map that is 3x100x100 */

The Buffer and Scrolling

To have smooth scrolling, you got to have a buffer that is somewhat larger than the drawing screen. When I say buffer, I mean an extra slice of video memory to draw on. You got to have some globals to keep trac of what map number you're starting to draw with, a x offset, and a y offset. The x offset is the amount of room that is left on the left side of the screen and the y offset is the room on the top. Lets just say that the screen resolution is 640x480 and you boxed out the last 160 pixels of the screen to make the drawing screen a nice 480x480 square and your tiles are 32x32. To have smooth scrolling you need a buffer of at least 544x544 (which leave room for a 17x17 map of 32x32 tiles). This will leave room for a "scrolling tile" on each side of the buffer.

Some may disagree with the following method but it's the easiest of 'em all. To start the whole process, just make a tile algorithm that blits the array onto the buffer. Of course you got to have global map coordinates counters. I'll call it mapX and mapY. Create a function that takes in these two map coordinate and blit from their. Something like this:


	void DrawMap(int mx, int my)
	{
	   int X = mx, int Y = my;

	   for(int i = 0; i < 544; i += 32)
	   {
	      for(int j = 0; j < 544; j += 32)
    	      {
	      blit(map[y][x].bmp_info, to_screen, (j+x_offset), (i+y_offset));
	      X++;
	      }
	   X = mx;
	   Y++;
	   }
	}

DrawMap(int, int) will take in starting map coordinates and use them to blit a 17x17 tile buffer. The x & y offsets are there to shift the map correctly into place. So, what you're really doing is increasing the x_offset and y_offset everytime you press the appropiate key. To make this accurate everytime, you got to redraw the map and checc the x & y offsets every frame. By checcing the offsets, I mean by if the x or y offset is greater than 32 or less then zero, you have to decrease the map or increse the global map coordinates, respectively.

Confused? I'll explain why. Just say you have a 64x64 picture and have a 80x80 picture. When the 80x80 is centered with the 64x64, the offsets of both x and y are be -8 (extra 8 pixels on all sides; for x axis: 64+(8+8) = 80; for y axis: 64+(8+8) = 80). When you move the 80x80 down 8 and right 8, the y offset that was -8 becomes 0 and the x offset that was -8 also becomes 0. Now you have no more buffer (on the left and top that is, the right and the bottom have offsets of +16 now) and it is time to remake the offsets. Since you moved down and right, the map coordinates have to be subtracted by one. This is because you moved down and right and the buffer that was there is now being shown and a new buffer have to take its place. If the pict is moved up and left, you do exactly the opposite.

Controlling Objects

Controlling objects are simple. All you have to do is make a structure that hold their x & y offsets and the current map coordinates they're on. Something like this:


	typedef struct
	{
	   int MX, MY;
	   int x_offset, y_offset;
	   unsigned char bmp;
	} obj_info;

And to draw it onto the screen all you have to do is calculate the (x, y) position with this:


	x = (((obj_status.MX - mapX) * 32) + obj_status.x_offset);
	y = (((obj_status.MY - mapY) * 32) + obj_status.y_offset);

This would take the object's map coordinate and subtract the current map coordinate away from it and add the offset to it. The x & y offsets are there to shift the object correctly. When moving the object, you do the same thing with it as the map shifting. You would only do the drawing and the calculations of the object if it is in range with the screen (starting map coordinates).

The Level Editor

This is the smartest thing to do: MAKE THE LEVEL EDITOR BEFORE YOU MAKE THE SCROLLING ENGINE. This is the best way cuz when you're making the editor, you're doing the scrolling anyway. And this will also avoid making your first map by filling in an array.

To start this off, level editors are event driven, meaning that every thing you do calls up a function to do that task. So when you init the screen, you have a function that displays the map region and the menu. How do you know what to do? Use the keys or have bitmapped buttons or something. I cant really explain but you gotta see it to believe. The source code to a map editor is at the end of the tutorial (in .zip format).

Download: tbbb.zip (Source & EXE's)



The Game Programming MegaSite - ⌐1996- Matt Reiferson.