|
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 ############################################## 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... >-----------------------------------------< 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
|
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 ======================= |
Dizzy Egg
Member #10,824
March 2009
|
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 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.
---------------------------------------------------- |
AmnesiA
Member #15,195
June 2013
|
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. ======================= |
LennyLen
Member #5,313
December 2004
|
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
|
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
|
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. ======================= |
Thomas Fjellstrom
Member #476
June 2000
|
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). -- |
LennyLen
Member #5,313
December 2004
|
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
|
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. 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
|
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() 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)... 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}
--- |
|