level file

Started by
6 comments, last by Aerts 18 years ago
I'm trying to make a C++ program that reads text (.txt) files. The text files are meant to represent the various things found in a game level (map). I need: 1)if possible a complete sourcecode that does this (or a link) or/and 2)some pointers about how to do this- especially what function/methods/structures to use.
Advertisement
No one is going to do this for you... :/

start with
#include <fstream>

//create input file stream
ifstream Input("filename.txt");

//make sure file is open
if(Input.is_open())
{
while(!Input.eof())
{
Input >> data structure of your choice;
//now just play around with input format and what you want to get out of the file
}
}
// dont forget to close the file when you're finished using it
"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein (1879-1955) That is so very true...
Quote:I'm trying to make a C++ program that reads text (.txt) files. The text files are meant to represent the various things found in a game level (map). I need:


We need:
You to tell us what you actually want to do...

There are plenty of tutorials out there on reading files - what exactly is causing you problems?
Here's the typical parser loop for reading objects:

size_t size;char * text = read_file( "level.txt", &size );char * del = text;char * end = size+text;while( text < end ) {  get_object( text );}delete[] del;


The helper function to read a file into memory looks like this:

char * read_file( char const * fn, size_t * osize ){  FILE * f = fopen( fn, "rb" );  if( !f ) throw std::runtime_error( "Can't find file" );  fseek( f, 0 , 2 );  *osize = ftell( f );  fseek( f, 0, 0 );  char * ret = new char[*osize+1];  fread( ret, 1, *osize, f );  ret[*osize] = 0;  fclose( f );  return ret;}


"getting" and "object" from a text file means parsing the file. There are a number of ways to write a parser; the simplest is a recursive-descent parser ("RD").

// assuming syntax is:// obj-type obj-name {//   parameter value;//   parameter value;// }void get_object( char * & text ){  std::string type = get_token( text );  std::string name = get_token( text );  if( get_token( text ) != '{' ) throw std::runtime_error( "syntax error; '{' expected" );  std::list< std::pair< std::string, std::string > > params;  while( true ) {    std::string param = get_token( text );    if( tok == '}' ) break; // done    std::string value = get_token( text );    if( get_token( text ) != ';' ) throw std::runtime_error( "syntax error; ';' expected" );    params.push_back( std::pair< std::string, std::string >( param, value ) );  }  register_object( type, name, params );}


OK, all we need to know now is how to read a token from a character pointer. In the simplest case, we assume that tokens are non-whitespace, non-semicolon and non-brace characters, separated by semicolons, braces, or whitespace. To support strings with spaces in them, let's use double-quote for that, and backslash-doublequote to quote a quote.

std::string get_token( char const * & text ){  while( *text && isspace( *text ) ) ++text;  if( !*text ) throw std::runtime_error( "get_token() encountered end of file" );  if( *text == '{' || *text == '}' || *text == ';' ) { ++text; return std::string(text[-1], 1); }  bool quote = false;  bool backslash = false;  std::string ret;  while( *text ) {    if( !quote && !backslash ) {      if( *text == '{' || *text == '}' || *text == ';' || isspace( *text ) ) break;      if( *text == '"' ) quote = true;      else if( *text == '\\' ) backslash = true;      else ret.push_back( *text );    }    else if( backslash ) {      ret.push_back( *text );      backslash = false;    }    else {      if( *text == '"' ) quote = false;      else ret.push_back( *text );    }    ++text;  }  if( quote || backslash ) throw std::runtime_error( "get_token() found end of file within string value" );  return ret;}


It's really not that complicates.

So, what do you do with the parsed objects that you get into register_object()? Well, that's where the specifics of your program comes in.

[Edited by - hplus0603 on March 26, 2006 5:10:35 PM]
enum Bool { True, False, FileNotFound };
What advantages does using c-style FILE* have over streams?
Quote:Original post by andrew_480
What advantages does using c-style FILE* have over streams?


Purely preference. For reading a single file into memory, using streams or using FILE* are equivalent.
enum Bool { True, False, FileNotFound };
I would look into using XML instead of just plain text to store your data. As long as you don't end up storing megabytes of text data in this file then using XML will make things easier to read and parse without too much over head.

There are a number of libraries out there that are already written to do the parsing that you want. Check out TinyXML on google. That's what I use and it works like a champ.

In the future if your level files get too big you'll want to move to a binary format anyways. At that point you can write a little utility to convert your XML files into an appropriate binary format and vice versa. This keeps it easy to read while doing your design work.
To Squirm: it's the first time I try to read a mapfile (the game that uses it is win32 console, without SDL, Allegro etc- a text game). All I need is a program that can read this:

health 100
ammo 50
damage 10

I need to know:
1 HOW to read the file: char-by-char or line by line, using delimitators?
2 how to handle whitespaces, newlines etc.

Also I'd appreciate links to some tutorials- I've searched but only found advanced tutorials/sourcecode.
Thanks.

This topic is closed to new replies.

Advertisement