help reading a game setting file into engine

Started by
3 comments, last by Zahlman 15 years, 9 months ago
I want to parse the sample file that is below and load it into my game engine. . I just want to be able to associate the below file to me game engine executable. I can read a similar file but I want to have it more generic. I am not sure this qualifies as needing a scripting language

Sample File

[GAMENAME] 
PAC MAN;

 [STATIC]
#object name, amount, image name, image mask, image hight, width
        tiles           66            1.bmp       mask.bmp           30            30
      player           1             2.bmp       mask.bmp           60            63
pac-man_tiles     1      maptiles.bmp maptilesmask.bmp 18          29

[ANIMATED]
ghost   ghost.bmp ghostmask.bmp  29 22 1 2 30
pac-man anim2.bmp animmask2.bmp  30 30 1 12 0

[LEVEL 0]
#  x      y   type  and extra
(tiles)
  105  33    2                0
156 34 2 0
206 34 2 0
256 34 2 0
307 33 2 0
357 34 2 0
(player)
100 50

I am trying to use a struct with a vector. The reason I am trying to do that so I can read every thing under each heading in a separate vector and have all its properties associated with it . For example I have a tile and attached to that tile is how many tiles, the image name, the image mask, its width and height. Then when the level loads it picks the object and places it at the x and y cords. Right now I am using a tone of vectors but there not connected in any way. I need one vector with many properties.

struct Sprite
{
    string Object_name;
    string Image_name;
    string Image_mask;
    int amount;
    int width;
    int height;
};

 vector<Sprite> sprites_obj;


     //Variable for file stream
     std::ifstream stream;

     //Variable for file name
     std::string my_file = "my_file.txt",data_set,name,object_type,image_name,image_mask;
     int amount,width,height;
     // Open stream to read the file
     stream.open(my_file.c_str());

       while (!stream.eof()) 
             {
                    
                    string test;
               // Search for next data_set

              stream >> data_set;

          if (data_set.find( "//" )  != std::string::npos || data_set.find( "#" ) != std::string::npos)
             {
               stream.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
              //Ignore tell end of line
            }
           else  if (data_set.find("[GAMENAME]") != std::string::npos)
               {
                    getline(stream,name);
                    getline(stream,name);
                  }
           else if(data_set.find("[STATIC]") != std::string::npos)
           {
                vector<string> static_objects;
                vector<string> static_image_name;
                vector<string> static_image_mask;
                vector<int>  static_amount;
                vector<int> static_width;
                vector<int> static_height;
                
                stream>>object_type;
                static_objects.push_back(object_type);
                sprites_obj.push_back(object_type);
              // sprites_obj[0].Object_name = "test";
              // cout<<sprites_obj[0].Object_name;
                stream>>amount;
                static_amount.push_back(amount);
                stream>>image_name;
                static_image_name.push_back(image_name);
                stream>>image_mask;
                static_image_mask.push_back(image_mask); 
                stream>>width;
                static_width.push_back(width);
                stream>>height;
                static_height.push_back(height);
            }
          
                }

        
 
Advertisement
The simple way to do this is with state and tokenization. That is, you break the problem down as follows:

  • Initialize your parser state. This allows you to keep track of 'where' you are, logically, in the file -- for example, when you read a header-like line ([LEVEL 0], [STATIC]) you update your parse state to reflect this somehow. This allows you to gauge how you should interpret the tokens on each line.

  • You read each line -- the complete, entire line -- and break it up into tokens. This is usually done by splitting on whitespace, producing a std::vector<std::string>> or the like contain each non-whitespace token from that line.Boost has some string manipulation routines that can help with this.

  • You exhaust each element of the vector you just read, handling it appropriately based on your state. This is achieved simply by some kind of switch statement based on your state (or nested if/else pairs if your state is too complex for a switch, but it doesn't look like yours needs to be, offhand) and then a loop over each item in the vector from the previous step.


For example, if you are in the [STATIC] state, you know that each line has a certain format and contains certain values in specific indices of the resulting token vector (e.g., object name is the 0th element). This also allows you some measure of error checking.

You seem to have the basic concept down, or at least partially formed, but your code could use some cleanup and reorganization. In particular, you're reading everything into locally-scoped vectors that get blown away when the scope exits. You're also not reading the line and tokenizing in favor of just using the formatted IO operators to pick everything up based on whitespace -- this is also acceptable in practice, although I personally find it annoying to maintain.

To solve your issue with respect to
Quote:
For example
I have a tile and attached to that tile is how many tiles, the image name, the image mask, its width and height.

Then when the level loads it picks the object and places it at the x and y cords.
Right now I am using a tone of vectors but there not connected in any way. I need one vector with many properties.

it sounds like you need to create yourself a Tile class or struct, and maintain a vector of Tile objects that you construct and fill as you read each tile section of the file -- similar to how you have a Sprite object.
Quote:Original post by jpetrie
The simple way to do this is with state and tokenization. That is, you break the problem down as follows:

  • Initialize your parser state. This allows you to keep track of 'where' you are, logically, in the file -- for example, when you read a header-like line ([LEVEL 0], [STATIC]) you update your parse state to reflect this somehow. This allows you to gauge how you should interpret the tokens on each line.

  • You read each line -- the complete, entire line -- and break it up into tokens. This is usually done by splitting on whitespace, producing a std::vector<std::string>> or the like contain each non-whitespace token from that line.Boost has some string manipulation routines that can help with this.

  • You exhaust each element of the vector you just read, handling it appropriately based on your state. This is achieved simply by some kind of switch statement based on your state (or nested if/else pairs if your state is too complex for a switch, but it doesn't look like yours needs to be, offhand) and then a loop over each item in the vector from the previous step.


For example, if you are in the [STATIC] state, you know that each line has a certain format and contains certain values in specific indices of the resulting token vector (e.g., object name is the 0th element). This also allows you some measure of error checking.

You seem to have the basic concept down, or at least partially formed, but your code could use some cleanup and reorganization. In particular, you're reading everything into locally-scoped vectors that get blown away when the scope exits. You're also not reading the line and tokenizing in favor of just using the formatted IO operators to pick everything up based on whitespace -- this is also acceptable in practice, although I personally find it annoying to maintain.



Could you show me some sample code or something so I can see were I am going wrong?
"You read each line -- the complete, entire line -- and break it up into tokens. This is usually done by splitting on whitespace, producing a std::vector<std::string>> or the like contain each non-whitespace token from that line."

To read the entire line I use getline();

But how can I store that so it can be broken up later and the data used?
Quote:Original post by kingpinzs
"You read each line -- the complete, entire line -- and break it up into tokens. This is usually done by splitting on whitespace, producing a std::vector<std::string>> or the like contain each non-whitespace token from that line."

To read the entire line I use getline();

But how can I store that so it can be broken up later and the data used?


When you use std::getline, you have already stored the line into the std::string variable that you provided.

To break up the data in the string, use it to construct a std::stringstream, and then read out of the stringstream with operator>>.

This topic is closed to new replies.

Advertisement