Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 [Tutorial] 2D Tile based games
Index -> Programming, Turing -> Turing Tutorials
Goto page 1, 2  Next
View previous topic Printable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
CodeMonkey2000




PostPosted: Wed Jun 13, 2007 4:13 pm   Post subject: [Tutorial] 2D Tile based games

2D Tile Based Games




Before going into the tutorial, you will need to be fairly experienced with arrays (2d, flexible etc), function and procedures.

How tile based games work

Basically you have a text map saved in grid format. E.g. like:
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1

Imagine that the screen is broken into blocks, 7 across and 3 down. Now imagine that each number in the text map represents a 10x10 tile/block on the screen. 1 means red tiles and 0 means black tiles. The position of the numbers is important, as that is going to be where the tiles are drawn. The top row in the text grid represents the top row which will be drawn on our screen (in this case the entire top row will be red, since the entire top row is 1). In the text map if I asked you what is at grid (1,3 ) you would say 1. So a red tile needs to be draw at grid 1,3 on our runtime screen. In short, the text map above should translate on screen into: *removed*


Creating and drawing a map.

First off let’s assume that our map is going to be 15 by 15 tiles. So our text file will have 15 numbers going across and 15 numbers going down. Now, let’s assume that each tile takes up 10 by 10 pixels. The number 1 still represents red tiles and the number 0 still represents black tiles. Here is a text file I made, save it as map.txt on your desktop:

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 1 1 1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1 1 1 1 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Now we need a 2d array which will store the numbers from the text file. The array size should be as follows: 0..14, 0..14. You will see why I started the array at 0 rather than 1 when we draw the map. We want the way we call our array to be the same as how we call a coordinate in the text grid (for collision purposes). Array (0,0) will store the number at the bottom left corner, array (0,1) will store the number right above it, array(1,1) will store the number which is to the right of the previous number, array (14,14) is the top right tile (which will be a red tile)…etc. So if I look at array (10,1) I am looking at a black tile. Now we need a way of storing the number from our text file into our array. Well, first we will need to open the text file. The way we get the information is simple: for every y and for every x in the array get the number. Drawing the map will have a similar for structure; for every y and for every x in the array, if the number is 1 draw a red box at x*10,y*10 (since each tile is 10 by 10 as stated above) or else draw a black box x*10,y*10 (We started the array at 0 because 1*10 is 10, so the whole map would be off 10 pixels). Here is some code which will draw our map (save this to where you save the text file above):
Turing:
View.Set ("graphics:150;150")
var tiles : array 0 .. 14, 0 .. 14 of int

var FileName : string := "map.txt"
var FileNo : int

open : FileNo, FileName, get
for y : 0 .. 14 % for every y
    for x : 0 .. 14 %for every x
        get : FileNo, tiles (x, y) %get the tile type at (x,y)
    end for
end for
close (FileNo)

for x : 0 .. 14
    for y : 0 .. 14
        if tiles (x, y) = 1 then
            Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, red) % the +10 is there because each tile is 10 by 10
        else
            Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, black)
        end if
        locate (5, 1)
        put x, ' ', y .. % the current tile we are drawing
        delay (150)
        %that just shows you what's going on if you still aren't sure
    end for
end for


If you are observant you will notice that the displayed map is upside down. Why? Well when turing reads from a file, it starts at the top line and goes to the bottom. When we read our file we assume that the first line is the bottom and goes up. We should be starting our y at the top and work our way down. So we should be doing this:
Turing:
View.Set ("graphics:150;150")
var tiles : array 0 .. 14, 0 .. 14 of int

var FileName : string := "map.txt"
var FileNo : int

open : FileNo, FileName, get
for decreasing y : 14 .. 0 % we start off from the top and go to the bottom
    for x : 0 .. 14 %for every x
        get : FileNo, tiles (x, y) %get the tile type at (x,y)
    end for
end for
close (FileNo)

for x : 0 .. 14
    for y : 0 .. 14
        if tiles (x, y) = 1 then
            Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, red) % the +10 is there because each tile is 10 by 10
        else
            Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, black)
        end if
        locate (5, 1)
        put x, ' ', y .. % the current tile we are drawing
        delay (150)
        %that just shows you what's going on if you still aren't sure
    end for
