Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Drag and Drop system and TileMap

This thread is locked; no one can reply to it. rss feed Print
Drag and Drop system and TileMap
Alexandre Bencz
Member #15,257
August 2013

I'm try to create a TileMap system... for this, I get that sample:

http://wiki.allegro.cc/index.php?title=Tilemap_Example

But, that sample is very confusing for me... so, How i can make for the allegro recognize the matrix in screen... for example:

sample.map

##############################################
##############################################
##############################################
#########$$###################################
##############################################
######$$###$$#################################
#2############################################
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

So, the system to read that file is very very very simple... but, How I can make to game put the correct imagens in correct screen matrix...

What I have thinked...
The game load all the matrix in memory, because, I whant to player walk freely around the map...
So, i think for that, I need to create a "camera" system... beacause at time, my player is fixied on the midle of scren... and I whant he can walk freely on the map...

>-----------------------------------------<
Drag And Drop
How I can make a system for drag and drop imagens inside of game ?
For example, I have one image loaded in game, and, I need to put that image in correct position of screen, how I can make this ?

Or, I can make this using the matrix ideia, using the keyboard to put the image in correct local ? :)

AmnesiA
Member #15,195
June 2013
avatar

You're asking very broad questions that don't necessarily have a "right" answer. The question isn't how is it done, it's how do you want to do it? Personally, I think the easiest way is to use the .map file and iterate through each character and use if-else to find out which object to create.

So let's say you load sample.map into a vector<string> where string[0] = first line, string[1] = second line, and so on until you reach eof. You could just go

//load sample.map into vector<string> map_string;
for( int i = 0; i != map_string.end(); ++i){           //iterate through each string
    for( int j = 0; j != map_string[i].length(); ++j){ //iterate through each character
        //Assumes 32x32 tileset
        int x_loc = j*32; //x location to create this tile
        int y_loc = i*32; //y location to create this tile
        if( c == '#'){ //Probably actually requires doing nothing
            create_tile( Background_Tile, x_loc, y_loc);
        }else if( c == '$'){
            create_tile( Block_Tile, x_loc, y_loc);
        }else if( c == '2'){
            create_tile( Character, x_loc, y_loc);
        }
    }
}

If you decide to do a drag and drop thing, it will require you to save the maps to a .map file like that anyway so I'd just stick to doing a tilemap like that for now :)

=======================
Website
My first game!

Dizzy Egg
Member #10,824
March 2009
avatar

As part of your question you asked how to represent the different images; your map should define this, so instead of:

#######$#########$##
####################
#$##################
##############$#####

You would have this:

1 1 1 1 4 1 1 3 1 1 1
1 1 1 1 1 1 3 3 1 1 1
1 1 1 1 1 1 1 3 1 1 1
1 1 1 1 4 1 1 1 1 1 1

The in your game loop you would say:

if(tileNumber[x][y] == 1) draw_grass();
if(tileNumber[x][y] == 3) draw_water();
if(tileNumber[x][y] == 4) draw_tree();

If you want a program to build the maps (drag & drop) look at something like Tilestudio or Mappy.

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

AmnesiA
Member #15,195
June 2013
avatar

The only limit to using numbers to represent tiles is that you have no more than 10 tiles. Comparing single characters works the same way but gives you way more options.

=======================
Website
My first game!

LennyLen
Member #5,313
December 2004
avatar

AmnesiA said:

The only limit to using numbers to represent tiles is that you have no more than 10 tiles. Comparing single characters works the same way but gives you way more options.

If you leave a space between them, you have as many different tiles as the size of whatever integer type you use to read them in allows.

Neil Roy
Member #2,229
April 2002
avatar

OR, you can save your maps as BINARY... write your own editor, which I always do first, they're not difficult to create, the just write your tile numbers and other level data (level number, name, description, player start x & Y, enemies etc) to it in binary and load it in as binary.

You'll much happier once you get an editor created that does things exactly as YOU want them done and end up with a smaller level file as well.

My little Deluxe Pacman 2 levels I am working on (I posted the editor in another thread) come out at 1.16K each in size.

AmnesiA
Member #15,195
June 2013
avatar

I don't know how to use binary files, I've been trying to figure it out but I can't find any resources that make sense to me.

If you include a delimiter obviously you can make the numbers as big as you want but I don't see why you'd do that when using a character set you have a uniform width for each object representation and just make it easier to read and write overall.

=======================
Website
My first game!

Thomas Fjellstrom
Member #476
June 2000
avatar

AmnesiA said:

I don't know how to use binary files, I've been trying to figure it out but I can't find any resources that make sense to me.

I think thats the funny part. I had the same issues.. But on a lower level, binary files are much simpler. Instead of thinking that you're saving "text" of some kind, you're storing raw numbers in the file. If you write an 8 bit number, you can read that 8 bit number back. Same goes for 16bit and larger numbers (if you ignore endianess).

Reading/writing raw data means you also don't have to parse the file's contents. Like if you chose to store ascii numbers separated by spaces, you have to specially handle that. With binary, its just one integer after another. very simple.

append: at a low level, a binary file is just an array of bytes. Or if you wish, any larger multiple of 8bits (so long as you don't go for a really strange non multiple of 8bits format, that would make things significantly more complicated for no good reason).

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

LennyLen
Member #5,313
December 2004
avatar

Binary file types are fairly easy once you get used to them, but they can be a bit of a pain until you've written an editor as they're not as easy to hand edit as text files. I usually stick with text files until the program is finished and then convert to a binary format.

edit:

I did start writing a tutorial on using Allegro 4 to read and write multi-platform binary files, but stopped halfway when I decided to switch to A5. I'm pretty certain I still have the A4.9 code I wrote for the tutorial around somewhere, so maybe I'll try to update/finish the tutorial.

Winfield
Member #15,244
July 2013
avatar

I have a bit of a predilection for plaintext formats, which I justify like so:

1) Even with binary save/resource formats, anyone who wants to cheat by editing the files can.
2) Unless my software is so unpopular that no one uses it.

I'd stick with plaintext even for something with an online component - all the popular MMOs have (multiple) communities devoted to extracting and unpacking their datafiles and mining them for interesting information. Security shouldn't be clientside, and online or offline using binary formats only serves to increase debugging complexity while excluding a portion of my users.

Neil Roy
Member #2,229
April 2002
avatar

Here's my save and load functions for my Deluxe Pacman 2 level editor (Pace2) which I posted in another thread. I don't know if it's the best way to do it, but it's the way I do it and it works perfectly for me. ;)

My loadmap() function uses Allegro 5 functions like al_fgetc() but not my save function for some odd reason, I may simply not have gotten around to it.
Edit: Just quickly rewrote it to use Allegro 5 functions, don't know how I missed this the first time around. See, it pays to help people! ;)

