Creating tile-based terrains (II)

In the previous chapter I explained the basic data definitions needed to create and manage a tile-based terrain; in that instance I used a hex-based terrain to show all the basic process, from defining the necessary entities to assemble the array of tiles with an algorithm. Now I will show the same process, but applied to an isometric square-based terrain. Below you can see a hexagonal tile and a square tile; the first one that I used in the previous tutorial and the one that I will use in this current tutorial. What you have to remember is that no matter what shape a tile presents to our view, it is always enclosed within an invisible rectangular area, which is the area that the computer actually understands and works with.

Tile Hexagonal tile
Tile Isometric square tile or diamond tile

Creating an isometric square-based terrain

In the previous example on how to build a hex-based terrain, I declared two constants that would inform the program about the size of the tiles, taking into account that the size that I would declare on the source code would not be exactly the size of the actual tile 'piece', since tiles are interleaved with each other. A similar thing happens here, but I declared instead four constants. The first two indicate the actual size of the tile and the other two indicate the subtracted size, that overlaps from tile to tile; because of the nature of these symmetric tiles, the reduced dimensions are half the total dimensions. Note that we have to give the tiles even numbers for their dimensions (width and height), so these can be divided in half with integers, ensuring precision and easiness. Avoid decimals whenever possible. Also, in Desert Vixens games, I have set the maps to have the same dimension on each of their four sides, so the maps are always square-shaped; this helps to simplify things.

Public Const HEIGHT_TILES = 36
Public Const WIDTH_TILES = 72
Public Const VERTICAL_TILES = 18
Public Const HORIZONTAL_TILES = 36

Remember how a hex-based terrain was constructed like it were a brickwall; for such reason, we had there even and odd rows of tiles. With square tiles we have no such complication; they are arranged as real floor tiles are. You can see that in the graphic below.

Isometric square tiles

As we did on the previous example, we will start by looking at the diverse variables that will define the map and elements that form part of it (entities), before implementing the algorithm that will construct the map by arranging the tiles. So let us start:

Declaration of the 2D coordinate data type:

Public Type Coordinate
intX As Integer
intY As Integer
End Type

Declaration of the map structure data type:

Public Type Map
bytTilesDimX As Byte
bytTilesDimY As Byte
W_Corner As Coordinate
E_Corner As Coordinate
N_Corner As Coordinate
S_Corner As Coordinate
End Type

The first two variables are intended to store the dimensions of the sides of the map. Though in Desert Vixens games the maps have equal vertical and horizontal sizes, I started declaring these as individuals. The following four variables, that are of the type that I previously defined as coordinate, will store the coordinates of the four corners of the map. Let us continue:

Declaration of the tile data type:

Public Type Tile
bytDefTerrain As Byte
W_Corner As Coordinate
E_Corner As Coordinate
N_Corner As Coordinate
S_Corner As Coordinate
Position As Coordinate
bytNumFrameTerrain As Byte
End Type

In the declaration of a tile entity shown in the previous example, the first variable stores which picture (terrain definition) the tile will display (for example soil, grass, sand, water, etc...). The following four variables will store the coordinates of the four corners of the tile; you can see how the tile is like a map in a much smaller scale. The sixth variable stores the position of the tile in the map, using a coordinate. The seventh variable stores which variation will be applied to the picture of that tile, to avoid an excessive repetitiveness on the tile pictures that form the terrain.

Declaration of the terrain definition data type:

Public Type Terrain_Def
bytId As Byte
bytNumFrames As Byte
Num_Surface As Integer
Num_Surface_Mask As Integer
Pos_Surface As Coordinate
Pos_Surface_Mask As Coordinate
End Type

Terrain definitions are the different types of terrains that maps can have. In this example, you can see that the terrain definition has an Id as the first variable. Then I declared a variable that stores the number of frames (variations) that the corresponding terrain definition has; in the previous example I did not included this variable, since in Combat Dolls games all the terrain definitions have the same number of variations. The third and fourth variables store the number of the graphical surface and surface mask where the program will load the graphics corresponding to a particular terrain definition. And the fifth and sixth variables indicate in which position the graphic corresponding to a particular terrain definition can be found on the graphical surface. If you do not understand what I am talking about, I encourage you to look at this article, in the section dedicated to Bitblt: API Functions For Games.

Declarations for the variables that will store the data of the map, tiles and terrain definitions. Since there is only a map, its data is stored in a simple variable. Tiles are stored in a dynamic array, so we can create maps with different sizes. And finally, terrain definitions are stored in a fixed array, whose number of cells is defined by a constant that stores the number of terrain definitions that we will use in our game.

Public The_Map As Map
Public Tiles() As Tile
Public Terrain_Defs(1 To NUM_TERRAIN_DEFS) As Terrain_Def

If you have read my previous tutorial on how to make a hex-based terrain, you will see that the definitions of entities that I made here ressemble a lot the ones that I made there. In general terms, all tile-based maps are conceptually similar. They all are composed of tiles and use 2D coordinates as their reference points. What is different on them is the way the assembling algorithm works, and that is what we will see now.

Now it is time to see the algorithm that creates the diamond-based terrain. We will start by giving the map a certain size:

The_Map.bytTilesDimX = 40
The_Map.bytTilesDimY = 40

In isometric maps, I used always the same size for both dimensions, so I could use just one variable as well...

Then, we have to initialize all the data of the map, terrain definitions and tiles. Firstly, we initialize the values for the western corner of the map, which I will use as the reference point; later I will calculate the coordinates of the other corners of the map by referring to the coordinates of the tiles which lie in those corners. In this example I use these values for that western corner; I use 200 pixels for X to put a margin between the corner and the left screen border and 300 pixels for Y because the program runs in 800 x 600 pixels screen resolution, so the corner will be in the exact mid of screen height. It is just an aesthetical matter...

The_Map.W_Corner.intX = 200
The_Map.W_Corner.intY = 300

Then, we have to load the different terrain definitions that can be used on a map; I am not going to put the code here because it works the same way than in the previous example. It always works the same way; the tiles are graphical elements and the require, to be used, to declare on which surface (graphical context) they are stored - I always use for this purpose indexed picture boxes with the graphics loaded on them - and the coordinates where each individual graphic is to be found on the surface. So the program is aware of each available graphic to be drawn on screen. To see the code, please refer to my previous article: Creating hex-tile based terrains.

Now we continue initializing more variables. The size of the map is calculated by multiplying the lenght in tiles of the map sides, which gives as a result the number of tiles that it has; that is what I call the map size. The array of tiles is then resized to the given number of tiles, and finally, by using a loop that will run that same number of iterations, we initialize to zero all the data contained on the array of tiles.

Dim intMapSize As Integer
intMapSize = CInt(The_Map.bytTilesDimX) * CInt(The_Map.bytTilesDimY)
ReDim Tiles(1 To intMapSize)
Dim i As Integer
For i = 1 To intMapSize
Tiles(i).bytDefTerrain = 0
Tiles(i).bytNumFrameTerrain = 0
Tiles(i).W_Corner.intX = 0
Tiles(i).W_Corner.intY = 0
Tiles(i).N_Corner.intX = 0
Tiles(i).N_Corner.intY = 0
Tiles(i).E_Corner.intX = 0
Tiles(i).E_Corner.intY = 0
Tiles(i).S_Corner.intX = 0
Tiles(i).S_Corner.intY = 0
Tiles(i).Position.intX = 0
Tiles(i).Position.intY = 0
Next i

This article continues in the following link: Creating diamond-tile based terrains.

About Dagovar

~ About Dagovar ~

Defining characters

~ Defining characters ~

Desert Vixens 2 maps

~ Desert Vixens 2 maps ~

Desert Vixens 3 maps

~ Desert Vixens 3 maps ~

Random maps

~ Random maps ~


~ Screenshots ~


~ Algorithms ~

API functions for games

~ API functions for games ~

Source code examples

~ Source code examples ~

<< Return To Index ~ ~ Next Chapter >>

Privacy Policy