----------------------------------- CodeMonkey2000 Wed Jun 13, 2007 4:13 pm [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):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: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: 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: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 :D Next: Making a map editor and introducing a new method of detecting which tile you are in. ----------------------------------- LaZ3R Wed Jun 13, 2007 4:53 pm Re: [Tutorial] 2D Tile based games ----------------------------------- Excellent Tutorial. Simple to understand (If you understand arrays already that is :) ). 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 :D). Good job on this turotial. :) ----------------------------------- SNIPERDUDE Thu Jun 14, 2007 9:11 am 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 :D . ----------------------------------- DifinityRJ Thu Jun 14, 2007 9:41 am Re: [Tutorial] 2D Tile based games ----------------------------------- Awesome Tutorial, thanks codemonkey! :D ----------------------------------- CodeMonkey2000 Thu Jun 14, 2007 7:37 pm 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 Thu Jun 14, 2007 7:58 pm 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 ----------------------------------- CodeMonkey2000 Mon Jul 02, 2007 2:54 pm 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 get : FileNo, tiles(x,y) we will do 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: 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: 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 ('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 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: 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 ('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 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 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 Sun Jul 08, 2007 10:00 am 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. ----------------------------------- CodeMonkey2000 Sun Jul 08, 2007 10:36 am 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 Sun Jul 08, 2007 11:19 am 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 Mon Jun 16, 2008 9:30 pm Re: [Tutorial] 2D Tile based games ----------------------------------- Thank you very much for this tutorial. ----------------------------------- Aziz Tue Jun 17, 2008 7:43 am 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 Tue Jun 17, 2008 11:02 pm RE:[Tutorial] 2D Tile based games ----------------------------------- Wow I just noticed that. ----------------------------------- evildaddy911 Fri Jan 06, 2012 3:52 pm Re: [Tutorial] 2D Tile based games ----------------------------------- it doesnt seem to be working for me, it highlights "get" and says "invalid integer input"... whats wrong? 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 Fri Jan 06, 2012 3:56 pm 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. ----------------------------------- evildaddy911 Fri Jan 06, 2012 4:03 pm Re: [Tutorial] 2D Tile based games ----------------------------------- do i need to put spaces between the tiles? ----------------------------------- mirhagk Fri Jan 06, 2012 4:35 pm RE:[Tutorial] 2D Tile based games ----------------------------------- hit the space bar? You could write a program to do it, but without experience it would take you longer than just doing it manually. ----------------------------------- Dreadnought Fri Jan 06, 2012 9:41 pm Re: [Tutorial] 2D Tile based games ----------------------------------- Alternately you can read in one character at a time and simply convert each one to an integer using ord() - 48 (since ord('0') = 48). It might look something like this. % Read in a wall of single digit integers const CharZero := 48 const ColumnsInFile := 20 const RowsInFile := 10 const FileName := "MyImaginaryFile.omg" var FileNo : int var NextChar : char var MyIntegers : array 1 .. RowsInFile, 1 .. ColumnsInFile of int open : FileNo, FileName, get for row : 1 .. RowsInFile for col : 1 .. ColumnsInFile get : FileNo, NextChar MyIntegers (row, col) := ord (NextChar) - CharZero end for get : FileNo, NextChar % Just to get rid of the newline character end for close : FileNo Note that this does not reverse the rows when writing to the array. Also, if you get weird - integers then you're likely reading in the newline character ('\n' = chr(10)). ----------------------------------- evildaddy911 Sat Jan 07, 2012 10:45 am Re: [Tutorial] 2D Tile based games ----------------------------------- couldn't you just var mapstr: array 1..20,1..20 of string var map: array 1..20,1..20 of int open FileNo, FileName,get for decreasing y:20..1 for x:1..20 get: FileNo, mapstr(x,y)(1) map(x,y):=strint (mapstr(x,y)) end for end for close(FileNo) ----------------------------------- Dreadnought Sat Jan 07, 2012 4:53 pm Re: [Tutorial] 2D Tile based games ----------------------------------- You could, and it essentially no different from the code I posted, except it seems wasteful. You declare 400 strings and use 1 out of the 255 characters for each. Also, you read the next character into a different string each time, but you never use that string anyways. It's the right idea, but you're declaring 101999 characters that you don't need. ----------------------------------- mirhagk Sat Jan 07, 2012 6:26 pm RE:[Tutorial] 2D Tile based games ----------------------------------- How about a comprimise. Read it into a temporary string variable (getting rid of the array of strings) and then use strint.