Reading info from Custom Map

Started by
6 comments, last by BlackShark33 14 years, 4 months ago
Mkay, Im reading in my map from a text file, (working on a simple 3d game using OpenGL, looks similar to Wolfenstein at this point), I'm having problems, reading in the Ceiling height, for some reason, thats the only thing giving me trouble. Code that reads in the Map,


/* Grab Tesla Map data */
bool c_Map::grab_tmf()
{
	string temp;

	//Open up Texture List file
	ifstream tmf_file(tmf_loc.c_str());
    
	//if file isn't open, return false
	if(!tmf_file.is_open()) { return false; }
	//Temporary
		top:
	//Get Width and Length of Map
	getline( tmf_file, temp);
	if( temp == "" ) { goto top; }					//Make sure to skip blank space	
	sscanf(temp.c_str(), "%d %d", &data.width, &data.length);	//Grab width and height of the map (represented 2d grid)

	data.n_cell = data.width * data.length;				//Grab how many sectors there are

	//Run through all of the sectors
	for(int y = 0; y < data.length; ++y) {
	for(int x = 0; x < data.width;  ++x) {
		//Reset label if there is a space (temporary
		reset:

			//Get Cell type
			getline( tmf_file, temp);
			
			if( temp == "" ) { goto reset; }				//Make sure to skip blank space
			//ignor_char = temp.find('#');					//Grab ignorage char
			//if(ignor_char == string::npos) { goto reset; }	//Skip lines with Ignorage char
			//sector height
			sscanf(temp.c_str(), "%d", &data.cell[x][y].type);		

		

                        /* PROBLEM STEMS FROM HERE
			//Grab floor/ceiling height
			getline( tmf_file, temp);     
			sscanf(temp.c_str(), "%d %d", &data.cell[x][y].f_height, &data.cell[x][y].c_height);	
			//Grab Wall Texture references
			getline( tmf_file, temp);
			sscanf(temp.c_str(), "%d %d %d %d", &data.cell[x][y].w_tex[0], &data.cell[x][y].w_tex[1], 
											    &data.cell[x][y].w_tex[2], &data.cell[x][y].w_tex[3]);
			//Grab floor/ceiling texture references
			getline( tmf_file, temp);
			sscanf(temp.c_str(), "%d %d", &data.cell[x][y].f_tex, &data.cell[x][y].c_tex);

			//Set player position
			if(data.cell[x][y].type == S_PLAYERSPAWN)
			{
				//get player spawn point
				set_playerPosition(-x*CELL_SIZE, data.cell[x][y].f_height-1.0f, -y*CELL_SIZE);
				//set player at spawn point
				player.set_position(data.player_pos);
			}
			cout << data.cell[x][y].f_height << ", " << data.cell[x][y].c_height << endl;

	}}//nested for loop

	tmf_file.close();
	return true;
}//EoF
; or more specifically,
;

			//Grab floor/ceiling height
			getline( tmf_file, temp);     
			sscanf(temp.c_str(), "%d %d", &data.cell[x][y].f_height, &data.cell[x][y].c_height);	
Map file looks like this,

8 4
1
0 2
1 1 1 1
3 4
1
0 2
1 1 1 1
3 4
1
0 2
1 1 1 1
3 4
1
0 2 
1 1 1 1
3 4
1
0 2  
1 1 1 1
3 4
...etc.
Its read in a 2d array, the first 2 numbers is the width/height in tiles (or cells) of the map, the rest are just the Cell definition.

1             //what kind of tile it is (Wall, or openspace)
0 2           //Floor and Ceiling Height, seems to be some problem here
1 1 1 1       //the Wall texture index from the maps' texture list (another file)
3 4           //Floor Ceiling texture index
When i debug my game, when it gets to reading in the floor/ceiling heights, it reads the floor correctly, but the ceiling height ends up being "2.803e-045#DEN" Every time. Any idea what I'm doing wrong? (besides my questionable map design)
-Jawshttp://uploading.com/files/eff2c24d/TGEpre.zip/
Advertisement
What does the debugger show as the contents of the string right before you read the floor and ceiling heights?

I didn't spot the problem, but I suspect you might be able to make things a little easier on yourself by using a more consistent coding style. You're using sort of a strange combination of modern C++ techniques and more C-ish techniques (some of which are kind of outdated even for C).

Are you familiar with the C++ stream classes and related functions, such as stringstream, etc.? You're already using some of these facilities (fstream, getline), but ignoring others. What you're doing with sscanf() you could be doing with the stream extraction operator (>>), which would probably make your code cleaner and a little easier to debug.

Also (and I promise this isn't some sort of arbitrary knee-jerk reaction), what's with the goto's? Although I never use them myself (in C or C++), I occasionally hear people say that there are places where they can be useful. However, I'm 99.9% sure that this isn't one of those places. IMO, your code would be much clearer (and probably also less error-prone and easier to debug) if you replaced the goto's with conventional control structures (such as while loops).

I can tell you as someone trying to read and understand your code that the goto's really make it hard to follow (which, IMO, is reason enough not to use them).
Ya file IO has always been my weak point for some reason, I basically converted an old map reading routine i was using for an old game i did in C, that's why its so Discombobulated. I couldn't find out how to read in files as easy as you could in C using "fscanf()", there was no C++ equivalent unfortunately.
-Jawshttp://uploading.com/files/eff2c24d/TGEpre.zip/
Quote:Ya file IO has always been my weak point for some reason, I basically converted an old map reading routine i was using for an old game i did in C, that's why its so Discombobulated. I couldn't find out how to read in files as easy as you could in C using "fscanf()", there was no C++ equivalent unfortunately.
There's plenty of info available online - a search of the web and/or forum archives for 'c++ io' should return some hits.

In short, C++ overloads the << and >> operators for formatted stream insertion and extraction. What that basically means is that << will convert certain types to a text representation and then insert it into a stream, while >> will read a 'token' from a stream, convert it to a value of a specified type, and assign it to a variable.

In code, it ends up looking something like this (not compiled or tested, and no error-checking to speak of):
// This code will convert a file with one 2-d vector (e.g. x y) per line to an array of vector objects:std::ifstream file("data.txt");std::vector<Vector2> v;std::string line;while (std::getline(file, line)) {    std::istringstream stream(line);    float x, y;    stream >> x, y;    v.push_back(Vector2(x, y));}
Note that in this case you probably wouldn't need to read the file line by line, but I included it in the example since that's what you're wanting to do.
I'm wondering if your heights are floats, so you should use the %f specifier rather than %d.
Quote:Original post by Gooberius
I'm wondering if your heights are floats, so you should use the %f specifier rather than %d.


LOL, i think this maybe the problem, I'll check it out, I'll try to update my file io code as well, thank you every body for you help :)

EDIT: I can't believe it, but that was INDEED the problem, thank you :)

[Edited by - BlackShark33 on December 10, 2009 8:20:25 PM]
-Jawshttp://uploading.com/files/eff2c24d/TGEpre.zip/
See, if you'd used the equivalent C++ tools, you would have avoided that problem automatically. :)

// If you need a comment to explain what your function does, your function// name is not clear enough.// Also, putting 'c_' on the beginning of class names gains you exactly nothing.bool Map::readFileData() {	string line;	// Don't write comments to explain what code does; write them to	// explain why you're doing it. And again, work with clear variable	// names. Don't try to put information into the variable name that	// doesn't actually help understand the code. You only have one kind	// of map data (I'm assuming!) and there's only one data file that	// gets read by a Map (again, I'm assuming) so you don't need to say	// which file it is. (And you certainly don't need to call something	// "tmf_file" when the 'f' stands for 'file'!)	// To demonstrate the point, I've been very sparing with comments	// here - except to explain the problems with the old code.	ifstream file(filename.c_str());	if (!file.is_open()) { return false; }	// Use locals for values that you'll do a lot of work with, and only	// store them into a difficult-to-refer-to place when you're done.	// That way, you avoid repeating the "navigation instructions".	int width, length;	// Use loop constructs to loop.	while (true) {		// Notice how with modern tools, blank lines are automatically		// handled, because the attempt to scan data will fail. Although		// you could have done that with sscanf() too, by simply		// checking the return value.		if (!(getline(file, line)) { return false; }		stringstream ss(line);		if (ss >> width >> length) { break; }	}	data.width = width;	data.length = length;	// Don't store redundant information. In this case, that's	// data.n_cell.	// Indent for every for loop. If it looks bad because there's too	// much indentation, that's because your code is too complicated.	for (int y = 0; y < length; ++y) {		for (int x = 0; x < width; ++x) {			// To avoid copying overhead/logic, you can also use			// references when you do the trick with locals			// mentioned above.			Cell& c = data.cell[x][y];			while (true) {				if (!(getline(file, line)) { return false; }				stringstream ss(line);				if (ss >> c.type) { break; }			}			// In your code you didn't skip blank lines at this			// point, so I won't either. But I will continue to			// add error checking logic. ;)			if (!(getline(file, line)) { return false; }			stringstream ss(line);			if (!(ss >> c.floor_height >> c.ceiling_height) { return false; }					if (!(getline(file, line)) { return false; }			stringstream ss(line);			if (!(ss >> c.wall_textures[0] >> c.wall_textures[1] >> c.wall_textures[2] >> c.wall_textures[3]) { return false; }			if (!(getline(file, line)) { return false; }			stringstream ss(line);			if (!(ss >> floor_texture >> ceiling_texture) { return false; }			//Set player position			if (c.type == S_PLAYERSPAWN) {				set_playerPosition(-x * CELL_SIZE, c.floor_height - 1.0f, -y * CELL_SIZE);				// Hold on; where does player_pos come from?				player.set_position(data.player_pos);			}			cout << c.floor_height << ", " << c.ceiling_height << endl;		}	}	// You don't need to close the file explicitly.	return true;}// No semicolon is needed after member function implementations - just after// the class body.


[Edited by - Zahlman on December 11, 2009 1:10:17 PM]
Quote:Original post by Zahlman
See, if you'd used the equivalent C++ tools, you would have avoided that problem automatically. :)

*** Source Snippet Removed ***



Thank you very much! this helped clean up map loading quite a bit, but i was wondering how would you skip blank lines when reading in the other variables?
-Jawshttp://uploading.com/files/eff2c24d/TGEpre.zip/

This topic is closed to new replies.

Advertisement