end for



Collision detection.
Finally we are into collision! First off, let’s make a moveable piece (which will be our player) and make a redraw procedure:
Turing:
View.Set ("graphics:150;150,offscreenonly")
var tiles : array 0 .. 14, 0 .. 14 of int

var FileName : string := "map.txt"
var FileNo : int

open : FileNo, FileName, get
for decreasing y : 14 .. 0 % for every y
    for x : 0 .. 14 %for every x
        get : FileNo, tiles (x, y) %get the tile type at (x,y)
    end for
end for
close (FileNo)
procedure reDraw
    for x : 0 .. 14
        for y : 0 .. 14
            if tiles (x, y) = 1 then
                Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, red) % the +10 is there because each tile is 10 by 10
            else
                Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, black)
            end if
        end for
    end for
end reDraw

var key : array char of boolean
var px, py : int := 1 % we start off at grid 1,1.
%Note we don't begin at 2,2 because we set the first grid
%to 0,0 so everything is off by 1

loop
    reDraw
    Input.KeyDown (key)
    if key ('a') then
        px -= 1
    end if
    if key ('d') then
        px += 1
    end if
    if key ('s') then
        py -= 1
    end if
    if key ('w') then
        py += 1
    end if

    Draw.FillBox (px * 10, py * 10, px * 10 + 10, py * 10 + 10, yellow)
    View.Update
    delay (50)
end loop



Collision is very easy. All we need to do is check weather or not the tile in front of us is open or not. Let all the black tiles be walk able, and red tiles are walls. So if the tile in front of the player is 1 (a red tile) we shouldn’t be able to move there. How are we going to do that? Well if ‘w’ is pressed check the tile above the player. If Array(px,py+1) = 0 then we can move. Now just do it for all keys. We get the code:
Turing:
View.Set ("graphics:150;150,offscreenonly")
var tiles : array 0 .. 14, 0 .. 14 of int

var FileName : string := "map.txt"
var FileNo : int

open : FileNo, FileName, get
for decreasing y : 14 .. 0 % for every y
    for x : 0 .. 14 %for every x
        get : FileNo, tiles (x, y) %get the tile type at (x,y)
    end for
end for
close (FileNo)
procedure reDraw
    for x : 0 .. 14
        for y : 0 .. 14
            if tiles (x, y) = 1 then
                Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, red) % the +10 is there because each tile is 10 by 10
            else
                Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, black)
            end if
        end for
    end for
end reDraw

var key : array char of boolean
var px, py : int := 1 % we start off at grid 1,1

loop
    reDraw
    Input.KeyDown (key)
    if key ('a') and tiles (px - 1, py) = 0 then
        px -= 1
    end if
    if key ('d') and tiles (px + 1, py) = 0 then
        px += 1
    end if
    if key ('s') and tiles (px, py - 1) = 0 then
        py -= 1
    end if
    if key ('w') and tiles (px, py + 1) = 0 then
        py += 1
    end if

    Draw.FillBox (px * 10, py * 10, px * 10 + 10, py * 10 + 10, yellow)
    View.Update
    delay (50)
end loop


Whoa that was easy!!! And the beauty is that we can make the map larger, and all we need to change in the main program is the size of the array, and how many x’s and y’s there are (i.e. in the for loops in which we read the text file and in the for loops in which we re draw the map). But we have one small problem, this method assumes we go 10 pixels each step (ie. 1 tile a step). What if I want to go less pixels each steps so I get a smoother game play? Well I’ll cover that in the lesson after the next Very Happy

Next: Making a map editor and introducing a new method of detecting which tile you are in.
Sponsor
Sponsor
Sponsor
sponsor
LaZ3R




PostPosted: Wed Jun 13, 2007 4:53 pm   Post subject: Re: [Tutorial] 2D Tile based games

Excellent Tutorial. Simple to understand (If you understand arrays already that is Smile ).

