learn

Map Tutorial

By Laval Gagnon (asondsoft@hotmail.com)

Part 1 : Creating a map
Part 2 : Opening a viewport
Part 3 : Scrolling
Part 4 : Using sprites
Part 5 : Using map objects
Part 6 : Collisions with tiles
Part 7 : Conclusion

Code for this tutorial:

Part 1: Creating a map

Welcome to this tutorial!

First of all, you must know there are two ways of doing scrolling in TNT Basic. The first way is the Canvas. This method stores a large image of the entire level in the memory. It takes A LOT of memory and so won't scale to large levels.
The second way is the Map ViewPort. It reads from a map and draws only what is visible. It'll always work, no matter how big the level is and how much memory is left. I will focus on this method, even though it's a bit harder to use.

There are some maths in this code youger people may not understand. Don't loose time on them, just copy them to your code and change the values / variables.

The first thing to do is to build a map. Open any graphic software ( I believe you know how to use it ) and draw tiles, all of them the same size, and then save the file.This picture is an example of a file containing tiles:

Here, blank tiles were left so you can see how the tiles must be arranged. In fact, no matter how you place your tiles, ( in square, horizontally, vertically, in rectangle ) the important thing is that all tiles must be the same size ( but it doesn't have to square ).

Open Hieroglyph and start a new project. Import the picture into the graphics section. You do not need to put it in an image bank.

Go in the map section and click menu Resource - Create new Map. The map is then small, empty and there are no tiles.

Click ( menu Genesis - Set map Tiles ) and enter the ID of the picture reprensenting your tiles. ( the ID found at the left side of the graphics section ) Now the tiles are in the tile window but are not the good size.

Click ( menu Genesis - Set Map Dimensions ). Enter the map width and height, then the size of your tiles and the number of tiles you will be using.

You can now select a tool ( pencil, line, rect ) and draw the tile you last clicked on. You can use the magnifying glass ( click to make bigger, alt-Click to make smaller ). If you do not see the tools, click ( menu Genesis - Show Tools Window ).

Part 2: Opening a viewport

Note: you should already have a map done.
On your TNT project, write the following code near the top of the code section( if it's not already done: )

Graphics mode 640,480 ' You can change the width and height numbers.
Load map 128 ' This line loads the map; replace 128 by the ID of your map.
After these two lines, the computer will be ready to run graphics commands and the map will be ready to be used. Now that the map is ready, we must open a Map Viewport. A viewport, as its name tells you, represents what you can see.
Open map Viewport 1,0,0,0 to 640,480
The first number ( 1 ) is the MapViewPort ID. Warning: any Canvas using ths same ID as the Vieport will be deleted.
The second number ( 0 ) is the layer of the loaded map to use. The rest ( 0,0 to 640,480 ) represents the area you will see through ( it's where the viewport will be located in the screen. ) In this eample, it's a screen-wide.

Now you need a loop:

while not ( mouse button)
  draw frame
...
wend

A while loop is important in most games, because you'll need to change the viewport position more than once. You may already have one in your project.

The draw frame command will display the screen.

So far the project is:

Graphics mode 640,480 ' This tells TNT it'll have to work with graphics. You can change the width and height numbers.
Load map 128 ' This line loads the map; replace 128 by the ID of your map.
Open map Viewport 1,0,0,0 to 640,480

while not (mouse button)
  draw frame
wend

Run the project. You should see the top-left corner of the map.

Part 3: Scrolling

Scrolling is very easy. You use the command set viewport offset ID, x, y . So let's add some lines to our project:
Graphics mode 640,480 ' This tells TNT it'll have to work with graphics. You can change the width and height numbers.
Load map 128 ' This line loads the map; replace 128 by the ID of your map.
Open map Viewport 1,0,0,0 to 640,480


int x=0,y=0

while not (mouse button)
  x=x+2
  y=y+2
  set viewport offset 1, x, y
  draw frame
wend
Run this project. You'll see the map moves to the bottom-right corner. Let's make it a bit better. This example uses the keyboard:
Graphics mode 640,480 ' This tells TNT it'll have to work with graphics. You can change the width and height numbers.
Load map 128 ' This line loads the map; replace 128 by the ID of your map.
Open map Viewport 1,0,0,0 to 640,480


int x=0,y=0

while not (mouse button)
  if right then x=x+2
  if left then x=x-2
  if down then y=y+2
  if up then y=y-2
  set viewport offset 1, x, y
  draw frame
wend
It' now looking pretty good but we still need a lot more. First, if you scroll out of the bounds, you get an alert daying something like " The viewport must be specified so all tiles lie inside " . Let's add some lines right between the 4 ( if.. thens ) and ( set Viewport Offset ):
if x < 0 then x =0
if y < 0 then y = 0
if x > map width()*25-640 then x = map width ()*25-640 ' Change if you use a different viewport size then use a different value
if y > map height()*25-480 then y = map height ()*25-480 ' Change if you use a different viewport size then use a different value
The first 2 lines of this code would mean something like that in English: If the position is before the beginning, then replace it on the beginning.

The other two lines are more difficult. First, you have to know that when you ask TNT to give you information about a map, it'll give you tiles. So, when I write map width() or map height () , TNT returns the map size in TILES, that's why I must multiply by 25 ( my tiles are 25-pixels large ) to get pixel values ( did you know a pixel is the smallest computer measure unity ? ). The -640 and -480 operations are there because the offset is the top-left corner, so as we are searching for the bottom-right corner we add these operations.

So basically, these two lines are the same as the previous two except that we don't know the maximum, as in the first two we knew the minimum was always 0.
In this case, the maximum is the number of tiles * the size of the tiles - the size of the screen.

Hey, now it should look pretty good! But don't forget the most difficult part is still to come.

So far the project is:

Graphics mode 640,480
Load map 128
Open map Viewport 1,0,0,0 to 640,480


int x=0,y=0

while not (mouse button)

  if right then x=x+2
  if left then x=x-2
  if down then y=y+2
  if up then y=y-2

  if x<0 then x = 0
if y<0 then y = 0
if x>map width()*25-640 then x = map width ()*25-640
  if y>map height()*25-480 then y = map height ()*25-480
  set viewport offset 1, x, y

  draw frame
wend

Part 4: Using Sprites

Now that you know how to do scrolling, you may want to add sprites. ( In this part, I will explain according to the fact you know how to use sprites. )

Try adding a still sprite and run the program: ( Now that you have other x and y positions to use, it'd be a good idea to replace x and y by mapX and mapY )

Graphics mode 640,480
Load map 128
Open map Viewport 1,0,0,0 to 640,480
Load images 128

int mapX=0,mapY=0,x=100,y=10

while not (mouse button)

  if right then mapX=mapX+2
  if left then mapX=mapX-2
  if down then mapY=mapY+2
  if up then mapY=mapY-2

  if mapX<0 then mapX = 0
if mapY<0 then mapY = 0
if mapX>map width()*25-640 then mapX = map width ()*25-640
  if mapY>map height()*25-480 then mapY = map height ()*25-480
  sprite 1,x,y,0
  set viewport offset 1, mapX, mapY

  draw frame
wend

You'll soon remark the sprite does not scroll with the viewport.
It's because the x and y values are positioned on screen according to the screen size, not the viewport size.

Try this line:

sprite 1,x-mapX,y-mapY,0
x-mapX and y-mapY could be translated like this: Its X position in screen is a variable ( ranging from 0 to map width()*25 ) - the viewport position. The larger the viewport is, the smaller the x variable must be, that's why it's x-mapX .

If you haven't been long enough at school to understand that, don't worry. Just remember it's
( POSITION - VIEWPORT )

But the most difficult sprite is still not done: the main character. ( the hero ) What is difficult with it is that it must stay in the middle unless you reach the map edge, when it goes closer to the edge. The first step in getting a centered hero is this code ( run it ):

Graphics mode 640,480
Load map 128
Open map Viewport 1,0,0,0 to 640,480
Load images 128

int mapX=0,mapY=0,x=100,y=10,charX=320,charY=240

while not (mouse button)

  if right then mapX=mapX+2
  if left then mapX=mapX-2
  if down then mapY=mapY+2
  if up then mapY=mapY-2

  if mapX<0 then mapX = 0
if mapY<0 then mapY = 0
if mapX>map width()*25-640 then mapX = map width ()*25-640
  if mapY>map height()*25-480 then mapY = map height ()*25-480

  sprite 1,x-mapX,y-mapY,0
  sprite 2,charX,charY,0
  set viewport offset 1, mapX, mapY

  draw frame
wend
In this model, if you reach an edge, the character stays in the middle and cannot go any closer to the map edge. The solution is to have two viewport positions: one, used in set viewport offset , will always stay in bounds. The second, used with sprites, will be allowed to go out of bounds ( it won't cause any error: don't forget it's only a variable )

Look at this code:

Graphics mode 640,480
Load map 128
Open map Viewport 1,0,0,0 to 640,480
Load images 128

int mapX=0,mapY=0,mapXX=0,mapYY=0,x=100,y=10,charX=320,charY=240

while not (mouse button)

  if right then mapXX=mapXX+2
  if left then mapXX=mapXX-2
  if down then mapYY=mapYY+2
  if up then mapYY=mapYY-2

  mapX=mapXX
mapY=mapYY
  if mapX<0 then mapX = 0
if mapY<0 then mapY = 0
if mapX>map width()*25-640 then mapX = map width ()*25-640
  if mapY>map height()*25-480 then mapY = map height ()*25-480

  sprite 1,x-mapX,y-mapY,0
  sprite 2,charX-(mapX-mapXX),charY-(mapY-mapYY),1
  set viewport offset 1, mapX, mapY

  draw frame
wend
It's not so important if you don't really understand the maths. ( As it is really easy to use, TNT has lots of young users who aren't far enough at school to understand everything ).

Part 5: Using map objects

TNT has a very useful map editor. Let's learn how to use it.

It is difficult to describe this tool. You'll need to keep in mind the appearence of the map editor as you read.

First of all, open your map and select the icon with little colored circles in the MODE window ( if it is not visible, click Show Mode Window in the View menu ). Click on the 2-sheet button to create a new object and on the trash to delete it. Each object has an ID, a name and a color. To edit the name or the color, just double-click on it. You can draw objects by clicking on the map. If you want to modify tiles, don't forget to switch back to the tiles editing mode.

Now that you have your objects placed, you'll have to adapt your code so you can use the objects. You'll need to do this:

- Read each object one by one
- Store the X and Y position of the object inside variables
- In the loop, read each object and react a different way for each ID.

Try the following code ( read the comments I wrote in; ) :

Graphics mode 640,480
Load map 128
Open map Viewport 1,0,0,0 to 640,480
Load images 128
int ObjNmb=map Object Count ' Declare the maximum number of sprites in a variable

int mapX=0,mapY=0,mapXX=0,mapYY=0,charX=320,charY=240
int pX[ObjNmb],pY[ObjNmb],n=0,objType
' Declare X[ ] and Y[ ] arrays, each of them the length of ObjNmb.
' The n variable will be used in the for block.
' ObjType will represent the type of the object ( the ID ) ' This means every object will have its own X and Y variable


for n=0 to objTNmb-1 ' This part passes every object and inits the variables pX and pY
pX[n]=map Object X (n)*25 ' *25 because TNT returns tiles values ( ex.: object on tile 3 * 25 = 75 pixels )
pY[n]=map Object Y (n)*25
next n


while not (mouse button)

  if right then mapXX=mapXX+2
  if left then mapXX=mapXX-2
  if down then mapYY=mapYY+2
  if up then mapYY=mapYY-2

  mapX=mapXX
mapY=mapYY
  if mapX <>  if mapY <>  if mapX>map width()*25-640 then mapX = map width ()*25-640
  if mapY>map height()*25-480 then mapY = map height ()*25-480


for n=0 to objNmb-1 ' The for statement will pass each object ( obj 0 to objectNumber )

objtype=map object type (n) 'This line stores the object type in the variable objType

if objType = 0
  'actions objects of type one will execute
  sprite n+2,pX[n]-mapX,pY[n]-mapY,0 'The ID of the sprite must be different for every object, so it's ( n+2 )
end if

if objType = 1
  'actions objects of type one will execute
  sprite n+2,pX[n]-mapX,pY[n]-mapY,1
end if

if objType = 2
  'actions objects of type one will execute
  sprite n+2,pX[n]-mapX,pY[n]-mapY,2
end if

next n

  sprite 1,charX-(mapX-mapXX),charY-(mapY-mapYY),1
  set viewport offset 1, mapX, mapY

  draw frame
wend

The computer executes this:

1- Prepare to receive Graphics
2- Prepare the map
3- Count the number of objects and give a pX and pY variable to each of them
4- For each object, set the variable to the object position in map. ( That is the FOR ... NEXT block! )
5- Run the main loop
6- Do the scrolling verifications
7- For each object, get the object type and do the appropriate actions.
Soon, you'll need to add more variables. Unless it contains temporary informations, each object should have a copy of the variable. Ths syntax is:

int varName[ObjNmb],pY[ObjNmb] ' Write this line AFTER ObjName is declared, or you'll get a "unknown variable ObjName" error.

You can call a variable ilike this when you are in the FOR block:

int varName[n],pY[n]
In the for block n represents the object, so pX[n] means: " Get the pX variable of n ".
If you do not understand the array[ ] notion, it's not so important; just remember how to declare and read it. You'll soon get it.

Now that I showed you the basics, you should be able to start developing your game yourself.

Part 6: Collision with tiles

That part is really easy. Use :
int tile=0 ' declared with other variables
...

tile = map tile ( pX[n] / 25 , pY[n] / 25 , 0) ' The last number is the layer
' placed in the For construct that is in the while section
if tile = 1
 'actions
 print " The object is on tile #1 "
end if
This code works for objects. The main character works this way:
tile = map tile ( (charX+mapXX) /25 , ( charY+mapYY) /25,0 )
There is the complete code of the project:
Graphics mode 640,480
Load map 128
Open map Viewport 1,0,0,0 to 640,480
Load images 128

int objNmb=map object count
int mapX=0,mapY=0,mapXX=0,mapYY=0,charX=320,charY=240
int pX[objNmb],pY[objNmb],n,tile,objType

for n=0 to objNmb-1
pX[n]=map Object X (n)*25
pY[n]=map Object Y (n)*25
next n

while not (mouse button)

'Scrolling ***************************************************************
'move the viewport position ( only the variables representing the viewport )
if right then mapXX=mapXX+10
if left then mapXX=mapXX-10
if down then mapYY=mapYY+10
if up then mapYY=mapYY-10

'set an inbounds value
mapX=mapXX
mapY=mapYY

if mapX <> if mapY <> if mapX>map width()*25-640 then mapX = map width ()*25-640
if mapY>map height()*25-480 then mapY = map height ()*25-480

'Objects***************************************************************

' A code to do for each object
for n=0 to objNmb-1

' Get the object type
objtype=map object type (n)

'React with the object type; here, the reaction is showing a different image
if objType=0
sprite n+2,Px[n]-mapX,Py[n]-mapY,0
end if
if objType=1
sprite n+2,Px[n]-mapX,Py[n]-mapY,1
end if
if objType=2
sprite n+2,Px[n]-mapX,Py[n]-mapY,2
end if

'Get the tile the object is on
tile = map tile ( pX[n] / 25 , pY[n] / 25 , 0)

'React with the tile the object is on ( you do not need to specify an action for each possibility of tile )
if tile = 6 or tile = 7 or tile = 8 or tile = 9
set sprite color n+2,red
else
set sprite color off n+2
end if

next n

'Main character********************************************************

' Get the tile the main character's on
tile = map tile ( (charX+mapXX) /25 , ( charY+mapYY) /25,0 )

' React with the tile the main character's on
if tile = 6 or tile = 7 or tile = 8 or tile = 9
set sprite color 2,red
else
set sprite color off 2
end if


' Show the main character
sprite 2,charX-(mapX-mapXX),charY-(mapY-mapYY),0

' Move the viewport
set viewport offset 1, mapX, mapY

' Draw the image
draw frame

wend
The polygons are also very easy to use. Instead of:
var = map tile ( (charX+mapXX) /25 , ( charY+mapYY) /25,0 ) 'Character
var = map tile ( pX[n] / 25 , pY[n] / 25 , 0) 'Object
it is:
var = in map polygon ( polygonID , (charX+mapXX) /25 , ( charY+mapYY) /25,0 ) 'Character
var = in map polygon ( polygonID, pX[n] / 25 , pY[n] / 25 , 0) 'Object
and ( var ) will become true or false.

You finished this tutorial! You can look at it in the TNT project attached with this tutorial to try and run it.

Part 7: Conclusion

At this point, you know the most important things for a beginner. Don't forget to open the TNT files from this project, the second contains extra code, like how to restrict access to walls using ( map tile ) and how to have a status bar. I hope this tutorial helped you!

Laval Gagnon
22nd February 2003
asondsoft@hotmail.com