I threw together a simple application to test out drawing tiles to the screen. This is nothing new, but I had never drawn more than three or four different tiles at once, so I wanted to test out using sixteen different tiles (just for fun). Anyway, each tile's data is stored in a text file and uses an integer to represent a particular tile. For example, "10" would represent a water tile. However, I've run into an issue with tiles with a value greater than nine. It seems to treat "10" as both "1" and "0", thus scrambling the screen.
main.cpp
map.h
map.cpp
map.txt
10 10 10 10 10 10 10 10 3 5 5 5 4 10 10 7 9 9 9 8 10 10 7 9 9 9 8 10 10 7 9 9 9 8 10 10 1 6 6 6 2 10 10 10 10 10 10 10 10
I've attached an image of what it results in. Any ideas why it's screwing my map up? Should I not use any tile above nine, it works just fine... But that would limit me to 10 (0-9) tiles.
What I usually do when I encounter problems like these is to use a symbol or letter to let my program know when to stop and add whatever it read up to that symbol or letter.
I quickly looked over your code, what you're basically doing is just checking each number and adding it to the array. This wont work as you've already witnessed, the reason for this is when you're checking against 10, a double digit number. you add 1 to the array then you read again and add 0.
One possible fix would be what I described above, example:
std::string buffer; while (!openfile.eof()) { // Assign tile data into array buffer.clear(); openfile.getline(buffer.c_str(), 3, '.'); tile[loadCounterX][loadCounterY] = atoi(buffer.c_str()); // rest of the stuff you wrote here }
map.txt would look like this:
10.10.10.10.10.10.10 10.3.5.5.5.4.10 10.7.9.9.9.8.10 10.7.9.9.9.8.10 10.7.9.9.8.10
Note: I didn't try any of this code so I don't think it'll be copy and paste-able. You can try though.
Thank you for the reply. I see where you're going with that, but your code did not work. I read up on the getline function too, but haven't managed to get it working just yet. It seems to work if I use a char* instead of a string for buffer, but then I can't clear it. Here's what your suggestion returns me:
C:\Users\Eric II\Desktop\games\mld-40\new\map.cpp||In member function 'bool Map::load(const char*)':|
C:\Users\Eric II\Desktop\games\mld-40\new\map.cpp|38|error: invalid conversion from 'const char*' to 'std::basic_istream<char>::char_type* {aka char*}' [-fpermissive]|
c:\mingw\bin\..\lib\gcc\mingw32\4.6.2\include\c++\istream|599|error: initializing argument 1 of 'std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::getline(std::basic_istream<_CharT, _Traits>::char_type*, std::streamsize, std::basic_istream<_CharT, _Traits>::char_type) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_istream<_CharT, _Traits>::char_type = char, std::streamsize = int]' [-fpermissive]|
||=== Build finished: 2 errors, 0 warnings (0 minutes, 0 seconds) ===|
It looks to me as though it wants a const char* instead of a string, but like I said earlier, I wouldn't be able to clear a const char*.
I thought it wouldn't work, but that wasn't the point of the post. You need to figure out a way to make sure that you're always reading the correct amount of integers.
Another way to solve your problem would be to use double digits for all your tiles.
01, 02, 03 etc etc and read two numbers at a time. But then you'd face the same problem if you ever had over 99 different tiles. This solution is a lot easier than looking for a delimiting character.
You don't need to remove the spaces. Get the integers one by one from the ifstream and it will work. Like this:
EDIT: Try compiling this code and testing it with the following input file. You'll see.
Thanks for the input, Cassio Renan. I am using a two-dimensional array for my x and y tiles. How would I incorporate your suggestion into a 2D array?
knowing the number of columns, it's easy:
for(i=0;i<num_tiles;i++){ x = i%columns; y = i/columns; map[x][y] = tile[i]; }
You may want to make the two first integers of your map file to be the map size. That way you can make it easier for you to get the entire map later.
On a side note: This is only an example. You should get the integers directly into your matrix, instead of passing them to an array first, witch is a not very smart redundancy. But I guess you know that
That would make sense I suppose, but my previous setup allowed me to dynamically get the rows and columns. I think it'd be better to implement Gnamra's suggestion about separating each value on the map with a dot or something, then to remove the dot and compare them. I've been reading up on getline and whatnot, but haven't had any luck yet being able to get his suggestion working. What do you think?
I see. Dumping them directly from the ifstream will ignore any spaces and newlines, so it's not a nice sollution. Instead, get the lines using getline(the global one, not istream's), and then dump them using a stringstream, just like if you used the ifstream. I'll code an example right now(and this one's more complicated ), so give me a minute.
EDIT: Finally done
Spaces delimit columns, newlines delimit rows.
Note that there's a LOT of room for improvement here. For instance, it will get the number of columns from the last row, i.e.: It doesn't check for any(incorrect) larger or smaller rows. Said that, that map1.txt file I posted will fail(since the first line has 4 ints, and the second has 5). Use this one instead:
I appreciate your willingness to help me out here.
Edit
So here's what I understand from your example. Correct me if I am wrong...
I am fairly new to C++.
yup, that's it.
Try to look at the reference for istream to get a better understanding on input streams(ifstream and istringstream inherit from them). I know that reading trough the reference may be a bit overkill for a beginner, but you should get an idea of what is what by looking at the info there.
EDIT: looking again:
you should rephrase that to:
I'll be sure to read it over.
Quick question: why do you reset j? If I remove the reset, it displays the file's contents, but if the reset is present, it does not display the file's contents.
if j is not reset, it will contain the number equivalent to width*height. Your map file probably has a newline at the end of it(another problem that the code doesn't check for), and that is making j reset just before reaching the EOF.
In case you're still stuck, a sollution for that is to check if the streamed line is empty. That's easy: It will be empty if j == 0. Add these lines, right after the second while loop:
if(j) h = j; else break;
and remove the line:
h = j;
down bellow. Note that this fix will make any empty line simbolize "stop reading". That means, anything after an empty line will be ignored.
Oh I see. Also, why use a string AND istringstream? Wouldn't a string alone be sufficient?
Actually, you could use a string, no prob. Using a stream just makes your job easier(You're not doubling the memory usage, per se: istringstream just holds a pointer to the string, instead of copying the data). One way of getting data directly from the string(altough really old) is to use g' old C's sscanf. It will also ignore spaces.
EDIT: The reason to use an istringstream is to be able to use the overloaded extracion operator("<<") to get the data from the string.
EDIT2: Correcting myself, sscanf will not ignore spaces, unless told to do so. A working example:
WTF are you guys doing?
Just use an ifstream and be done with it. Stop dicking around with stringstreams and buffers already. You can read directly into an integer from an ifstream. Read the width and height, create your map, and then read the values. ifstream >> int& skips leading whitespace, so you can keep using spaces in your text file. And as many as you need to maintain nice rows and columns. I do not know what number the stream extractor will return if a number has leading zeroes though. You could also write your own extractor function and call it directly.
void store_next_int(ifstream input , int& store) { //... }
Here's Map.txt :
3 4 0 1 2 3 4 5 6 7 8 9 10 11
Here's the output :
c:\ctwoplus\progcode\allegro5\test>MapReader Map.txt 0 1 2 3 4 5 6 7 8 9 10 11
Everything you need to look at is here on http://cplusplus.com.
http://cplusplus.com/reference/fstream/ifstream/
I know that.
You may want to make the two first integers of your map file to be the map size. That way you can make it easier for you to get the entire map later.
That would make sense I suppose, but my previous setup allowed me to dynamically get the rows and columns
Hi again. I appreciate the replies guys, truly.
I went out and learned all about vectors and whatnot, and threw together another tile system, which worked much better than my last one... Then I came back here and saw Edgar Reynaldo's post; you knocked it out of the park man. Your approach is so much smaller and easier than I had going. Ha. I appreciate it! That's pretty damn nice.
I come from a PHP background, so I'm still adjusting to C++... Vectors are so nice guys.
I come from a PHP background, so I'm still adjusting to C++... Vectors are so nice guys.
PHP's got vectors (essentially). Well, arrays have all the functionality of vectors... and a bunch of other data types.
Well, technically I suppose they do (array lists are essentially vectors), but they are somewhat different than C++'s; that's what I meant.