I haven't bothered trying to make a 2D Tile based game but I guess that's one of the small amount of games I can still try to make. I'm working on a slime soccer game in turing (Circular hit detection is what I'm into now Very Happy).

Good job on this turotial. Smile
SNIPERDUDE




PostPosted: Thu Jun 14, 2007 9:11 am   Post subject: Re: [Tutorial] 2D Tile based games

Yes, it was a great tutorial - simple and easy to understand. I have done 2D mapping games before (although with more advanced collision detection), but now I am into 2D isometric mapping. I have most of it working, I just want to remove some of the lag and fix some other problems (knowing which tile the mouse is on and placing objects accordingly). I hope to get enough of it working soon so I can post some of it Very Happy .
DifinityRJ




PostPosted: Thu Jun 14, 2007 9:41 am   Post subject: Re: [Tutorial] 2D Tile based games

Awesome Tutorial, thanks codemonkey! Very Happy
CodeMonkey2000




PostPosted: Thu Jun 14, 2007 7:37 pm   Post subject: RE:[Tutorial] 2D Tile based games

Thanks for the comments. I'm glad everyone found it easy to understand. I hope I didn't sound too redundant though... Anyway I plan to add more after exams.
Dan




PostPosted: Thu Jun 14, 2007 7:58 pm   Post subject: RE:[Tutorial] 2D Tile based games

Not a bad tutorial at all. This is a simple version of how alot of old 2d rpgs where made.

There is alot that could be added on to this idea like how to add more propterys to a title, and making it so the world (titles move) rather then the char, so you get scorling type effect and do not have to reload the map so much. You could also add more info on how to load the titles from a image rather then just boxs.

Overall tho it is a very good intro to the tile system, and is alot clearer then the current posts we have on it.

+ 100 bits
Computer Science Canada Help with programming in C, C++, Java, PHP, Ruby, Turing, VB and more!
CodeMonkey2000




PostPosted: Mon Jul 02, 2007 2:54 pm   Post subject: Re: [Tutorial] 2D Tile based games

Changing the map size without hassle.

The current way of drawing our map isn’t flexible. We can’t make the map bigger or smaller without changing the code. One possible solution to this is to use a 2 dimensional flexible array. The problem is that turing doesn’t support 2d flexible arrays. Now what? Well we could store all the information from a 2d array into a single dimensional flexible array, after all a 2d array is just another way of organizing information. (Note that the size of the array must be totalX’s times totallY’s. So if our grid was 15 by 15, our array should have 225 elements. We also we need to know the totalX’s and totallY’s beforehand). For simplicities sake, the way we will read our text file exactly how we did before, only instead of doing
code:
get : FileNo, tiles(x,y)
we will do
code:
get : FileNo, tiles( Array(x,y) )
. Where array is a function that takes in x and y (which would normally be used in a 2d array) and converts it into the single dimensional equivalent. How do we do that? There are two formulas we can use. They are: TotalX *currentY+currentX or TotalY *currentX+currentY. Both are practically identical.

In our text file we need to include the totalX’s and totalY’s, so it should be:
15
15
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 1 1 1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1 1 1 1 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Next we need to enclose the subscripts for the 2d array with Array(), and change the values in our for loop structure. Here’s what our new code looks like:
Turing:
View.Set ("graphics:150;150,offscreenonly")
var tiles : flexible array 0 .. 0 of int

var FileName : string := "map.txt"
var FileNo : int

var totalX, totalY : int := 0

fcn Array (x, y : int) : int
    result totalX * y + x     %totalY * x + y also works
end Array
%open the file
open : FileNo, FileName, get
get : FileNo, totalX %how many X's
get : FileNo, totalY %how many Y's
new tiles, totalX * totalY - 1 %total number of elements
%the -1 is there because we started the aray at 0
for decreasing y : totalY - 1 .. 0 % for every y remember we started the array at 0!
    for x : 0 .. totalX - 1 %for every x
        get : FileNo, tiles (Array (x, y)) %get the tile type at (x,y) and store it in it's 1d counter-part
    end for
end for

close (FileNo)

