Noob in need of tile array help!

BlitzMax Forums/BlitzMax Beginners Area/Noob in need of tile array help!

TomShep(Posted 2011) [#1]
Hi,

I was wondering if someone could take a look at what I have been working on.... (its supposed to be a basic map) I have a couple of issues/questions

a) Is this the best way of doing this sort of tile map

b) If you look at the 1s I would say they should be in a diagonal south east - line. However, there is a sort of larger gap along the x-axis. I wondered whether this was the *50 remark however i tried taking this out but that was obviously wrong.

Graphics 640, 480


Global map[13,10]

#mapoftiles
DefData 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0


Global tile1 = LoadImage("grass.png")
Global tile2 = LoadImage("Path.png")


'MAIN GAME LOOP
While Not KeyHit(KEY_ESCAPE)
Cls
Fdrawtiles()
Flip 
Wend
 
Function Fdrawtiles()
RestoreData mapoftiles 
For y = 0 Until 10
	For x = 0 Until 13
		ReadData map[x,y]
		If map(x,y) = 0 Then 
			DrawImage tile1,x*50,y*50
		ElseIf map(x,y) = 1 Then
			DrawImage tile2,x*50,y*50

		EndIf 

	Next
Next 
 
End Function 




ANY help would be amazing as I dont really know what Im doing lol

Tom


