Reading level data from a .txt file...
BlitzMax Forums/BlitzMax Beginners Area/Reading level data from a .txt file...
| ||
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 |
| ||
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. |
| ||
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 |
| ||
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 |
| ||
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 ;) |
| ||
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. |
| ||
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 |
| ||
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 |
| ||
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 |