procedure reDraw
    for x : 0 .. totalX - 1
        for y : 0 .. totalY - 1
            %array is a function and px-1,py are the parameters
            if tiles (Array (x, y)) = 1 then
                Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, red) % the +10 is there because each tile is 10 by 10
            else
                Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, black)
            end if
        end for
    end for
end reDraw

var key : array char of boolean
var px, py : int := 1 % we start off at grid 1,1

loop
    reDraw
    Input.KeyDown (key)
    %array is a function and px-1,py are the parameters
    if key ('a') and tiles (Array (px - 1, py)) = 0 then
        px -= 1
    end if
    if key ('d') and tiles (Array (px + 1, py)) = 0 then
        px += 1
    end if
    if key ('s') and tiles (Array (px, py - 1)) = 0 then
        py -= 1
    end if
    if key ('w') and tiles (Array (px, py + 1)) = 0 then
        py += 1
    end if

    Draw.FillBox (px * 10, py * 10, px * 10 + 10, py * 10 + 10, yellow)
    View.Update
    delay (50)
end loop

Scrolling.

Yeah we are in to scrolling! There are many methods of doing this, but the one I’m going to look at is the simplest one. Save this map as map.txt:
30
30
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1
1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Let’s set the boundaries of where we should scroll. If the player’s x is more than (or less than) maxx div 2 move the map left/right depending on the direction. Similarly if the player’s y is more than (or less than) maxy div 2 move the map up/down depending on the direction the player is moving. Let’s make 2 counters that keep track of how much the map has moved (x and y displacements). This number will increase/decrease (depending on the direction that the has player moved in) and will be added to the x and y’s of both the player and tiles when we draw them. Code:

Turing:

View.Set ("graphics:150;150,offscreenonly")
var tiles : flexible array 0 .. 0 of int

var FileName : string := "map.txt"
var FileNo : int

var displacementX, displacementY : int := 0
var totalX, totalY : int := 0

fcn Array (x, y : int) : int
    result totalX * y + x     %totalY * x + y also works
end Array
%open the file
open : FileNo, FileName, get
get : FileNo, totalX %how many X's
get : FileNo, totalY %how many Y's
new tiles, totalX * totalY - 1 %total number of elements
%the -1 is there because we started the aray at 0
for decreasing y : totalY - 1 .. 0 % for every y remember we started the array at 0!
    for x : 0 .. totalX - 1 %for every x
        get : FileNo, tiles (Array (x, y)) %get the tile type at (x,y) and store it in it's 1d counter-part
    end for
end for

close (FileNo)

procedure reDraw
    for x : 0 .. totalX - 1
        for y : 0 .. totalY - 1
            %array is a function and px-1,py are the parameters
            if tiles (Array (x, y)) = 1 then
                Draw.FillBox (x * 10 + displacementX, y * 10 + displacementY,
                    x * 10 + 10 + displacementX, y * 10 + 10 + displacementY, red)
                % the +10 is there because each tile is 10 by 10
            else
                Draw.FillBox (x * 10 + displacementX, y * 10 + displacementY, x * 10 + 10 + displacementX, y * 10 + 10 + displacementY, black)
            end if
        end for
    end for
end reDraw

var key : array char of boolean
var px, py : int := 1 % we start off at grid 1,1

loop
    reDraw
    Input.KeyDown (key)
    %array is a function and px-1,py are the parameters
    if key ('a') and tiles (Array (px - 1, py)) = 0 then
        px -= 1
        %notice how this if is within the if that checks weather or not the player has collided?
        %this is convenient since the map should move only if the player moved.
        if px * 10 + displacementX <= maxx div 2 then
            displacementX += 10
        end if
    end if
    if key ('d') and tiles (Array (px + 1, py)) = 0 then
        px += 1
        if px * 10 + displacementX >= maxx div 2 then
            displacementX -= 10
        end if
    end if
    if key ('s') and tiles (Array (px, py - 1)) = 0 then
        py -= 1
        if py * 10 + displacementY <= maxy div 2 then
            displacementY += 10
        end if
    end if
    if key ('w') and tiles (Array (px, py + 1)) = 0 then
        py += 1
        if py * 10 + displacementY >= maxy div 2 then
            displacementY -= 10
        end if
    end if

    Draw.FillBox (px * 10 + displacementX, py * 10 + displacementY, px * 10 + 10 + displacementX, py * 10 + 10 + displacementY, yellow)
    View.Update
    delay (50)
