Ok, so I've had a problem for awhile, I'm trying to load a map from a text file. The map has 24 X 24 numbers and each number represents a tile. This is my current loading code (I'm using C) :
| 1 | int i, j; |
| 2 | writeToLog("Opening Map File...\n"); |
| 3 | mapfile = fopen("map.txt", "r"); |
| 4 | if(mapfile == NULL) |
| 5 | allegro_message("Map failed to load!"); |
| 6 | char ch; |
| 7 | writeToLog("Getting first character...\n"); |
| 8 | ch = getc(mapfile); |
| 9 | while(ch != EOF) |
| 10 | { |
| 11 | writeToLog("First while loop\n"); |
| 12 | map<i>[j] = (int)ch; |
| 13 | writeToLog("Setting map to character from map"); |
| 14 | ch = getc(mapfile); |
| 15 | writeToLog("Got the character...\n"); |
| 16 | if(i < 24) |
| 17 | i++; |
| 18 | else |
| 19 | { |
| 20 | i = 0; |
| 21 | j++; |
| 22 | } |
| 23 | } |
| 24 | |
| 25 | fclose(mapfile); |
When I take out
map<i>[j] = (int)ch;
it works, but then again that's the key part. When it does work, it just ends up loading the same tile repeated. Can anyone help? (The source is attached)
Why not use a for loop and make the whole code much cleaner? There is no real need to check for EOF if you know the amount of tiles beforehand.
Anyway, getc() returns an int so there is no need to make ch a char and cast it later. Other than that I don't know what to say.
BTW, the source isn't attached.
I actually used this for a bit
| 1 | int i, j; |
| 2 | int num = 0; |
| 3 | char *ch; |
| 4 | ch = (char*)malloc(576); |
| 5 | mapfile = fopen("map.txt", "rt"); |
| 6 | if(mapfile == NULL) |
| 7 | allegro_message("Map file isn't loaded correctly"); |
| 8 | fread(ch, 576, 576, mapfile); |
| 9 | for(i = 0; i < 24; i++) |
| 10 | { |
| 11 | for(j = 0; j < 24; j++) |
| 12 | { |
| 13 | map[j]<i> = ch[num]; |
| 14 | num++; |
| 15 | } |
| 16 | } |
| 17 | free(ch); |
| 18 | fclose(mapfile); |
And it didn't work so well either.
| 1 | int i, j; |
| 2 | writeToLog("Opening Map File...\n"); |
| 3 | mapfile = fopen("map.txt", "r"); |
| 4 | if(mapfile == NULL) |
| 5 | allegro_message("Map failed to load!"); |
| 6 | char ch; |
| 7 | writeToLog("Getting first character...\n"); |
| 8 | ch = getc(mapfile); |
| 9 | while(ch != EOF) |
| 10 | { |
| 11 | writeToLog("First while loop\n"); |
| 12 | map<i>[j] = (int)ch; |
| 13 | writeToLog("Setting map to character from map"); |
| 14 | ch = getc(mapfile); |
| 15 | writeToLog("Got the character...\n"); |
| 16 | if(i < 24) |
| 17 | i++; |
| 18 | else |
| 19 | { |
| 20 | i = 0; |
| 21 | j++; |
| 22 | } |
| 23 | } |
| 24 | |
| 25 | fclose(mapfile); |
I would use something more like (untested):
| 1 | PACKFILE *mapf = pack_fopen("map", "r"); |
| 2 | int w, h, x, y; |
| 3 | char **map; |
| 4 | |
| 5 | w = pack_igetl(mapf); |
| 6 | h = pack_igetl(mapf); |
| 7 | |
| 8 | map = (char **)malloc(sizeof(char *) * w); |
| 9 | |
| 10 | for(x = 0; x < w; ++x) |
| 11 | { |
| 12 | map[x] = (char *)malloc(sizeof(char) * h); |
| 13 | for(y = 0; y < h; ++y) |
| 14 | { |
| 15 | map[x][y] = pack_igetw(mapf); |
| 16 | } |
| 17 | } |
| 18 | |
| 19 | pack_fclose(mapf); |
Although I have more information in my maps, that's a basic map loader. Untested though, but should work.
[edit]
You'd have to write the map file using the inverse of whats above as it would be binary, not plain text.
Too late.
What's too late?
I was. Posted something but your reply was more extensive.
instead of
if(i < 24) i++; else { i = 0; j++; }
try this
for(i=0; i<24; i++) { for(j=0; j<24; j++) { map<i>[j] = (int)ch; } }
Ok I tried that, and it didn't work. This is really annoying. Is there any way to do it in a similiar way I was doing it?
EDIT: Paul, I tried your method as well, and it didn't work either. ><
This usually works, but is untested, so be careful!
No, it didn't work. Once again it just repeated the tiles, but this one had patches of grass in a black spot on the left.
I've tested the following with a "map.txt" file that I've attached, and it works.
| 1 | #include <stdio.h> |
| 2 | |
| 3 | int main() { |
| 4 | |
| 5 | FILE *mapfile, *output; |
| 6 | int i, j; |
| 7 | int map[24][24]; |
| 8 | |
| 9 | mapfile = fopen("map.txt", "rb"); |
| 10 | output = fopen("output", "w"); |
| 11 | |
| 12 | for (i = 0; i < 24; i++) { |
| 13 | |
| 14 | for (j = 0; j < 24; j++) { |
| 15 | |
| 16 | map<i>[j] = fgetc(mapfile); |
| 17 | fprintf(output, "Read value (%d, %d): %d\n", i, j, map<i>[j]); |
| 18 | |
| 19 | } |
| 20 | |
| 21 | } |
| 22 | |
| 23 | fclose(mapfile); |
| 24 | fclose(output); |
| 25 | |
| 26 | return 0; |
| 27 | |
| 28 | } |
Also attached is the output from the program, which shows it works.
Actually when I use your attachment, the map.txt is a bunch of squares and the output has numbers ranging from 0 - around 15. I tried this code myself, and wrote it to my output.
This:
000000000000000000000000 000000000000000000000000 000000000022220000000000 000000000022220000000000 000000000000000000000000 333333333333333333333333 333333333333333333333333 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 333333333333333333333333 333333333333333333333333 000000000000000000000000 000000000022220000000000 000000000022220000000000 000000000000000000000000 000000000000000000000000
turned into this:
484848484848484848484848 484848484848484848484848 131048484848484848484848 484848484848484848484848 484813104848484848484848 484850505050484848484848 484848481310484848484848 484848485050505048484848 484848484848131048484848 484848484848484848484848 484848484848484813105151 515151515151515151515151 515151515151515151511310 515151515151515151515151 515151515151515151515151 131049494949494949494949 495151494949494949494949 494913104949494949494949 494949515149494949494949 494949491310494949494949 494949494951514949494949 494949494949131049494949 494949494949495151494949 494949494949494913104949 494949494949494949515149 494949494949494949491310 494949494949494949494951 514949494949494949494949 131049494949494949494949 495151494949494949494949 494913104949494949494949 494949515149494949494949 494949491310494949494949 494949494951514949494949 494949494949131049494949 494949494949495151494949 494949494949494913105151 515151515151515151515151 515151515151515151511310 515151515151515151515151 515151515151515151515151 131048484848484848484848 484848484848484848484848 484813104848484848484848 484850505050484848484848 484848481310484848484848 484848485050505048484848 484848484848131048484848
Except that the above code was all on one line. I still can't see why it's doing this.
48 is ASCII for 0
fopen( .., "rb" ); is the likely cause
I actually suspected that, but I changed rb to r, then r to r+ and it all came out with ascii.
Actually when I use your attachment, the map.txt is a bunch of squares and the output has numbers ranging from 0 - around 15.
The map.txt file is 576 (24x24) characters. Each character can be a number between 0 and 255 (though the generator I used only generated numbers between 0 and 20). You cannot see these characters (your text editor displays them as squares) as they are non-displayable characters.
Try getting a better text editor with a hex-edit mode so you can see the values:
{"name":"maptxttg9.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/6\/e621f2523bd89e154ee766bdbee86034.png","w":643,"h":641,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/6\/e621f2523bd89e154ee766bdbee86034"}
If you look at the hex values, and convert them to decimal, you will see that they corrspond to the decimal values in the output file.
Obviously this approach cannot be taken if you have more than 256 values for the map data.
Here is how this map.txt file was created:
[edit]
Except that the above code was all on one line. I still can't see why it's doing this.
You are not svaing the numbers 0, 1, 2, etc. to file, you are saving the characters '0', '1', '2', etc to file. when you read these as integers instead of characters, you will get there corresponding ASCII codes; 48, 49, 50, etc.
If you want to read the numbers 0, 1, 2, then you will need to write them as the chars with value 0, 1, 2, etc, which is what I did.
Alternatively, you can read them as chars, then subtract 48 to convert them to the numbers you want.
[edit2]
The 1310 that keeps repeating through your output is where it's reading the end of line chars 13 and 10 (under DOS/Windows). Either write your files in a method that does not include these characters, or you will need to read each line individually to strip the end of line characters.
Ok, so I have this current code:
and when I load map:
000000000000000000000000 000000000000000000000000 000000000022220000000000 000000000022220000000000 000000000000000000000000 333333333333333333333333 333333333333333333333333 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 111111111113311111111111 333333333333333333333333 333333333333333333333333 000000000000000000000000 000000000022220000000000 000000000022220000000000 000000000000000000000000 000000000000000000000000
I get
000000000000000000000000 -38000000000000000000000 000-38000000000022220000 000000-38000000000022220 000000000-38000000000000 000000000000-38333333333 333333333333333-38333333 333333333333333333-38111 111111113311111111111-38 111111111113311111111111 -38111111111113311111111 111-38111111111113311111 111111-38111111111113311 111111111-38111111111113 311111111111-38111111111 113311111111111-38111111 111113311111111111-38111 111111113311111111111-38 111111111113311111111111 -38333333333333333333333 333-38333333333333333333 333333-38000000000000000 000000000-38000000000022 220000000000-38000000000 022220000000000-38000000 000000000000000000-38000 000000000000000000000-49
I tried a few things, but I couldn't seem to figure out why it has the negative numbers there. Sorry Lenny that I didn't catch the binary part, I should have picked that up.
If you are only going to have a few tiles then just use bitmaps like I did for my Free Dungeons tutorial. It makes it much easier to change your maps in any paint program. 
Hahaha, I was actually going to do that, but I really just wanted to learn how to load a map from a textfile rather from a bmp. I would actually rather use your bmp method since it's easy, but I am trying to learn.
Manually entering numbers in a textfile is too awkward though. You'd have to write a map editor to do complex maps and then you might as well either use binary data directly with the map editor, or just use bitmaps if you have less than around 30 different tile types.
I actually plan on writing a map editor once I'm done with this. I'll probably convert to binary once I get this working. Would you happen to know what my current problem is?:-/
Your file reader is reading newlines. Newlines are characters that appear at the end of a line and can be one or two characters. Heres an easy way to fix your code.
| 1 | #include <ctype.h> // Add this to the top of your file |
| 2 | .. |
| 3 | FILE *mapfile = fopen("map.txt", "r+"); |
| 4 | FILE *output = fopen("output.txt", "w"); |
| 5 | int x, y; |
| 6 | |
| 7 | for (y = 0; y < 24; y++) |
| 8 | { |
| 9 | for (x = 0; x < 24; x++) |
| 10 | { |
| 11 | int c = '\0'; |
| 12 | |
| 13 | while(!isdigit(c)) |
| 14 | c = fgetc(mapfile); |
| 15 | |
| 16 | map[x][y] = c - 48; |
| 17 | fprintf(output, "%i", map[x][y]); |
| 18 | } |
| 19 | } |
| 20 | |
| 21 | fclose(mapfile); |
| 22 | fclose(output); |
By the way, you really don't want to use the mode "r+", a simple "r" should do just fine. You should also really replace 'c - 48' with 'atoi(c)', its much cleaner and portable.
Originally, I used atoi, but it never worked. It would always crash for some reason.
BTW, your method worked. Thanks a lot! Would you happen to know why atoi wouldn't work? I replaced it like you said and I have stdlib.h included.
atoi wants a null terminated string, not a char AFAIK.
So is
character - 48
the best way to do it?
Hm, well the best way i think is to put spaces inbetween each number and then use atoi.
Your map format would be something like:
0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0
and then you'd read the file into a char* and call atoi on that. And then increment past spaces.. yeah in C it kinda sucks. Heres the C++ version to parse the above with spaces.
ifstream in("map.txt"); ofstream out("output.txt"); for(int y = 0; y < 24; y++) { for(int x = 0; x < 24; x++) { in >> map[x][y]; out << map[x][y]; } }
This code does the same as the C code in my last post did, except that it assumes there are spaces inbetween the numbers.