Czar Flavius(Posted 2011) [#2]
I don't know how the defdata stuff works as I personally never use it. But it looks like you are re-reading the data into your map array each time. Try to read the whole map in a loadup function before your main game.

I like to store my data in files. Make a function to output a map array to a file and a function to read it from a file. Write/read two integers for the sizes of the map at the beginning.

Try to use more constants/variables instead of magic numbers. For example, store 10 and 13 in mapsizex and mapsizey variables of some kind. It lets you change the size of your map much easier later on.

Is 50 the size of the image? You should also put this in a variable for changing it later.

Last edited 2011


Jesse(Posted 2011) [#3]
your map is not 13 width it's 17
make your array 17x10 also

Last edited 2011


TomShep(Posted 2011) [#4]
@CZar Thank you I will get those consts/vars in. However iM not exactly sure how to write the map array to file and then to load it again after - Im very new to programming and extremely poor at it. LOL

@Jesse OMG! These silly mistakes I keep making are a pain!! Thank you

Last edited 2011


Jesse(Posted 2011) [#5]
I tried to structure your code so it would be more logical and clear for you to understand:

Strict
Graphics 640, 480

'******************* initialization of variables ***************************
Const MAP_WIDTH:Int = 17
Const MAP_HEIGHT:Int = 10

Const GRASS_TILE:Int = 0
Const PATH_TILE:Int = 1

Global map[MAP_WIDTH,MAP_HEIGHT]

Global tile1:TImage = LoadImage("grass.png")
Global tile2:TImage = LoadImage("Path.png")


'****************** map data 17 x 10 ***************************************

#mapoftiles
DefData 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0


'********************* preload map *************************

LoadMap()

'MAIN GAME LOOP

While Not KeyHit(KEY_ESCAPE)
	Cls
	Fdrawtiles()
	Flip 
Wend

'****************** 'load map function ********************** 
Function LoadMap()
	RestoreData mapoftiles 
	For Local y:Int = 0 Until MAP_HEIGHT
		For Local x:Int = 0 Until MAP_WIDTH
			ReadData map[x,y]
		Next
	Next 	 
End Function 

'***************** display map funciton *********************

Function Fdrawtiles()
	For Local y:Int = 0 Until MAP_HEIGHT
		For Local x:Int = 0 Until MAP_WIDTH
			If map[x,y] = GRASS_TILE Then
				DrawImage tile1,x*50,y*50
			ElseIf map[x,y] = PATH_TILE Then
				DrawImage tile2,x*50,y*50	
			EndIf 
		Next
	Next 	 
End Function 


a few things to suggest as you are a beginner so that you can learn good programming practice and your experience will be more enjoyable:

First and most important use Strict or Superstrict at the beginning of your code. This will make debugging your code 100 easier.

second use indentation when writing your code for functions, loops, ifs, whiles etc. this will make your code easier to read and understand for you and anybody that tries to help you in debugging.

third limit the number of globals you use as much as possible. One of the best ways of avoiding that is by learning to use "Types".

if you get into the habit of doing stuff the right way now you won't have problems in the future developing those habits.

finally if you haven't read any tutorials in the tutorial section here are some good ones that might help you:

http://www.blitzmax.com/Community/posts.php?topic=42519
http://www.blitzmax.com/Community/posts.php?topic=59509
http://www.blitzmax.com/Community/posts.php?topic=59233
http://www.blitzmax.com/Community/posts.php?topic=48800
http://www.blitzmax.com/Community/posts.php?topic=61157
http://www.blitzmax.com/Community/posts.php?topic=42619

Last edited 2011

Last edited 2011


TomShep(Posted 2011) [#6]
WOW Jesse I really appreciate the effort you have gone to for me here, thank you


CS_TBL(Posted 2011) [#7]
If you're really a beginner, there's a risk the following is beyond you.., but alas.. let's mention it anyway! :)

* I could suggest procedural map generation over data statements. I personally find such data statements distracting and hard to manage. Think of (your!) functions like: Mapmake(w,h,clearvalue), Mapline(x,y,angle,length,value) and Maprect(x,y,w,h,value).
* Put your graphics into an array rather than in unique variables, or put 'm all in one image and load it with LoadAnimimage so that you can use the image frame as array position. That way you don't need these endless If map[x,y] = GRASS_TILE checks, you simply draw the image that corresponds to the map value for a given x,y coordinate. No checks, no nothing!
* Even though you may be a beginner, using types would already be rewarding, and you really don't have to go with scary inheriting 'n stuff. Just having a data container with its own methods is already a great way to bring peace to your brain.


CS_TBL(Posted 2011) [#8]
E.g. you could do this:

SuperStrict

Type TTilemap
	'
	' wee example by CS_TBL
	'
	
	Field data:Int[,],mapvalid:int=0,  mapw:Int,maph:Int,  mapx:Int,mapy:Int ' mapdata, size of the map, cameraposition
	Field vieww:Int,viewh:Int ' viewport, the size of the game area
	
	Method Make(w:Int,h:Int)
                mapvalid=0
                If w*h=0 Return
                mapvalid=1
		data=New Int[w,h]
		mapw=w; maph=h
	End Method
	
	Method Viewport(w:Int,h:Int)
		If w*h=0 Return
		vieww=w; viewh=h
	End Method
	
	Method Rect(px:Int,py:Int,w:Int,h:Int,v:Int)
                If not mapvalid Return
		If w*h=0 Return
		For Local x:Int=0 To w-1
			For Local y:Int=0 To h-1
				Setvalue(px+x,py+y,v)
			Next
		Next
	End Method
	
	Method Getvalue:Int(x:Int,y:Int)
                If not mapvalid Return 0
		If x<0 Or x>=mapw Return -1
		If y<0 Or y>=maph Return -1
		Return data[x,y]
	End Method
	
	Method Setvalue(x:Int,y:Int,v:Int)
                If not mapvalid Return
		If x<0 Or x>=mapw Return
		If y<0 Or y>=maph Return
		data[x,y]=v
	End Method
	
	Method Clipcamera()
		If mapx<0 mapx=0
		If mapy<0 mapy=0
		If (vieww+mapx)>mapw mapx=mapw-vieww
		If (viewh+mapy)>maph mapy=maph-viewh
	End Method
	
	Method Debug()
                If not mapvalid Return
		Local s$,v:Int,l$="+"+Replace(LSet("",vieww*2)," ","-")+"+"
		Print l
		For Local y:Int=0 To viewh-1
			s=""
			For Local x:Int=0 To vieww-1
				v=Getvalue(x+mapx,y+mapy)
				If v<0 s:+" " Else s:+Mid(".:x@",v+1,1) ' for this routine, the map has only 4 values: . : x and @, or: 0,1,2,3 in integers
				s:+" "
			Next
			Print "|"+s+"|"
		Next
		Print l
	End Method
End Type

Local map:TTilemap=New TTilemap
map.Make 64,48  ' here we make a map of 64x48 tiles
map.Viewport 32,24 ' the game screen is 32x24

For Local t:Int=0 To 23 ' here we fill it up with some random crap
	map.Rect Rnd(48),Rnd(36),Rnd(16),Rnd(12),1+Rnd(3)
Next
Print "0,0"
map.Debug ' let's see the map at the top left (0,0)

Print "~n -8,-5"
map.mapx=-8;map.mapy=-5 ' move the camera to another location
map.Debug

Print "~n -8,-5, but eventually clipped to 0,0"
map.Clipcamera ' keep the camera inside the map
map.Debug

Print "~n 37,29"
map.mapx=37;map.mapy=29 ' move the camera to another location
map.Debug

Print "~n 37,29, but eventually clipped to mapw-vieww,maph-viewh"
map.Clipcamera ' keep the camera inside the map
map.Debug


Last edited 2011

Last edited 2011

Last edited 2011

Last edited 2011


CS_TBL(Posted 2011) [#9]
One could make whole games using nothing but Print, and add the visuals much later on.. ^^

ps/edit: One could rename mapx and mapy to camerax and cameray... matter of taste, technically it doesn't matter.

Last edited 2011


craigmon(Posted 2011) [#10]
Thanks for posting this code. I've learned a lot and can follow it fairly well. I just need to spend a little more time looking at the debug method's string manipulation routines and I'll have it down

-craigmon


Twinprogrammer(Posted 2011) [#11]
Could one change that sample code to be a scrolling map ??

Twinprogrammer


Midimaster(Posted 2011) [#12]
I know it is called "moving map", but...

"It is never the map, that is moving, but always the 'camera'!"

So it you want to see a scrolling part of the map, just move the 'camera' position the the right and substract it frmo the drawing position.

Here is a stand alone (very reduced) basic sample:
Graphics 400,400

Repeat
	CamX=CamX+1
	Cls
	SetColor 1,99,1
	For I=0 To 30
		DrawRect (i*30)-CamX+1,101,29,29
	Next
	Flip 1
Forever


Now you could combine this with the maps-code and optimize it. In this simple code the main loop tries to draw every field....
You can add the y-part and add some input-controls. But the system keeps the same.

Last edited 2011