Reading level data from a .txt file...

BlitzMax Forums/BlitzMax Beginners Area/Reading level data from a .txt file...

spraycanmansam(Posted 2009) [#1]
As the topic, I would like to read the level data for my game from a text file. I knocked up this little bit of code to do it internally using DefData, but I would like to be able to expand on this and be able to use different characters in the text file to represent different tiles.

Can anyone help with the code to read it from the txt file stream, store it in a grid array and then differentiate the different characters to draw the corresponding tile?

I've written this kind of code in C# before but porting it to BMax is doing my head in with no sleep :P


Function readGrid()
	
	For Local y:Int = 0 Until gridH
		
		For Local x:Int = 0 Until gridW
		
			Local data:Int
			ReadData data
			
			grid[ x, y ] = data
			
		Next
		
	Next

End Function


Function drawGrid()
	
	For Local x:Int = 0 Until gridW
	
		For Local y:Int = 0 Until gridH

			Tile.Create( x * gridSize, y * gridSize )
			
		Next
		
	Next

End Function



DefData 0,0,0,0,0
DefData 0,0,0,0,0
DefData 0,0,0,0,0
DefData 0,0,0,0,0
DefData 0,0,0,0,0



Czar Flavius(Posted 2009) [#2]
Well I have just got up so brain not fully engaged yet :P However I will give you this bit of advice: it is much easier to create a level editor first, which can then save the level data, rather than trying to manually create the level data using notepad first time round.


GfK(Posted 2009) [#3]
However I will give you this bit of advice: it is much easier to create a level editor first, which can then save the level data, rather than trying to manually create the level data using notepad first time round.
I disagree entirely. If you have a sound level structure you can easily store and edit it in readable format in a text file.

There is no point whatsoever in wasting time reinventing tools to do a job, that can already be done with existing tools.

My entire game's scripting was done in notepad and I can change pretty much everything without having to recompile.

Without any further ado, sample code (typed straight into reply box, so untested):
Strict

Global file:tStream
Global array:String[] 'This is used with the S var below when we chop it up
Global s:String

Global x:Int
Global y:Int

Global grid:int[5,5]

file = ReadFile("datafile.txt")
If Not File
  RuntimeError "File not found!"
EndIf
y = 0
Repeat
  s = ReadLine(file) 'read the next line
  If Len(s) > 0
    array = s.Split(",") 'split it up into elements separated by a comma
 
    For x = 0 to array.length - 1 '(array.length returns 5, but the elements are numbered 0-4)
      grid[x,y] = array[x].ToInt() 'convert value to int and put into array
    Next
    y:+1
  EndIf
Until Eof(file)
CloseFile file


datafile.txt:
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



Jesse(Posted 2009) [#4]
or this way:
Function readGrid()
	local file:TStream = OpenStream("game.dat")
	For Local y:Int = 0 Until gridH
		
		For Local x:Int = 0 Until gridW
		
			grid[x,y] = ReadInt(file)   'Or ReadShort(file), ReadByte(file), ReadString(file,n), ReadLine(file)
			
		Next
		
	Next
	CloseStream(file)
End Function



Czar Flavius(Posted 2009) [#5]
There is no point whatsoever in wasting time reinventing tools to do a job, that can already be done with existing tools.

My entire game's scripting was done in notepad and I can change pretty much everything without having to recompile.

I wasn't talking about scripting, but 'physical' level structure, which is probably a big 2d grid of tiles. Especially if it is a complex game (doors which can only be opened by particular keys, etc) it can become very tedious and confusing directly editing a giant mass of numbers with arbitrary meanings. By creating an in-game level editor, not only can you see exactly what the level will look like what-you-see-is-what-you-get style, with a bit of polish there's no reason you can't ship it with your game too so the players can make their own levels easy peasy :D (and I don't see why you'd need to recompile to edit a level)

Case in point: here is the content of one of the map files from one of my own tile based games, with goodies, maps, doors, teleporters.. Don't ask what the numbers mean because I couldn't tell you! The ones near the bottom seem to be coordinates, probably for items. Try adding a key in the middle of one of the rooms to this level please, using only notepad. While you're doing that, I'll load my editor and visually inspect the map looking for a suitable room ;)




spraycanmansam(Posted 2009) [#6]
Thanks for the replies :)
Thanks GfK, that's put me more on the right track... I was (and still am a bit :P ) a little unfamiliar with how BMax reads streams.

To go into more depth, my level file looks something like this...

.....
.---.
.....
.....
-----


...where the '-' represents a block, '.' thin air, etc (and notice it's not comma delimited)

Sooo, what I need to do is be able to distinguish between the character types within the array to create the corresponding tile. I've been playing with it for a while, but no luck.


_Skully(Posted 2009) [#7]
The way I approach this is to create a save/load method/function within each type involved in the map and each cell may have several different types associated. When saving the map I just have to call the associated save method, when loading I just call the load function.

If you're making a fairly simple game, then what you are doing above may work for you.

You could have constants that represent the different tiles

const Tile_Block:int=1
const Tile_Air:int=2


Then save those values. When loading you can use a Select

Select LoadedTile
case Tile_Block
   ...
case Tile_Air
   ...
End Select



Jesse(Posted 2009) [#8]
this would work just how you want it Although I wouldn't do it that way.
Function readGrid()
	Local file:TStream = OpenStream("game.txt")
	Local s:String
	For Local y:Int = 0 Until gridH
		
		For Local x:Int = 0 Until gridW
			s = ReadString(file,1)
			If s= Chr(13) s = ReadString(file,1)  'end of line
			If s= Chr(10) s = ReadString(file,1)  'carriage return
			If s ="." Then grid[x,y] = 0
			If s ="-" Then grid[x,y] = 1
		Next
		
	Next
	CloseStream(file)
	
End Function



degac(Posted 2009) [#9]
If you want to be able to edit/re-edit with notepad your data-level, you should save the map-data as a text file. Of course you need to know exactly how is its data structures.
Assuming this, you can load the entire level with LoadText(url) that is a little faster than openfile - readline loop - close file.

Local txt:string=LoadText("gametext.txt")
for local line:string=Eachin txt.split("~n")
'every line 
next