Drawing a level
octotep

Hello everybody. For my game I'm trying to create a load_level function which loads a config file from disk to get all of the parameters for drawing the level. The problem is I have is in the level struct, where I have a int **, in order to hold the order of tiles to be drawn. The level struct looks like this:

#SelectExpand
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <allegro5/allegro.h> 5 6#include "player.h" 7 8typedef struct level 9{ 10 int size_x; 11 int size_y; 12 float start_x; 13 float start_y; 14 int tilesize; 15 int **tilemap; 16 ALLEGRO_BITMAP *tile_file; 17} level; 18 19extern level *load_level(int world_num, int level_num); 20extern void destroy_level(level *my_level); 21extern void setup_level(level *my_level, player *my_player);

The problem is in the load level function, where I try to assign the values from the config file to int **tilemap

#SelectExpand
1level *load_level(int world_num, int level_num) 2{ 3 ALLEGRO_CONFIG *level_file; 4 level hard_level; 5 level *tmp_level; 6 tmp_level = &hard_level; 7 const char *tile_file_name; // for the tiles.bmp level.tile_file 31 8 char level_file_name[27]; // worldxx-levelyy.cfg 27 9 10 // Get all of the data from the level cfg file 11 sprintf(level_file_name, "levels/world%02d-level%02d.cfg", world_num, level_num); 12 level_file = al_load_config_file(level_file_name); 13 tmp_level->size_x = atoi(al_get_config_value(level_file, NULL, "size_x")); 14 tmp_level->size_y = atoi(al_get_config_value(level_file, NULL, "size_y")); 15 tmp_level->start_x = (float) atof(al_get_config_value(level_file, NULL, "start_x")); 16 tmp_level->start_y = (float) atof(al_get_config_value(level_file, NULL, "start_y")); 17 tmp_level->tilesize = atoi(al_get_config_value(level_file, NULL, "tilesize")); 18 19 // Get the tile file loaded into the level struct 20 tile_file_name = al_get_config_value(level_file, NULL, "tile_file"); 21 tmp_level->tile_file = al_load_bitmap(tile_file_name); 22 23 24 // Create the tilemap array 25 tmp_level->tilemap = malloc(tmp_level->size_y * sizeof(int *)); 26 if(tmp_level->tilemap == NULL) 27 { 28 fprintf(stderr, "Out of memory for the pointer-pointer-int in the level struct!\n"); 29 return NULL; 30 } 31 int i; 32 for(i = 0; i < tmp_level->size_y; i++) 33 { 34 tmp_level->tilemap[i] = malloc(tmp_level->size_x * sizeof(int)); 35 if(tmp_level->tilemap[i] == NULL) 36 { 37 fprintf(stderr, "Out of memory for the **intergers in the level struct!\n"); 38 return NULL; 39 } 40 } 41 42 // Get the tilemap data from the cfg file 43 char *result = NULL; 44 const char *tilemap_data; 45 tilemap_data = al_get_config_value(level_file, NULL, "map_data"); 46 result = strtok((char *)tilemap_data, ","); 47 int x = 0; 48 int y = 0; 49 50 while (result != NULL) 51 { 52 hard_level.tilemap[y][x] = atoi(result); 53 while(x < tmp_level->size_x) 54 { 55 hard_level.tilemap[y][x] = atoi(result); 56 result = strtok(NULL, ","); 57 x++; 58 } 59 x = 0; 60 result = strtok(NULL, ","); 61 y++; 62 } 63 fprintf(stderr, "done the strtok loop\n"); 64 65 // See if the pointer was filled correctly 66 int b, c; 67 for(b = 0; b < tmp_level->size_y; b++) 68 { 69 for(c = 0; c < tmp_level->size_x; c++) 70 fprintf(stderr, "%i,", tmp_level->tilemap[b][c]); 71 } 72 73 al_destroy_config(level_file); 74 fprintf(stderr, "~~CREATE LEVEL - DONE~~\n"); 75 return tmp_level; 76}

Inside the function, getting the values from a_level->tilemap[y][x] returns the expected values. Outside the function, a_level->tilemap[y][x] returns garbage values and crashes the program.

The config file that I am using looks like this:

size_x = 20
size_y = 15
start_x = 32.0
start_y = 416.0
tilesize = 32
tile_file = tiles/tiles.bmp
map_data = 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,1,2,2,2,2,2,2,3,3,3,2,2,2,2,2,2,2,2,3,1,0,3,3,3,3,3,3,1,1,1,3,3,3,3,3,3,3,3,1,0,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0

How would I need to change my code in order to access the **tilemap pointer and get correct values?

Edgar Reynaldo
octotep said:

  level hard_level;
  level *tmp_level;
tmp_level = &hard_level;
//... return tmp_level;

You are returning the address of a temporary level object. As soon as load_level returns 'hard_level' is no longer a valid object. You have to create a new 'level' using malloc. It crashes because the area in memory where 'hard_level' was has most likely been overwritten or else it causes a segfault.

octotep

Ok, I think I see what the problem is now, but I have one more question.
I now have:
level *tmp_level = malloc(sizeof(level));
instead of
level *tmp_level;
but the program gives the error:
"request for member 'tilemap' in something not a structure or a union", so I don't think what I did was right.

Could you point me in the right direction as to what I need to do to malloc() the level?

Thanks

gnolam

Since you're now dealing with a pointer to a struct instead of a struct itself, you're using the wrong member access operator - "." instead of "->".

octotep

Hrm... I fixed that, but now my main loop always crashes when I try to access the tilemap (even though I allocate memory for that and the level struct pointer), while I can access the other values of the level struct just fine.

#SelectExpand
1 // In main, before the loop checking for events and after initializing 2 // everything 3 level *first_level; 4 first_level = load_level(current_world, current_level); 5 if(!first_level) 6 { 7 fprintf(stderr, "Couldnt create the level!\n"); 8 // shutdown everything 9 return -1; 10 } 11 fprintf(stderr, "Back to main\n"); 12 player *player; 13 player = create_player(); 14 if(!player) 15 { 16 fprintf(stderr, "Couldnt create the player!\n"); 17 // shutdown everything 18 return -1; 19 } 20 fprintf(stderr, "Back to main2\n"); 21 al_set_new_bitmap_flags(0); 22 printf("Set the flag"); 23 int level_x = SCREEN_W + (2 * first_level->tilesize); 24 int level_y = SCREEN_H + (2 * first_level->tilesize); 25 level_bitmap = al_create_bitmap(level_x, level_y); 26 if(!level_bitmap) 27 { 28 fprintf(stderr, "Couldn't create the level bitmap!\n"); 29 // shutdown everything 30 return -1; 31 } 32 33 //crashes right here 34 int b, c; 35 for(b = 0; b < first_level->size_y; b++) 36 { 37 for(c = 0; c < first_level->size_x; c++) 38 fprintf(stderr, "%i,", first_level->tilemap[b][c]); 39 }

I feel bad for asking so many questions, because I feel that there's just one really stupid thing I'm missing... ???

Edgar Reynaldo

Post your latest load_level function. Either level->size_y or level->size_x is wrong, or you are not allocating level->tilemap correctly.

octotep

Here it is:

#SelectExpand
1level *load_level(int world_num, int level_num) 2{ 3 ALLEGRO_CONFIG *level_file; 4 level *tmp_level = malloc(sizeof(level *)); 5 if(tmp_level == NULL) 6 { 7 fprintf(stderr, "Out of memory for the level struct!\n"); 8 return NULL; 9 } 10 printf("Break here!\n"); 11 12 const char *tile_file_name; // for the tiles.bmp level.tile_file 31 13 char level_file_name[27]; // worldxx-levelyy.cfg 27 14 15 // Get all of the data from the level cfg file 16 sprintf(level_file_name, "levels/world%02d-level%02d.cfg", world_num, level_num); 17 level_file = al_load_config_file(level_file_name); 18 tmp_level->size_x = atoi(al_get_config_value(level_file, NULL, "size_x")); 19 tmp_level->size_y = atoi(al_get_config_value(level_file, NULL, "size_y")); 20 tmp_level->start_x = (float) atof(al_get_config_value(level_file, NULL, "start_x")); 21 tmp_level->start_y = (float) atof(al_get_config_value(level_file, NULL, "start_y")); 22 //without this, I can't access tilesize from outside this function... 23 tmp_level->tilesize = (int) malloc(sizeof(int)); 24 tmp_level->tilesize = (int) atoi(al_get_config_value(level_file, NULL, "tile_size")); 25 26 // Get the tile file loaded into the level struct 27 tile_file_name = al_get_config_value(level_file, NULL, "tile_file"); 28 tmp_level->tile_file = al_load_bitmap(tile_file_name); 29 if(!tmp_level->tile_file) 30 { 31 printf("TILE FILE NOT LOADED!\n"); 32 return NULL; 33 } 34 35 36 // Create the tilemap array 37 tmp_level->tilemap = malloc(tmp_level->size_y * sizeof(int *)); 38 if(tmp_level->tilemap == NULL) 39 { 40 fprintf(stderr, "Out of memory for the pointer-pointer-int in the level struct!\n"); 41 return NULL; 42 } 43 int i; 44 for(i = 0; i < tmp_level->size_y; i++) 45 { 46 tmp_level->tilemap[i] = malloc(tmp_level->size_x * sizeof(int)); 47 if(tmp_level->tilemap[i] == NULL) 48 { 49 fprintf(stderr, "Out of memory for the **intergers in the level struct!\n"); 50 return NULL; 51 } 52 } 53 54 55 // Get the tilemap data from the cfg file 56 char *result = NULL; 57 const char *tilemap_data; 58 tilemap_data = al_get_config_value(level_file, NULL, "map_data"); 59 result = strtok((char *)tilemap_data, ","); 60 int x = 0; 61 int y = 0; 62 63 while (result != NULL) 64 { 65 tmp_level->tilemap[y][x] = atoi(result); 66 while(x < tmp_level->size_x) 67 { 68 tmp_level->tilemap[y][x] = atoi(result); 69 result = strtok(NULL, ","); 70 x++; 71 } 72 x = 0; 73 result = strtok(NULL, ","); 74 y++; 75 } 76 77 int b, c; 78 for(b = 0; b < tmp_level->size_y; b++) 79 { 80 for(c = 0; c < tmp_level->size_x; c++) 81 fprintf(stderr, "%i,", tmp_level->tilemap[b][c]); 82 } 83 84 al_destroy_config(level_file); 85 printf("%i\n", tmp_level->tilesize); 86 fprintf(stderr, "~~CREATE LEVEL - DONE~~\n"); 87 return tmp_level; 88}

Edgar Reynaldo
octotep said:

level *tmp_level = malloc(sizeof(level *));

That should be level* tmp_level = malloc(sizeof(level));, like you had it before. You're only allocating enough memory to hold a pointer.

octotep said:

  //without this, I can't access tilesize from outside this function...
//  tmp_level->tilesize = (int) malloc(sizeof(int));
  tmp_level->tilesize = atoi(al_get_config_value(level_file, NULL, "tile_size"));

The line I commented out (the second one) is not good C. You allocate an integer's worth of memory and then cast that address to an integer - it's value would likely be huge, and totally incorrect. The third line there is correct.

octotep said:

#SelectExpand
1 tilemap_data = al_get_config_value(level_file, NULL, "map_data"); 2 result = strtok((char *)tilemap_data, ","); 3 int x = 0; 4 int y = 0; 5 6 while (result != NULL) 7 { 8// tmp_level->tilemap[y][x] = atoi(result);// this is not necessary 9 while(x < tmp_level->size_x) 10 { 11 tmp_level->tilemap[y][x] = atoi(result); 12 result = strtok(NULL, ","); 13 x++; 14 } 15 x = 0; 16// result = strtok(NULL, ",");// You're skipping a token here 17 y++; 18 }

I commented out two lines - the first commented line is unnecessary and is overwritten by your second assignment, and the second commented line is a mistake, because it would skip one of your values.

octotep

Thank you, it works perfectly! :D

Edgar Reynaldo

Glad to hear it. Got a screenshot you could show us?

octotep

Here's one. Unfortunately I'm not the best artist, so all I have right now is a stick figure for testing purposes. ;D
{"name":"screenshot.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/6\/069bfb2e47ac9abeeb5ce934152edd50.jpg","w":646,"h":512,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/6\/069bfb2e47ac9abeeb5ce934152edd50"}screenshot.jpg

Edgar Reynaldo

Well, your basic ground tile looks good. It blends perfectly with the tiles next to it.

Thread #607045. Printed from Allegro.cc