As you can see, you simply write your data to the file, then read in back in the same order. When you write a 2, a 2 goes into the file for example (not a text "2" but an actual number 2, not readable by text editors. Open up the file in a hex editor and you'll see a 2 where you wrote a 2 etc... pure binary, no waste of space and no time wasted parsing text. It is most definitely easier in my opinion.

I commented the loadmap() function to give an idea what is going on, it's quite simple as you can see. No parsing, just load and go.

This is also all in pure C (I use -std=c11, the 2011 C standard)...

#SelectExpand
1// returns true if loaded properly 2bool loadmap(ALLEGRO_DISPLAY *display, LEVEL *level) 3{ 4 const char *filename = NULL; 5 ALLEGRO_FILECHOOSER *file_dialog = NULL; 6 7 // normally we're loading from the data file, switch to normal 8 // interface so we can load from the disk 9 al_set_standard_file_interface(); 10 11 file_dialog = al_create_native_file_dialog("//.", "Load Level", "*.dp2", 12 ALLEGRO_FILECHOOSER_FILE_MUST_EXIST); 13 if(!file_dialog) { 14 return false; 15 } 16 17 if(!al_show_native_file_dialog(display, file_dialog)) { 18 if(file_dialog) { 19 al_destroy_native_file_dialog(file_dialog); 20 } 21 return false; 22 } 23 24 filename = al_get_native_file_dialog_path(file_dialog, 0); 25 26 // convert to lower case 27 char lcname[4096] = ""; 28 for(int i=0; i<strlen(filename); i++) { 29 lcname[i] = tolower(filename[i]); 30 } 31 32 ALLEGRO_FILE *file = NULL; 33 34 file = al_fopen(lcname, "rb"); 35 if(file == NULL) { 36 printf("%s(%d): Error opening \"%s\" for reading.\n", __FILE__, __LINE__, filename); 37 return 0; 38 } 39 40 // The map id's are all the same to identify this as a Deluxe pacman 2 file 41 // In this case, it will always be "Pace2" 42 al_fread(file, &level->map_id, sizeof(char)*strlen(MAP_ID)); 43 level->map_ver = al_fgetc(file); 44 45 // This is the version number of the map, in case it is changed in the 46 // future, the game checks this. A conversion program can be created 47 // to convert levels to a new format by checking this and then converting 48 // it as needed (I done this with the last game and it paid off). 49 if(level->map_ver != MAP_VER || strcmp(level->map_id, MAP_ID) != 0) { 50 printf("%s(%d): Invalid map type or version.\n", __FILE__, __LINE__); 51 return false; 52 } 53 54 // is the level validated (checked for errors by the editor) 55 // if this is true, than we can play the level now, otherwise 56 // it can only be loaded and used by the editor until error free (validated) 57 level->validated = al_fgetc(file); 58 59 // Line set we're using 60 level->line_set = al_fgetc(file); 61 62 // Player starting location (map tile location) 63 level->player.x = al_fgetc(file); 64 level->player.y = al_fgetc(file); 65 66 // Four ghost starting locations (each has it's own) 67 for(int i = 0; i < 4; i++) { 68 level->ghost[i].x = al_fgetc(file); 69 level->ghost[i].y = al_fgetc(file); 70 } 71 72 // pickup spawn location 73 level->pickup.x = al_fgetc(file); 74 level->pickup.y = al_fgetc(file); 75 76 // background tile # to use 77 level->background = al_fgetc(file); 78 79 // read the actual map data here 80 for(unsigned char y = 0; y < MAPY; y++) { 81 for(unsigned char x = 0; x < MAPX; x++) { 82 level->map[y][x].tile = al_fgetc(file); 83 level->map[y][x].is_pill = al_fgetc(file); 84 level->map[y][x].is_powerpill = al_fgetc(file); 85 } 86 } 87 88 // Number of pills on this map, used to know when the level is clear 89 al_fread(file, &level->pills, sizeof(unsigned short)); 90 91 // never forget to close the file 92 al_fclose(file); 93 94 if(file_dialog) { 95 al_destroy_native_file_dialog(file_dialog); 96 } 97 98 // Switch back to physfs file we're using 99 al_set_physfs_file_interface(); 100 101 return true; 102} 103 104 105 106// returns true if saved properly 107bool savemap(ALLEGRO_DISPLAY *display, LEVEL *level) 108{ 109 const char *filename = NULL; 110 ALLEGRO_FILECHOOSER *file_dialog = NULL; 111 112 al_set_standard_file_interface(); 113 114 /// TODO: Search folder for levels and set the filename to the next available level # 115 file_dialog = al_create_native_file_dialog(".//", "Save Level", "*.dp2", 116 ALLEGRO_FILECHOOSER_SAVE); 117 if(!file_dialog) { 118 return false; 119 } 120 121 if(!al_show_native_file_dialog(display, file_dialog)) { 122 if(file_dialog) { 123 al_destroy_native_file_dialog(file_dialog); 124 } 125 return false; 126 } 127 128 filename = al_get_native_file_dialog_path(file_dialog, 0); 129 130 // convert to lower case 131 char lcname[4096] = ""; 132 for(int i = 0; i < strlen(filename); i++) { 133 lcname[i] = tolower(filename[i]); 134 } 135 136 ALLEGRO_FILE *file = NULL; 137 138 file = al_fopen(lcname, "wb"); 139 if(file == NULL) { 140 printf("%s(%d): Error opening \"%s\" for writing.\n", __FILE__, __LINE__, lcname); 141 return 0; 142 } 143 144 al_fwrite(file, level->map_id, strlen(level->map_id)); 145 146 al_fputc(file, level->map_ver); 147 al_fputc(file, level->validated); 148 al_fputc(file, level->line_set); 149 al_fputc(file, level->player.x); 150 al_fputc(file, level->player.y); 151 for(int i = 0; i < 4; i++) { 152 al_fputc(file, level->ghost[i].x); 153 al_fputc(file, level->ghost[i].y); 154 } 155 al_fputc(file, level->pickup.x); 156 al_fputc(file, level->pickup.y); 157 al_fputc(file, level->background); 158 for(unsigned char y = 0; y < MAPY; y++) { 159 for(unsigned char x = 0; x < MAPX; x++) { 160 al_fputc(file, level->map[y][x].tile); 161 al_fputc(file, level->map[y][x].is_pill); 162 al_fputc(file, level->map[y][x].is_powerpill); 163 } 164 } 165 al_fwrite(file, &level->pills, sizeof(unsigned short)); 166 167 // never forget to close the file 168 al_fclose(file); 169 170 if(file_dialog) { 171 al_destroy_native_file_dialog(file_dialog); 172 } 173 174 al_set_physfs_file_interface(); 175 176 return true; 177}

Go to: