A brief description of tile based algorithms - By Gary Beebe

This tutorial is here to help you make your own Tile Based game using some simple Algorithms.  This tutorial show you both aspects of making an editor and where to display the tile.  There are many styles of games that could come from these algorithms such as side views and top views.  Some parts of this tutorial may be easier to understand.  I will do my best to give you the most flexible code so that you may change it to suite your needs.
 
Basic declarations
 
These are some of the declarations that you may need to get started.  In some cases you may want to keep some of these declarations Private instead of Public.

Public Const Xoff = 6
Public Const Yoff = 6
Public Const TileHeight = 16
Public Const TileWidth = 16

 
The picture above shows you why you may need the Xoff and Yoff variables.  You may have a space between where the top and left of the map start and the actual top and left of the area that the map is in.  The thick black line may be the border of the maps container (ex: Picture1)  and the cyan tiles are your actual map.  The width and height of your tiles are held as TileWidth and TileHeight.  You may need to change these to equal the width and height of your tiles in your set.

Understanding your tile sets

Tile set forms may be different from programmer to programmer.  They may also be different from each game made by the same programmer.  Most often, the tiles in a set will appear side by side and in multiple rows separated only by one row or column of pixels.

The picture above shows what I mean.  The tiles are arranged side by side separated by a column of pixels and are in rows separated by a row of pixels.  Finding the exact Top and Left of a tile can be easy if you know the X and Y (row, column) of that tile or, if need be, a single number representing.

Single and X, Y number tile sets

Suppose, in our tile set, that the first tile is #1 and the second tile is #2 that would make the tile under #1 (the black one) be #5 and the last tile #16.  These are called single number tile sets.  Note:  This is based on a tile set that has 4 columns only.  To be able to use our single number tile set we must first convert it over to an X, Y tile.

An X, Y tile set is one which gives you the number of the tile using it's X and Y position.  For example, the first tile in our tile set is (1, 1), the second is (2, 1), the one under the first one (the black one) is (1, 2) and the last one is (4, 4).

Using an X, Y tile set is easier to work with at design and run times.  Because your tile sets may change in size you would have to rewrite a part of your code to compensate for a change in columns, using a single number tile set.  By using an X, Y tile set you may only have to let the program know the maximum of rows and columns in the set.

Converting from single to X, Y

Even though I don't approve of using single numbered tile sets, I will show you how to work with them since I mentioned them above.

To convert from single to X, Y you first must have a constant holding the number of columns that you have in your tile set.  I recommend using a constant because using an actual number every time you do this may make it difficult to find and change if the time ever comes that you have resized the set.  A constant, on the other hand, can be easy to locate and you'd only have to change it's value.

Again I am using a Public instead of Private declaration.  Also I am using the number 4.  This is the same number of columns that I have in the example above, you will need to change this to the number of columns in your set.  Also, for future purposes, we will make a variable type called XYTile containing the X and Y value.  These should be put in a Module.

Public Const MaxCol = 4

Type XYTileA
   X As Integer
   Y As Integer
End Type

Public XYTile As XYTileA

To do this easily you may want to make a sub.  This will reduce the lines of code that you will have.. 

Public Function GetXandY (SingleNumber as Integer) As XYTileA
   Let GetXandY.X = SingleNumber Mod MaxCol
   Let GetXandY.Y = Fix(SingleNumber / MaxCol) + 1
End Function

This is very simple math once you think about it.  To get the Y you divide the single tile number (SingleNumber) by the maximum number of columns (MaxCol).  We use Fix because we don't want a remainder for the Y and we use + 1 because it considers the first column to be 0 (zero).  To get the X just simply get the remainder of the same product.  Using Mod will give us only the remainder and nothing else.

To use this code just follow the examples below:

Let XYTile = GetXandY (SingleNumber)  Given the single number of the tile XYTile.X and XYTile.Y will become the row and column location of the single number.

With that out of the way, let get down to business...

Finding the top left of a tile in a set

Finding the top and left corner of a tile in a tile set is almost easier than finding the X, Y of a single numbered tile.  In fact, it's quite similar, but very opposite :).  Remember the TileWidth and TileHeight declarations (in Basic declarations)?  This is one place they will come in use.  Also, to do this, we may need a another to work with.  This should be put in a Module as well.  Note:  I am recycling the XYTileA Type in the Converting from single to X, Y section above.

Public CurrentTileInSet as XYTileA

I will stick with the tile set I have above in this code.  They are 16x16.  We will also use a Function to save us some lines of code.

Public Function GetTopLeftOf (X As Integer, Y As Integer) As XYTileA
   Let GetTopLeftOf.Top = X * (TileWidth + 1) - TileWidth
   Let GetTopLeftOf.Left = Y * (TileHeight + 1) - TileHeight
End Function

We add 1 to TileWidth and TileHeight to compensate for the one pixel dividers.  We then multiply X or Y by TileWidth or TileHeight.  Because this will be (1, 1) too many, we subtract TileWidth and TileHeight from the answers.  So, once you have the row and column (X and Y) of the tile, pass it to the function and it will return the Top and Left corner of the tile.  Here is an example of how to use it.

Let CurrentTileInSet = GetTopLeftOf(X, Y)  This will let CurrentTileInSet.Top and CurrentTileInSet.Left equal the right pixel of the Top, Left corner of the X, Y tile.

And for you single number set users who are following closely along...

Let CurrentTileInSet = GetTopLeftOf(XYTile.X, XYTile.Y)

You clicked where?

Suppose, in your editor, you have all of your tile set displayed.  It may be a challenge to find out which tile you or the user wants to draw on the screen, if you are new to programming.  Anyone good at math should be able to figure it out.  But if you lacking in programming experience or math skills it could take a while.  It may seem quite obvious once you figure it out and you may decide to kick yourself in the butt for not doing so sooner.  To save you some time and pain, I will write the code for you.

Supposing that your tile set is contained in a Picture box, you can easily get the X and Y coordinates where the user clicked.  Note: Don't forget to change the ScaleMode to 3 - Pixels.  For our example we will name our Picture box TileSetBox1 and in order to get the X and Y of where the user clicked we will use the MouseUp event.  The code is as follows:

Private Sub TileSetBox1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
   Let XYTile.X = Fix(X / (TileWidth + 1)) + 1
   Let XYTIle.Y = Fix(Y / (Tile.Height + 1)) + 1
End Sub

Again, we are using Fix to ensure that we don't have a remainder, we are adding 1 to TileWidth and TileHeight to compensate for the 1 pixel dividers in our set and, we are adding because Fix usually considers 0 to be the first number.

Note:  The declaration for XYTile appears in the Converting single to X, Y section of this tutorial.

Single number tile set users need to work backwards

If you are using a single number tile set then you need to work backwards to be able to record the data correctly.  What I mean by this is that the section above gives you the information in X and Y format.  You, on the other hand, may be using single numbered tiles.  In this case, just use the following code:

Let SingleNumber = (XYTile.Y -1) * MaxCol + XYTile.X

What this does is figures out the last tile in the row above XYTile.Y by subtracting 1 and multiplying by MaxCol.  Then we move on ahead by adding XYTile.X to get the correct Tile.

Ok, now what?

Now that you have the Top Left corner of the tile, in the set, and all data needed for recording purposes, we can move on and plot our tile.  Remember Xoff and Yoff (in Basic declarations)?  This is where they will come into place.  This can be an easy step, if you know Top and Left corner is of the tile on your map.  But suppose you don't.  This is almost like finding the Top and Left corner of your tile set, except you don't have to compensate for the single pixel dividing the tiles because there aren't any on the map.  We do, however, have to compensate for Xoff and Yoff.

Again in our code we need to have another variable to work with.  This should be put in a Module as well.

Public TileInMap as XYTileA

And our Function should look like this:

Public Function GetTopLeftOfTile (XofTile As Integer, YofTile As Integer) As XYTileA
   Let GetTopLeftOfTile.X = (XofTile * TileWidth) - TileWidth + Xoff
   Let GetTopLeftOfTile.Y = (YofTile * TileHeight) - TileHeight + Yoff
End Function

Note:  In the section below (But, what if I don't know that either?) there is the declaration for XofTile and YofTile

This just simply multiplies the Row (XofTile) by the width of the tiles (TileWidth).  We have to subtract TileWidth also because 1 * 2 = 2.  Also Xoff because the far left of the Map (Where the tiles start may not be at point 0 (zero).  We do this for the column (YofTile) as well.

But, what if I don't know that either?

It's ok, you're in good hands.  So, you need what tile, on the map, you or the user clicked on.  No problem.  This is much like finding out what tile in the tile set was selected, but we don't have to compensate for the one pixel devoured and we have to compensate for the Xoff and Yoff.

First we need our variables.  You should know where to put it by now (in the Module).

Public XofTile as Integer
Public YofTile as Integer

For this example we will be using a picture box named TiledMap1.  Remember to set the ScaleMode to 3-Pixel.

Private Sub TiledMap1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
   Let XofTile = Fix(X / TileWidth) + 1
   Let YofTile = Fix(Y / TileHeight) + 1
End Sub

We figure out what tile the user clicked on by dividing the mouse position (either X or Y) by the size of the tile (either TileWidth or TileHeight).  We then add 1 because Fix starts at 0 (zero).

Well, that's it.  You soon should be on your way to creating a tile set, working on your editor, or plotting the tiles on your map.