Allegro.cc - Online Community

Allegro.cc Forums » Game Design & Concepts » Loading a map from a text file

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Loading a map from a text file
Paladin
Member #6,645
December 2005
avatar

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)

SonShadowCat
Member #1,548
September 2001
avatar

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.

Paladin
Member #6,645
December 2005
avatar

I actually used this for a bit

1int 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. :-/

BAF
Member #2,981
December 2002
avatar

Quote:

1int 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):

1PACKFILE *mapf = pack_fopen("map", "r");
2int w, h, x, y;
3char **map;
4 
5w = pack_igetl(mapf);
6h = pack_igetl(mapf);
7 
8map = (char **)malloc(sizeof(char *) * w);
9 
10for(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 
19pack_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.

SonShadowCat
Member #1,548
September 2001
avatar

BAF
Member #2,981
December 2002
avatar

What's too late?

SonShadowCat
Member #1,548
September 2001
avatar

I was. Posted something but your reply was more extensive.

Paul whoknows
Member #5,081
September 2004
avatar

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;
    }
}

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

Paladin
Member #6,645
December 2005
avatar

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. ><

Paul whoknows
Member #5,081
September 2004
avatar

This usually works, but is untested, so be careful!

FILE *fp;
fp=fopen("FILE.DAT","rb");
if(fp==NULL) {printf("\nFile error");}
fread(&my_tile, sizeof(my_tile), 1, fp);
while(!feof(fp) && i<24 ){
  while(!feof(fp) && j<24 ){
    fread(&my_tile, sizeof(my_tile), 1, fp);
    map<i>[j] = my_tile;
    j++;
  }
  j=0;  
  i++;
}
fclose(fp);

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

Paladin
Member #6,645
December 2005
avatar

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. :-/

LennyLen
Member #5,313
December 2004
avatar

I've tested the following with a "map.txt" file that I've attached, and it works.

1#include <stdio.h>
2 
3int 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. ;)

Paladin
Member #6,645
December 2005
avatar

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. :-/

A J
Member #3,025
December 2002
avatar

48 is ASCII for 0

fopen( .., "rb" ); is the likely cause

___________________________
The more you talk, the more AJ is right. - ML

Paladin
Member #6,645
December 2005
avatar

I actually suspected that, but I changed rb to r, then r to r+ and it all came out with ascii.

LennyLen
Member #5,313
December 2004
avatar

Quote:

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"}maptxttg9.png

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:

1#include <stdio.h>
2#include <stdlib.h>
3#include <time.h>
4 
5int main() {
6
7 FILE *map;
8 int i, j;
9
10 srand(time(0));
11
12 map = fopen("map.txt", "wb");
13
14 for (i = 0; i < 24; i++) {
15
16 for (j = 0; j < 24; j++) {
17
18 fputc(rand()%20, map);
19
20 }
21
22 }
23
24 fclose(map);
25
26 return 0;
27 
28}

[edit]

Quote:

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.

Paladin
Member #6,645
December 2005
avatar

Ok, so I have this current code:

1 FILE *mapfile = fopen("map.txt", "r+");
2 FILE *output = fopen("output.txt", "w");
3 int x, y;
4
5 for (y = 0; y < 24; y++)
6 {
7 for (x = 0; x < 24; x++)
8 {
9 map[x][y] = fgetc(mapfile) - 48;
10 fprintf(output, "%i", map[x][y]);
11 }
12 }
13
14 fclose(mapfile);
15 fclose(output);

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.

Richard Phipps
Member #1,632
November 2001
avatar

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. :)

http://www.reflectedgames.com/create.html

Paladin
Member #6,645
December 2005
avatar

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. :P

Richard Phipps
Member #1,632
November 2001
avatar

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. :)

Paladin
Member #6,645
December 2005
avatar

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?:-/

ImLeftFooted
Member #3,935
October 2003
avatar

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..
3FILE *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.

Paladin
Member #6,645
December 2005
avatar

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.

BAF
Member #2,981
December 2002
avatar

atoi wants a null terminated string, not a char AFAIK.

Paladin
Member #6,645
December 2005
avatar

So is
character - 48
the best way to do it?

 1   2 


Go to: