components used: TImage TPaintBox

this tutorial will work with borland kylix

download source code

In this tutorial we'll be making our own tiled map based on three different bitmaps, each square and the same size. The aim of this will be to move around a makeshift grid in a 'Civilisation' kind of way. In the next tutorial we'll proceed to move a character around the map using the mouse to click on a particular tile.

The Creation of the Map
The first thing we need to do is create our three images that we're going to use for the map. In the case of this tutorial I've got each tile 60 * 60 pixels in size, with one image being of trees, one of grass and one of water. You can see these images below with their names that I have given them in our program. Create a TImage for each tile and set the AutoSize to true and Visible to false. As the visible property is set to false it doesn't matter where you place your images on the screen, because the program will be placing them in their tiled locations.

Forest Tile Grass Tile Water Tile

TreeImg

GrassImg

WaterImg

Once you've inserted them, it's time to create the program that'll place the images where we want. To do this we need to use a command called CopyRect. Before we use this though we'll need to set up our array variable. This will be used to lay out our map on the screen. What we do is assign the a number to each of our three images, 0 for the TreeImg, 1 for the GrassImg and 2 for the WaterImg and then lay them out. So say we have a map that is going to be five tiles by five tiles with water round the outside, trees in the middle and grass everywhere else, then we'd have the following:

2

2

2

2

2

2

2

1

1

1

1

2

2

1

0

0

1

2

2

1

1

1

1

2

2

2

2

2

2

2

This would give the following picture on the screen:

Water Tile Water Tile Water Tile Water Tile Water Tile Water Tile
Water Tile Grass Tile Grass Tile Grass Tile Grass Tile Water Tile
Water Tile Grass Tile Forest Tile Forest Tile Grass Tile Water Tile
Water Tile Grass Tile Grass Tile Grass Tile Grass Tile Water Tile
Water Tile Water Tile Water Tile Water Tile Water Tile Water Tile

To represent this in our program we need to imagine this on its side. The following lines placed in the var part of our program will do this.

arr: array[0..5, 0..4] of integer =
((2, 2, 2, 2, 2),
 (2, 1, 1, 1, 2),
 (2, 1, 0, 1, 2),
 (2, 1, 0, 1, 2),
 (2, 1, 1, 1, 2),
 (2, 2, 2, 2, 2));

The line of 2's down the left hand side will actually represent the bottom line of our map when it appears on the screen. If you were to have a bigger or smaller map than this you would adjust the 5 and 4 in the [0..5, 0..4] for the number of tiles you are using minus one. So if you're map was actually 7 * 8 tiles then the line would be [0..6, 0..7]

Of course these lines alone will do nothing, and that's where the CopyRect command is used. Head to the System control tab on your components menu and select the PaintBox component.

Once you've added the component set its Align property to alClient. This will make the PaintBox take up the whole of your form. Now move to the Events tab on the Object Inspector and double click beside the OnPaint line. This will create the code in which we are going to place the next few lines. We want our code to look like that which is show below so enter the relevant lines in the code given.

procedure TForm1.PaintBox1Paint(Sender: TObject);
var
 x: integer;
 y: integer;
begin
 for
x := 0 to 5 do begin
  for
y := 0 to 4 do begin
   case
arr[x, y] of

    0: PaintBox1.Canvas.CopyRect(Rect(x*60, y*60, (x*60)+59,(y*60)+59),TreeImg.Canvas,Rect(0,0,59,59));

    1: PaintBox1.Canvas.CopyRect(Rect(x*60, y*60, (x*60)+59,(y*60)+59),GrassImg.Canvas,Rect(0,0,59,59));

    2: PaintBox1.Canvas.CopyRect(Rect(x*60, y*60, (x*60)+59,(y*60)+59),WaterImg.Canvas,Rect(0,0,59,59));

   end;
  end;
 end;
end;

This code will take a little explaining so bare with me. Obviously at the beginning we're just introducing our two variables, x and y which we use in this procedure. From then on though, things get complicated.

The two lines after begin will tell the program to carry out our procedure the number of times necessary for the map to be tiled correctly by each time entering a number from 0 to 5 for the x coordinate and 0 to 4 for y coordinate. What this means is the first time the program loops, the x will be 0 and the y will be 0, the second time the x will be still 0 but the y will now be 1. When the y coordinate has reached 4 the x coordinate will now go up one and we will again cycle through the y coordinates until every possible coordinate has been catered for. Also note that the numbers 5 and 4 are directly dependent on the numbers 5 and 4 in our array variable, so if you adjust that, remember to adjust this.

The case arr[x,y] of line takes the number from our array variable at each x and y coordinate. So when the x and y coordinates are 0 the number 2 is present which represents the water. Each coordinate is checked and the equivalent picture number placed in the correct place by the CopyRect lines which we come to next. The lines that begin with either 0: , 1: , or 2: give the instructions for each picture. So if the picture that is connected to the current coordinates is 1 then the line with 1: at the beginning will be used instead of the others. So in this case, the GrassImg is being used to be placed at the current coordinates.

We'll take the following line to describe how it works.

1: PaintBox1.Canvas.CopyRect(Rect(x*60,y*60,(x*60)+59, (y*60)+59),GrassImg.Canvas,Rect(0,0,59,59));

The CopyRect will place a rectangle on our PaintBox canvas. All the command needs to draw the rectangle is the coordinates for the top left of the rectangle and the coordinates of the bottom right of the rectangle. So the command PaintBox1.Canvas.CopyRect(Rect(0,0,59,59) would draw a rectange from the coordinates (0,0) to (59,59). Note that we use 59 to represent the edge of our 60 by 60 tile as the distance between 0 and 1 also counts as one pixel.

In the case of our lines in the program our tile is drawn from our current x and y coordinates times sixty to our starting coordinates plus 59, with the last part of our line telling the CopyRect command to use the GrassImg TImage (of coordinates (0,0,59,59) ) to represent that tile. Confused? Don't be. Spend some time changing things around to see what happens and hopefully it'll all slip into place. The diagram below may also help.

Diagram 1 Diagram 2 Diagram 3

In the diagram above, the x and y coordinates are both 0, so the starting coordinates are also 0. The final coordinates are (59,59) because 0 + 59 is 59.

In the diagram above, the x and y coordinates are both 1 so the starting coordinates are (60,60) as 1 * 60 is 60. The final coordinates are (119,119) because 60+59 is 119.

In the diagram above, the x and y coordinates are both 2 so the starting coordinates are (120,120) as 2 * 60 is 120. The final coordinates are (179,179) because 120+59 is 179.

You should now find that if you run the program you will have a map six tiles by five tiles in size which use your three images. Give yourself a pat on the back. It should also be said that if you don't want a gap of one pixel between your tiles (as will most probably be the case), then swap all the 60's in the code for 59's. That way you'll have a seamless join between each tile.

Of course, the tiled map on its own isn't much good, so in the next tutorial we'll look at how to introduce the movement of a player around our map by using a mouse to click on the tile we want it to move into. We'll also look at restricting the movement to a set number of tiles per turn and also how to get the player to recognise whether they are on grass, water or in the forest. In the meantime, play around with what you've learnt in this tutorial. Make the map bigger, add more image tiles. Do whatever takes your fancy really. If you've any questions, then please e-mail me, or leave a message on the board.

download source code

Subscribe to the feed delphigamedev.com NEWS Feed
archived news | mailing list

[ all tutorials found at delphigamedev.com are Copyright © 2008 Ben Watt ]