end loop


This works great, but the map should snap back to the screen when it goes off screen. What we want to happen is:

If the displacementX plus the location (relative to our screen) of the very last X tile is less than maxx then the displacementX should equal maxx - totalX * 10.
Or else if the displacementX plus the location (relative to our screen) of the very first X tile is more than 0 then the displacementX should equal 0 - 0 *10.

And we repeat the same thing for displacementY. Code:
Turing:

View.Set ("graphics:150;150,offscreenonly")
var tiles : flexible array 0 .. 0 of int

var FileName : string := "map.txt"
var FileNo : int

var displacementX, displacementY : int := 0
var totalX, totalY : int := 0

fcn Array (x, y : int) : int
    %make sure that going offscreen won't crash the game
    if x >= 0 and x < totalX and y >= 0 and y < totalY then
        result totalX * y + x %totalY * x + y also works
    else
        for k : 0 .. upper (tiles)
            if tiles (k) = 1 then
                result k
            end if
        end for
    end if
end Array
%open the file
open : FileNo, FileName, get
get : FileNo, totalX %how many X's
get : FileNo, totalY %how many Y's
new tiles, totalX * totalY - 1 %total number of elements
%the -1 is there because we started the aray at 0
for decreasing y : totalY - 1 .. 0 % for every y remember we started the array at 0!
    for x : 0 .. totalX - 1 %for every x
        get : FileNo, tiles (Array (x, y)) %get the tile type at (x,y) and store it in it's 1d counter-part
    end for
end for

close (FileNo)

procedure reDraw
    for x : 0 .. totalX - 1
        for y : 0 .. totalY - 1
            %array is a function and px-1,py are the parameters
            if tiles (Array (x, y)) = 1 then
                Draw.FillBox (x * 10 + displacementX, y * 10 + displacementY,
                    x * 10 + 10 + displacementX, y * 10 + 10 + displacementY, red)
                % the +10 is there because each tile is 10 by 10
            else
                Draw.FillBox (x * 10 + displacementX, y * 10 + displacementY, x * 10 + 10 + displacementX, y * 10 + 10 + displacementY, black)
            end if
        end for
    end for
end reDraw

var key : array char of boolean
var px, py : int := 1 % we start off at grid 1,1

proc snapGrid
    %if the grid is too far left
    if (displacementX + totalX * 10) < maxx then
        displacementX := maxx - totalX * 10 %we use 10 because that is the size of each tile
        %if the grid is too far right
    elsif (displacementX + 0 * 10) > 0 then
        displacementX := 0 - 0 * 10 %or just zero
    end if
    %if the map is too far down, move it up
    if (displacementY + totalY * 10) < maxy then
        displacementY := maxy - totalY * 10
        % if the map is too far up move it down
    elsif (displacementY + 0 * 10) > 0 then
        displacementY := 0 - 0 * 10 %or just zero
    end if
end snapGrid

loop
    reDraw
    Input.KeyDown (key)
    %array is a function and px-1,py are the parameters
    if key ('a') and tiles (Array (px - 1, py)) = 0 then
        px -= 1
        %notice how this if is within the if that checks weather or not the player has collided?
        %this is convenient since the map should move only if the player moved.
        if px * 10 + displacementX <= maxx div 2 then
            displacementX += 10
        end if
    end if
    if key ('d') and tiles (Array (px + 1, py)) = 0 then
        px += 1
        if px * 10 + displacementX >= maxx div 2 then
            displacementX -= 10
        end if
    end if
    if key ('s') and tiles (Array (px, py - 1)) = 0 then
        py -= 1
        if py * 10 + displacementY <= maxy div 2 then
            displacementY += 10
        end if
    end if
    if key ('w') and tiles (Array (px, py + 1)) = 0 then
        py += 1
        if py * 10 + displacementY >= maxy div 2 then
            displacementY -= 10
        end if
    end if
    snapGrid
    Draw.FillBox (px * 10 + displacementX, py * 10 + displacementY, px * 10 + 10 + displacementX, py * 10 + 10 + displacementY, yellow)
    View.Update
    delay (50)
end loop


Editing a map.
To edit a map we could change the text in the text map. But that is too tedious. Why not make program that can enable us to edit the map with ease? First we should give the user choice to create a new map, or to load an old one. If the user chooses to start a new map we should ask for the dimensions of the map and then set all the tiles to 0 (so we don’t get any “variable has to value error”). If they choose to load, we should load the map how we normally do. We can copy and paste a bunch of things from the main game onto our map editor (eg. The redraw procedure).
Now if the user left clicks we should place a red tile in the tile the mouse is on (tiles in Array(mouseX, mouseY) now equals 1). If the user right clicks place a black tile in the tile the mouse is on on (tiles in Array(mouseX, mouseY) now equals 0). We can figure out what tile the mouse is on with the formula: mx div sizeOfTile (which is 10), my div sizeOfTile (which is 10). This method of detecting what tile we are on can be used for collision. It is very accurate but it can be slow. There is a trick to using it though. (Note: if we know what tile we are on, but want to find out its position on screen we do: x*10 and y*10). Moving along, if the user presses ‘q’ we should quit and save. The format to save is exactly the same as how we load, but we replace get with put. Code [Note: I added the ability to tell weather or not the mouse is within the grid. Don’t let it confuse you.]:

Turing:

var tiles : flexible array 0 .. 0 of int

var answer : string
var totalX, totalY : int
var FileName : string := "map.txt"
var FileNo : int

fcn Array (x, y : int) : int
    result totalX * y + x     %totalY * x + y also works
end Array

put "Would you like to load or create a new map? (load/new)"
get answer

if answer = "new" then
    put "How many tiles across and down?"
    get totalX, totalY
    new tiles, totalX * totalY - 1 %total number of elements
    for x : 0 .. totalX * totalY - 1
        tiles (x) := 0
    end for
elsif answer = "load" then
    %open the file
    open : FileNo, FileName, get
    get : FileNo, totalX %how many X's
    get : FileNo, totalY %how many Y's
    new tiles, totalX * totalY - 1 %total number of elements
    %the -1 is there because we started the aray at 0
    for decreasing y : totalY - 1 .. 0 % for every y remember we started the array at 0!
        for x : 0 .. totalX - 1 %for every x
            get : FileNo, tiles (Array (x, y)) %get the tile type at (x,y) and store it in it's 1d counter-part
        end for
    end for
    close (FileNo)
else
    put "Invalid input, now crashing"
    delay (1000)
    quit
end if

procedure reDraw
    for x : 0 .. totalX - 1
        for y : 0 .. totalY - 1
            %array is a function and px-1,py are the parameters
            if tiles (Array (x, y)) = 1 then
                Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, red)
                % the +10 is there because each tile is 10 by 10
            else
                Draw.FillBox (x * 10, y * 10, x * 10 + 10, y * 10 + 10, black)
            end if
        end for
    end for
end reDraw

Mouse.ButtonChoose ("multibutton")%check the turing help section if you don't know what this does
cls
var mx, my, mb, left, middle, right : int
var key : array char of boolean

View.Set ("offscreenonly")
loop
    Mouse.Where (mx, my, mb)
    %how this work can be found in the turing help section under 'Mouse.ButtonChoose'
    left := mb mod 10
    middle := (mb - left) mod 100
    right := mb - middle - left
    %move the map around
    Input.KeyDown (key)
    reDraw
    %make sure that the mouse is within the grid
    %remember mx div 10,my div 10 tells us what grid we are on
    % the lower bound of the grid is 0 and the upper bound is totalX/Y
    if mx div 10 >= 0 and mx div 10 < totalX and my div 10 >= 0 and my div 10 < totalY then
        %places red tiles
        if left = 1 then
            tiles (Array (mx div 10, my div 10)) := 1
        end if
        %places black tiles
        if right = 100 then
            tiles (Array (mx div 10, my div 10)) := 0
        end if
        %just makes it clearer which tile you are on
        Draw.Box (mx div 10 * 10, my div 10 * 10, mx div 10 * 10 + 10, my div 10 * 10 + 10, white)
    end if
    View.Update
    exit when key ('q')
end loop

open : FileNo, FileName, put
put : FileNo, totalX     %how many X's
put : FileNo, totalY     %how many Y's
%new tiles, totalX * totalY - 1     %total number of elements
%the -1 is there because we started the aray at 0
for decreasing y : totalY - 1 .. 0     % for every y remember we started the array at 0!
    for x : 0 .. totalX - 1     %for every x
        put : FileNo, tiles (Array (x, y))     %get the tile type at (x,y) and store it in it's 1d counter-part
    end for
end for
close (FileNo)


Now we can just start playing in the new map right away, and not worry about changing the main code.

If you open the text file you will see that you now have a number per line. We don’t need to worry about organizing the text file any more.

Next: I will show you how to add property to tiles, how to only draw the tiles that are on screen, change tiles during game play, how to use pictures rather than the Draw.Box procedure, and finally add enemies. I will probably use pacman as an example as it’s the simplest to understand.
skaarj




PostPosted: Sun Jul 08, 2007 10:00 am   Post subject: Re: [Tutorial] 2D Tile based games

Hi,

I'm writing a RPG game (C++/OpenGL/OpenAL) and this map editor would be very useful, can i find binary for this tutorial? somewhere.
Sponsor
Sponsor
Sponsor
sponsor
CodeMonkey2000




PostPosted: Sun Jul 08, 2007 10:36 am   Post subject: RE:[Tutorial] 2D Tile based games

You can't find binaries for turing. If you understand the logic you probably could program your own map editor.

Oh and how experienced are you with openGL? If you are new, then SDL is probably a better alternative. It's simple (hence the name Simple Direct-Media Layer). I found openGl to be very confusing and frustrating.
skaarj




PostPosted: Sun Jul 08, 2007 11:19 am   Post subject: Re: [Tutorial] 2D Tile based games

Im not new in OpenGL, just look at this:

http://img412.imageshack.us/my.php?image=screenav2.png

I'll try to write map editor.
Sandwich




PostPosted: Mon Jun 16, 2008 9:30 pm   Post subject: Re: [Tutorial] 2D Tile based games

Thank you very much for this tutorial.
Aziz




PostPosted: Tue Jun 17, 2008 7:43 am   Post subject: RE:[Tutorial] 2D Tile based games

CodeMonkey, I suggest you pic a better image host next time. I didn't know that map would translate into jailbait.
CodeMonkey2000




PostPosted: Tue Jun 17, 2008 11:02 pm   Post subject: RE:[Tutorial] 2D Tile based games

Wow I just noticed that.
evildaddy911




PostPosted: Fri Jan 06, 2012 3:52 pm   Post subject: Re: [Tutorial] 2D Tile based games

it doesnt seem to be working for me, it highlights "get" and says "invalid integer input"... whats wrong?

Turing:
var rural, town : array 0 .. 39, 0 .. 29 of int
var rfile, tfile, mfile : int
var rname, tname, mname : string
rname := "rural.txt"
tname := "town.txt"
mname := "map.txt"
open : rfile, rname, get
for decreasing y : 29 - 1 .. 0
    for x : 0 .. 39 - 1
        get : rfile, rural (x, y)
    end for
end for
close (rfile)
mirhagk




PostPosted: Fri Jan 06, 2012 3:56 pm   Post subject: RE:[Tutorial] 2D Tile based games

whatever it's getting isn't a integer (or possibly it's too large) it means your file is formatted incorrectly.
Display posts from previous:   
   Index -> Programming, Turing -> Turing Tutorials
View previous topic Tell A FriendPrintable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 2  [ 21 Posts ]
Goto page 1, 2  Next
Jump to:   


Style:  
Search: