Post by Linkage on Mar 3, 2007 23:57:10 GMT -5
Here's a tutorial I've written for Tile Maps. I'm not sure if it's of much use to most of the people here, but it's aimed at the people who are new to sprites and stuff.
So, you know how to use sprites, and want to make your own 2D game. But most of the time, such a game will require a level to move around, and you’re not sure how to make it. You COULD make it one big sprite, or heaps of sprites put together, but that’d be annoying, and would probably slow the game down. So what’s a good way to make levels? Tile Maps.
Tile Maps are very similar to sprites, but are generally meant to be bigger and don’t require making a huge sprite. Instead, you take a picture that has multiple segments, referred to as tiles, and take each segment and place them where you want, kind of like a puzzle. This way, we can make a map using as little as 2 tiles.
So how do we make these Tile Maps? This tutorial will show you how, providing sample code and explanations of how it works to give you a good understanding of them. You don’t really need to know too much about Basic4GL to get through this tutorial, but an understanding of the main basic things such as loops, variables etc. Is required.
OK, so here we go. First, we need a picture to use as our tiles. For now, we’ll just use a very simple one, with only 2 tiles. Here it is:
(you’ll need to save this picture into whatever directory you’re running the finished program from, under the filename basictiles)
As you can see, it’s just divided into black and white sections. Seeing as the default background for Basic4GL programs is black, we’re going to use the white area to show where “something” is, and the black area for blank space.
Now, we’re going to write a section of code that we’ll use later on to tell Basic4GL how to distribute the tiles for the Tile Map. For this we use a data table:
If you’ve never seen the data command before, it is basically used to tell Basic4GL that anything after it is going to be read into the program later and used accordingly.
Now, from looking at the data there, we can see the general shape of a room, visualising the 1s as white space and the 0s as black space. It is useful when using data tables for tile maps to keep all the numbers aligned, so it makes it easier to see in the numbers your map. However, when you start using pictures with an amount of tiles that goes into double digits, they may become unaligned and harder to visualise. It’s obviously not very good to restrict the variety of a tile map simply so that you can code it easier, so you’ll have to either put up with it or leave the first 10 spaces blank, so that all of the tiles will have double digits (and if you go into triple digits, well... that’s one big Tile Map!).
Also, you may be wondering why we have the 9 and the 5 up the top. We’re going to use that laster to help tell the program just how much data to read. When making your own tile maps, you'll have to make the first number equal to the amount of columns in your data, and the second equal to the amount of rows.
Now, we have to actually store that data into a variable so that we can use it. For that we have to dim a few variables and go through a certain subroutine:
You’re probably a bit puzzled as to how this works, so I’ll explain it bit by bit.
First, we dim a pointer variable. So far, the best explanation of pointer variables that I have come across is from Davy:
Pointer variables must be dimmed with a & at the start, and the type we are dimming, which is going to have a 2D array of numbers, must have a ()() at the end. The other variables we are dimming are all integer variables.
OK, now to the more confusing bits. First, we use read. Read does more or less what it says- it reads data, starting from the top, and assigns the values it reads to the variables told. So in this case, it first reads the data 9, and assigns it to mapx, and then the 5, and assigns it to mapy. So now mapx = 9 and mapy = 5.
Then, we use alloc. We use this to allocate the values of mapx – 1 and mapy – 1 to the array dimensions of &tiles. So now, &tiles has the dimensions of (8) and (4). This means that it is divided up into 9 sections, each with 9 values (remember, in arrays 0 is included as a usable section).
Now we use two for loops to read the rest of the data. Because when we go through the first loop the first time, it executes all of the second for loop, in which it reads the next piece of data into i, and ends up doing that instruction the amount of times equal to 9 times 5, which equals 45. So that way, we get it to read all of the data we put in. Also in the second for loop is an instruction to make tiles (x)(y) equal the current value of i. So we end up storing all of our data values into tiles, which we will now use to make the actual map appear. So after that code we place this:
And we add some more variables to our dim statement:
And one line of code after that dim statement:
To end up with a working program, which is this:
So, if you run that, you can see the results, but first let me explain how the code we added works:
This area first assigns the variable tilemap the Image Strip of our tile picture, using LoadImageStrip. This loads our image as a texture with tilemap as its handle. Then, we use gosub, which tells the program to skip to another labelled area of the program and run the code from there until it hits a return command, at which point it goes back to where it was. In this case, it sends it to the LoadTiles subroutine, where all the values of &tiles are set. Then, we use NewTileMap to make map a Tile Map, with the tiles in tilemap. SprSetXRepeat and SprSetYRepeat stop the map from being continuously displayed in both X and Y directions. Then we use SprSetTiles to set the map’s tiles to those indicated in &tiles, at which point it displays it.
The goto command we added before just makes the program skip straight to the MakeMap section, so it doesn't try to tun the LoadTiles section first.
So, hopefully this tutorial has given you a good understanding of how to make Tile Maps. If not, let me know and I’ll either try and address your questions personally or edit the tutorial to fit your needs. The most common thing I could think of is that maybe my explanations in some parts were a bit vague/confusing.
I’m also planning on making another one or two tutorials to do with Tile maps, such as collision detection with them.
EDIT: Almost forgot, I need to extend this slightly to explain how to load multiple maps. Not sure when I'll get around to it.
So, you know how to use sprites, and want to make your own 2D game. But most of the time, such a game will require a level to move around, and you’re not sure how to make it. You COULD make it one big sprite, or heaps of sprites put together, but that’d be annoying, and would probably slow the game down. So what’s a good way to make levels? Tile Maps.
Tile Maps are very similar to sprites, but are generally meant to be bigger and don’t require making a huge sprite. Instead, you take a picture that has multiple segments, referred to as tiles, and take each segment and place them where you want, kind of like a puzzle. This way, we can make a map using as little as 2 tiles.
So how do we make these Tile Maps? This tutorial will show you how, providing sample code and explanations of how it works to give you a good understanding of them. You don’t really need to know too much about Basic4GL to get through this tutorial, but an understanding of the main basic things such as loops, variables etc. Is required.
OK, so here we go. First, we need a picture to use as our tiles. For now, we’ll just use a very simple one, with only 2 tiles. Here it is:
(you’ll need to save this picture into whatever directory you’re running the finished program from, under the filename basictiles)
As you can see, it’s just divided into black and white sections. Seeing as the default background for Basic4GL programs is black, we’re going to use the white area to show where “something” is, and the black area for blank space.
Now, we’re going to write a section of code that we’ll use later on to tell Basic4GL how to distribute the tiles for the Tile Map. For this we use a data table:
TileData:
data 9,5
data 1,1,1,1,1,1,1,1,1
data 1,0,0,0,0,0,0,0,1
data 1,0,0,0,0,0,0,0,1
data 1,0,0,0,0,0,0,0,1
data 1,1,1,1,1,1,1,1,1
If you’ve never seen the data command before, it is basically used to tell Basic4GL that anything after it is going to be read into the program later and used accordingly.
Now, from looking at the data there, we can see the general shape of a room, visualising the 1s as white space and the 0s as black space. It is useful when using data tables for tile maps to keep all the numbers aligned, so it makes it easier to see in the numbers your map. However, when you start using pictures with an amount of tiles that goes into double digits, they may become unaligned and harder to visualise. It’s obviously not very good to restrict the variety of a tile map simply so that you can code it easier, so you’ll have to either put up with it or leave the first 10 spaces blank, so that all of the tiles will have double digits (and if you go into triple digits, well... that’s one big Tile Map!).
Also, you may be wondering why we have the 9 and the 5 up the top. We’re going to use that laster to help tell the program just how much data to read. When making your own tile maps, you'll have to make the first number equal to the amount of columns in your data, and the second equal to the amount of rows.
Now, we have to actually store that data into a variable so that we can use it. For that we have to dim a few variables and go through a certain subroutine:
dim &tiles ()(), mapx, mapy, i, x, y
LoadTiles:
read mapx, mapy
alloc tiles, mapx -1, mapy - 1
for y = 0 to mapy - 1
for x = 0 to mapx - 1
read i
tiles (x)(y) = i
next
next
return
You’re probably a bit puzzled as to how this works, so I’ll explain it bit by bit.
First, we dim a pointer variable. So far, the best explanation of pointer variables that I have come across is from Davy:
Basic4gl's memory is allocated on one big array. So, say you dim the variable "X", you are just expanding the size of that big array by one, then the label "X" is replaced with the index into the memory array (assuming "X" is the first variable, it would be 0 or something).
Pointers are able to store that index value, so they essentially "point" to a place in memory... But they aren't stuck there, they can be changed and point to various locations in memory.
Pointers are able to store that index value, so they essentially "point" to a place in memory... But they aren't stuck there, they can be changed and point to various locations in memory.
Pointer variables must be dimmed with a & at the start, and the type we are dimming, which is going to have a 2D array of numbers, must have a ()() at the end. The other variables we are dimming are all integer variables.
OK, now to the more confusing bits. First, we use read. Read does more or less what it says- it reads data, starting from the top, and assigns the values it reads to the variables told. So in this case, it first reads the data 9, and assigns it to mapx, and then the 5, and assigns it to mapy. So now mapx = 9 and mapy = 5.
Then, we use alloc. We use this to allocate the values of mapx – 1 and mapy – 1 to the array dimensions of &tiles. So now, &tiles has the dimensions of (8) and (4). This means that it is divided up into 9 sections, each with 9 values (remember, in arrays 0 is included as a usable section).
Now we use two for loops to read the rest of the data. Because when we go through the first loop the first time, it executes all of the second for loop, in which it reads the next piece of data into i, and ends up doing that instruction the amount of times equal to 9 times 5, which equals 45. So that way, we get it to read all of the data we put in. Also in the second for loop is an instruction to make tiles (x)(y) equal the current value of i. So we end up storing all of our data values into tiles, which we will now use to make the actual map appear. So after that code we place this:
MakeMap:
tilemap = LoadImageStrip("basictiles.gif", 32)
gosub LoadTiles
map = NewTileMap(tilemap)
SprSetYRepeat(false)
SprSetXRepeat(false)
SprSetTiles(tiles)
And we add some more variables to our dim statement:
dim &tiles ()(), mapx, mapy, i, x, y, tilemap(1), map
And one line of code after that dim statement:
goto MakeMap
To end up with a working program, which is this:
TileData:
data 9,5
data 1,1,1,1,1,1,1,1,1
data 1,0,0,0,0,0,0,0,1
data 1,0,0,0,0,0,0,0,1
data 1,0,0,0,0,0,0,0,1
data 1,1,1,1,1,1,1,1,1
dim &tiles ()(), mapx, mapy, i, x, y, tilemap(1), map
goto MakeMap
LoadTiles:
read mapx, mapy
alloc tiles, mapx -1, mapy - 1
for y = 0 to mapy - 1
for x = 0 to mapx - 1
read i
tiles (x)(y) = i
next
next
return
MakeMap:
tilemap = LoadImageStrip("basictiles.gif", 32)
gosub LoadTiles
map = NewTileMap(tilemap)
SprSetYRepeat(false)
SprSetXRepeat(false)
SprSetTiles(tiles)
So, if you run that, you can see the results, but first let me explain how the code we added works:
MakeMap:
tilemap = LoadImageStrip("basictiles.gif", 32)
gosub LoadTiles
map = NewTileMap(tilemap)
SprSetYRepeat(false)
SprSetXRepeat(false)
SprSetTiles(tiles)
This area first assigns the variable tilemap the Image Strip of our tile picture, using LoadImageStrip. This loads our image as a texture with tilemap as its handle. Then, we use gosub, which tells the program to skip to another labelled area of the program and run the code from there until it hits a return command, at which point it goes back to where it was. In this case, it sends it to the LoadTiles subroutine, where all the values of &tiles are set. Then, we use NewTileMap to make map a Tile Map, with the tiles in tilemap. SprSetXRepeat and SprSetYRepeat stop the map from being continuously displayed in both X and Y directions. Then we use SprSetTiles to set the map’s tiles to those indicated in &tiles, at which point it displays it.
The goto command we added before just makes the program skip straight to the MakeMap section, so it doesn't try to tun the LoadTiles section first.
So, hopefully this tutorial has given you a good understanding of how to make Tile Maps. If not, let me know and I’ll either try and address your questions personally or edit the tutorial to fit your needs. The most common thing I could think of is that maybe my explanations in some parts were a bit vague/confusing.
I’m also planning on making another one or two tutorials to do with Tile maps, such as collision detection with them.
EDIT: Almost forgot, I need to extend this slightly to explain how to load multiple maps. Not sure when I'll get around to it.