Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Allegro5 Cant get Tilemaps to work.

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Allegro5 Cant get Tilemaps to work.
Kris Asick
Member #1,424
July 2001

  _tile_sheet = VZ_LoadBitmap("Textures","vz_tiles_1.png",ALLEGRO_VIDEO_BITMAP|ALLEGRO_MIN_LINEAR|ALLEGRO_MAG_LINEAR|ALLEGRO_NO_PREMULTIPLIED_ALPHA);
  if (_tile_sheet == NULL) FatalErrorMsg(8,display);
  for (z = 0; z < VZ_MAX_FRAMES; z++)
    if ((tile_bmp[z] = al_create_sub_bitmap(_tile_sheet,(z%51)*20+2,(z/51)*20+2,16,16)) == NULL) FatalErrorMsg(9,display);

This is my tile loading code. Typically, you want to modulo one coordinate by the number of tiles per col/row, and divide the other. In my case, each column goes up by 1 and each row by 51, so I modulo the X by 51 and divide the Y by 51, then just multiply each by the space between each tile. 8-)

I also extend my tiles by 2 pixels in both directions since I have to be prepared to scale them. In fact, this a good practice to do with ALL 2D graphics using hardware acceleration that need to be joined together out of pieces, like status bars and whatnot.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Audric
Member #907
January 2001

Kris, I see you use things like FatalErrorMsg(8,display); apparently with 8 or 9 to get information about the point where the problem was raised.
In case you don't know, compilers provide macros like _FILE_ and _LINE_ that expand into source filename and line number.
This allows writing macros like

#define FATAL_ERR Error_handler(__FILE__, __LINE__)

Then you can use the macro any number of time, each occurence will pass a different filename + line number.

Edit: GCC additionally provides _func_ which is the function's name.

Angeljruiz
Member #14,553
September 2012

Thats understandable kris :p Thanks for introducing me to a interesting concept tho :D

@Enclave what do you mean?

Kris Asick
Member #1,424
July 2001

Audric said:

In case you don't know, compilers provide macros like FILE and LINE that expand into source filename and line number.

Didn't know that... but it wouldn't really help me much anyways since I can actually use the MSVC10 debugger with A5 projects and the FatalErrorMsg() routine I developed is intended for end-users to know what went wrong if something does go wrong in the completed product. ;)

My only problem at the moment is that the popups produced by the FatalErrorMsg() routine are appearing BEHIND the Allegro window, and when I try to shut the program down with an exit() call it's turning Allegro off before calling my additional uninitialization routines, which crashes the program. Meh, I'll figure out how to make that all work soon enough, it's not a high priority right now. :P

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Raidho36
Member #14,628
October 2012
avatar

Why don't use allegro native dialogs? They work fine. Unless there's a crash already happened, of course.

Kris Asick
Member #1,424
July 2001

Raidho36 said:

Why don't use allegro native dialogs? They work fine. Unless there's a crash already happened, of course.

I am. :(

void FatalErrorMsg (int errornum, ALLEGRO_DISPLAY *display)
{
  if (display != NULL) al_show_mouse_cursor(display);
  al_show_native_message_box(display, "Vectorzone - Fatal Error", _errormsg[errornum], NULL, NULL, ALLEGRO_MESSAGEBOX_ERROR);
  exit(1);
}

--- Kris Asick (Gemini)
--- http://www.pixelships.com

EnClave
Member #14,661
October 2012

this is my code to load tiles right now,

BlockSize = 64

#SelectExpand
1 2void LoadMap(const char *filename, std::vector< std::vector <int> > &map) 3{ 4 std::ifstream openfile(filename); 5 if(openfile.is_open()) 6 { 7 std::string line, value; 8 int space; 9 10 while(!openfile.eof()) 11 { 12 std::getline(openfile, line); 13 14 if(line.find("[TileSet]") != std::string::npos) 15 { 16 state = TileSet; 17 continue; 18 } 19 else if (line.find("[Map]") != std::string::npos) 20 { 21 state = Map; 22 continue; 23 } 24 25 switch(state) 26 { 27 case TileSet: 28 if(line.length() > 0) 29 tileSet = al_load_bitmap(line.c_str()); 30 break; 31 case Map: 32 std::stringstream str(line); 33 std::vector<int> tempVector; 34 35 while(!str.eof()) 36 { 37 std::getline(str, value, ' '); 38 if(value.length() > 0) 39 tempVector.push_back(atoi(value.c_str())); 40 } 41 map.push_back(tempVector); 42 break; 43 } 44 } 45 } 46 else 47 { 48 } 49} 50 51 52 53 //%%%%% RITAR UPP TILES %%%%%// 54 55void DrawMap(std::vector <std::vector <int> > map) 56{ 57 for(int i = 0; i < map.size(); i++) 58 { 59 for(int j = 0; j < map[i].size(); j++) 60 { 61al_draw_bitmap_region(tileSet, map[i][j] * BlockSize, 0, BlockSize, 64, j * BlockSize, 62 i * BlockSize, NULL); 63 } 64 } 65}

and I'm kind of loading the pngs from the .txt files, like this:

[TileSet]
test.png
[Map]
3 3 3 5 5 5 5 5 5
3 3 3 5 5 5 5 5 5
4 3 3 5 5 5 5 5 5

my problem is tho that in my Tilesheet my program can only load tiles horizontal right now my .png file is 1088x64 because it can only load horizontal but now i have runned out of space in the .png file, i want it to be example 1088x128 and the program can load the tiles on the second row aswell. :-/

Angeljruiz
Member #14,553
September 2012

Well in my code i fix that by keeping the x value and increasing it every time it reads a value and once it gets to the maximum tiles per row or whatever i reset it to 0 then increment the y value. Why dont you just do that ? :p
(obviously im not very good at explaining)

EnClave
Member #14,661
October 2012

The thing was i couldent implement your "Loading maps code" into my own code and i dont want to like straight copy your code because i dont recognize anything there hehe, hmm i really have water above my head right now, this is extremly complicated i might need to change this code, because i followed some guys tutorial but i dont understand it so well, damn, i just want a nice working Mapload function :(

Angeljruiz
Member #14,553
September 2012

But mine is so much simpler than yours, albeit maybe a little bit more cryptic looking X)
Heres a deep explaination of my code
To keep track of all the tiles i just use a simple 2d array of ints

int tiles[40][30];

I then open up a file then keep looping until it is the end of the file, keeping track of how many values have been stored, once 40 values (the number of how many tiles per row) has been stored it must mean that its time to increase the y value because all the tiles in that row are filled up.

//openfile bla bla bla
while (File >> temp) //loops until end
{
  Tiles[x][y] = temp;
  x++; //next tile in the row
  if (x == TILES_PER_ROW /*40*/) //all the rows are filled up
  {
    x = 0; //reset it
    y++; //next column
  }
}

Then, as ive already explained, i just make a bitmap out of the tiles then i just draw the bitmap as you would with any other bitmap.
Im not saying this is the best way to do this but its definately a good way to start off and get a feel of things.
Also i didnt compile this code, its only for example so if there are anything syntax errors thats why

EnClave
Member #14,661
October 2012

Yeah, actully i borrowed your code and implemented in my code, it runs good but now it just creates a bitmap and only using the:

BitTile = al_create_bitmap(800, 600);

so it doesent matter what i do in my .txt document it takes like the first tile in my png file and just copys it to 800 x 600, here is a screenshot

http://i.imgur.com/g7NkN.jpg

do you know why it does that?

Angeljruiz
Member #14,553
September 2012

Emm im not sure, maybe bad input? I know when you give bad input it just keeps repeating the last good input. Also check the updateBitMap function and make sure its actually drawing the tile that the input corrisponds to.

EnClave
Member #14,661
October 2012

Yeah this is extremly wierd can it have something to do with i changed your [40][30] to [100][100] because i want to make bigger maps?

anyway with some touching of the code i end up with this,

http://i.imgur.com/qq0KG.jpg

also there is the png file im using and also the update code, hmm

Kris Asick
Member #1,424
July 2001

One of the ways I debug a problem like this is to actually do all the logic, step by step, in my head, following along in my code. You can either do this in a forwards motion to determine what the result should be, or a backwards motion to determine what you need to start with to get the result you want.

However, I just noticed something obvious: You're only going up by increments of 32 when pulling tile references, not 64 like your tile sizes are. :P

I also noticed that tile #0 is a brick wall. Usually it's best to make tile #0 your empty, undefined tile for sake of if statements. ;)

--- Kris Asick (Gemini)
--- http://www.pixelships.com

EnClave
Member #14,661
October 2012

I actully havent had any luck on the Working TileMap yet, its still doesent update as it should do, it only creates a wierd big Tile of 800, 600 because its set like that in the BitTile = al_create_bitmap(800, 600);

Its extremly wierd, i dont know what to do anymore ive been experimenting with my code changed alot of values, switching locations of the updates but still nothing, just does the same thing, if anyone with sharper eyes and knowledge could spot something out i would really appreciate it, been working with this for 2 days now withouth any luck, also when i have Screen scrolling on my Game my Mouse event doesent work either, it works fine if i stay in place in the beginning of the game but when i start to move it doesent update as it should so it just lacks behind all the time, here is my code if anyone have the time to just look over it a quickie! :)

#SelectExpand
1 2#include<fstream> 3#include<string> 4#include<sstream> 5#include<iostream> 6#include<allegro5\allegro5.h> 7#include<allegro5\allegro_native_dialog.h> 8#include<allegro5\allegro_primitives.h> 9#include<allegro5\allegro_image.h> 10 11using namespace std; 12 13int loadmap(int Tiles[][30]); 14void updateBitTile(int Tiles[][30], ALLEGRO_BITMAP* BitTile, ALLEGRO_BITMAP* tiles, ALLEGRO_DISPLAY* display); 15bool Collision(int Tiles[][30], const int& x, const int& y); 16 17 18#define ScreenWidth 1024 19#define ScreenHeight 768 20 21int pos_y = ScreenWidth / 2; 22int pos_x = ScreenHeight / 2; 23 24 25// %%%%% COLLISION OF MOVEMENT HITTING BOX %%%%%// 26bool Collision(float x, float y, float ex, float ey, int width, int height) 27{ 28 if(x + width < ex || x > ex + width || y + height < ey || y > ey + height) 29 { 30 return false; 31 } 32 return true; 33} 34 35int state = NULL; 36 37// %%%%% CAMERA SCROLLING %%%%%// 38 39void cameraUpdate(float *cameraPosition, float x, float y, int width, int height) 40{ 41 cameraPosition[0] = -(ScreenWidth / 2) + (x + width / 2); 42 cameraPosition[1] = -(ScreenWidth / 2) + (y + height / 2); 43 44 if(cameraPosition[0] < 0) 45 cameraPosition[0] = 0; 46 if(cameraPosition[1] < 0) 47 cameraPosition[1] = 0; 48 49} 50 51 52int main() 53{ 54 // %%%%% IMPORTANT SETTINGS %%%%%// 55 ALLEGRO_DISPLAY *display; 56 const float FPS = 60.0; 57 const float frameFPS = 10.0; 58 enum Direction { DOWN, LEFT, RIGHT, UP }; 59 60 // %%%%% ERROR CODES, ALLEGRO AND DISPLAY %%%%%// 61 if(!al_init()) 62 al_show_native_message_box(NULL, "Error", NULL, "Could not Initialize Allegro", NULL, NULL); 63 64 display = al_create_display(ScreenWidth, ScreenHeight); 65 66 if(!display) 67 al_show_native_message_box(NULL, "Error", NULL, "Could not create Allegro Display", NULL, NULL); 68 69 70 // %%%%% WINDOW SETTINGS %%%%%// 71 72 al_set_new_display_flags(ALLEGRO_WINDOWED); 73 al_set_window_position(display, 200, 200); 74 al_set_window_title(display, "PRE-alpha Test"); 75 76 ALLEGRO_COLOR playerColor = al_map_rgb(255, 0, 255); 77 78 // %%%%% Movement SPEED %%%%%// 79 bool done = false, draw = true, active = false; 80 float x = 512, y = 384, moveSpeed = 3; 81 int dir = DOWN, sourceX = 64, sourceY = 96; 82 float cameraPosition[2] = { 0, 0 }; 83 84 // %%%%% ADDONS %%%%%// 85 al_init_primitives_addon(); 86 al_install_keyboard(); 87 al_init_primitives_addon(); 88 al_install_mouse(); 89 al_init_image_addon(); 90 91 92 // %%%%% PNGS AND OTHER THINGS TO INSTALL %%%%%// 93 94 ALLEGRO_EVENT_QUEUE* queue = NULL; 95 ALLEGRO_BITMAP *enemy1 = al_load_bitmap("Zanm1.png"); 96 ALLEGRO_BITMAP *player = al_load_bitmap("player.png"); 97 al_convert_mask_to_alpha(player, al_map_rgb(255, 0, 255)); 98 al_convert_mask_to_alpha(enemy1, al_map_rgb(255, 0, 255)); 99 100 queue = al_create_event_queue(); 101 ALLEGRO_KEYBOARD_STATE KeyState; 102 ALLEGRO_TRANSFORM camera; 103 ALLEGRO_BITMAP* BitTile = NULL; 104 ALLEGRO_BITMAP* tiles = NULL; 105 106 107 tiles = al_load_bitmap("test.png"); 108 if (!tiles) 109 { 110 cout << "Bad Tiles.png\n"; 111 return -1; 112 } 113 114 int Counter = 0; 115 int OffsetX = 0; 116 int OffsetY = 0; 117 118 int Tiles[40][30]; 119 120 for (int x = 0; x < 40; ++x) 121 { 122 for (int y = 0; y < 30; ++y) 123 { 124 Tiles[x][y] = 0; 125 } 126 } 127 128 if (loadmap(Tiles) == -1) 129 { 130 return -1; 131 } 132 BitTile = al_create_bitmap(800, 600); 133 134 updateBitTile(Tiles, BitTile, tiles, display); 135 136 137 138 // %%%%% EVENTS installation & TIMERS %%%%%// 139 ALLEGRO_TIMER *timer = al_create_timer(1.0 / FPS); 140 ALLEGRO_TIMER *frametimer = al_create_timer(1.0 / frameFPS); 141 142 ALLEGRO_EVENT_QUEUE *event_queue = al_create_event_queue(); 143 al_register_event_source(event_queue, al_get_keyboard_event_source()); 144 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 145 al_register_event_source(event_queue, al_get_timer_event_source(frametimer)); 146 al_register_event_source(event_queue, al_get_display_event_source(display)); 147 al_register_event_source(event_queue, al_get_mouse_event_source()); 148 149 // %%%%% TIMER, NO installations UNDER THIS %%%%%// 150 al_start_timer(timer); 151 al_start_timer(frametimer); 152 153 // %%%%% Beginning of Events %%%%%// 154 while(!done) 155 { 156 ALLEGRO_EVENT events; 157 al_wait_for_event(event_queue, &events); 158 al_get_keyboard_state(&KeyState); 159 160 // %%%%% TILE MAP IN THE EVENT & TIMER CODE %%%%%// 161 162 if(events.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 163 { 164 done = true; 165 } 166 else if (events.type == ALLEGRO_EVENT_TIMER) 167 { 168 169 } 170 171 // %%%%% KEYBOARD INPUT AND EVENTS AND PLAYER IMAGE AND CAMERA SCROLLING FOR CHARACTER %%%%%// 172 173 if(events.type == ALLEGRO_EVENT_KEY_UP) 174 { 175 switch(events.keyboard.keycode) 176 177 { 178 case ALLEGRO_KEY_ESCAPE: 179 done = true; 180 } 181 } 182 183 184 else if(events.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 185 { 186 done = true; 187 } 188 189 // %%%%% MOUSE %%%%%// 190 else if(events.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) 191 192 { 193 if(events.mouse.button & 1) 194 draw = !draw; 195 else if (events.mouse.button & 2) 196 draw = !draw; 197 } 198 199 else if(events.type == ALLEGRO_EVENT_MOUSE_AXES) 200 { 201 pos_x = events.mouse.x; 202 pos_y = events.mouse.y; 203 } 204 205 // %%%%% KEYBOARD %%%%%// 206 else if (events.type = ALLEGRO_EVENT_TIMER) 207 { 208 if(events.timer.source == timer) 209 { 210 active = true; 211 if(al_key_down(&KeyState, ALLEGRO_KEY_S)) 212 { 213 y += moveSpeed; 214 dir = DOWN; 215 } 216 else if(al_key_down(&KeyState, ALLEGRO_KEY_W)) 217 { 218 y -= moveSpeed; 219 dir = UP; 220 } 221 else if(al_key_down(&KeyState, ALLEGRO_KEY_D)) 222 { 223 x += moveSpeed; 224 dir = RIGHT; 225 } 226 else if(al_key_down(&KeyState, ALLEGRO_KEY_A)) 227 { 228 x -= moveSpeed; 229 dir = LEFT; 230 } 231 232 else 233 active = false; 234 235 if(Collision(x, y, 400, 400, 32, 32)) 236 { 237 if(dir == 0) 238 y -= moveSpeed; 239 else if(dir == 1) 240 x += moveSpeed; 241 else if(dir == 2) 242 x -= moveSpeed; 243 else if(dir == 3) 244 y += moveSpeed; 245 } 246 247 248 cameraUpdate(cameraPosition, x, y, 96, 64); 249 al_identity_transform(&camera); 250 al_translate_transform(&camera, -cameraPosition[0], -cameraPosition[1]); 251 al_use_transform(&camera); 252 253 } 254 255 256 else if(events.timer.source == frametimer) 257 { 258 259 if(active) 260 sourceX += al_get_bitmap_width(player) / 4; 261 262 else 263 sourceX = 64; 264 265 if(sourceX >= al_get_bitmap_width(player)) 266 sourceX = 0; 267 268 sourceY = dir; 269 } 270 271 draw = true; 272 } 273 274 275 if(al_event_queue_is_empty(queue) &&draw) 276 277 { 278 279 al_clear_to_color(al_map_rgb(0, 0, 0)); 280 al_draw_bitmap(BitTile, 0-OffsetX, 0-OffsetY, NULL); 281 al_draw_bitmap_region(enemy1, 0, 0, 92, 150, 400, 400, NULL); 282 al_draw_bitmap_region(player, sourceX, dir * al_get_bitmap_height(player) / 4, 64, 96, x, y, NULL); 283 al_draw_filled_rectangle(pos_x, pos_y, pos_x + 30, pos_y + 30, al_map_rgb(150, 150, 150)); 284 285 al_flip_display(); 286 } 287 288 289 290 // %%%%% GAME UI SHELL %%%%%// 291 /*al_draw_rectangle(1, 1, 800, 100, al_map_rgb(255, 50, 50), 9.0);*/ 292 293 // %%%%% Destroy ENDING %%%%%// 294 } 295 al_destroy_display(display); 296 al_destroy_timer(timer); 297 al_destroy_bitmap(player); 298 al_destroy_bitmap(enemy1); 299 al_destroy_event_queue(event_queue); 300 al_destroy_bitmap(tiles); 301 al_destroy_bitmap(BitTile); 302 303 return 0; 304} 305 306int loadmap(int Tiles[][30]) 307{ 308 int x(0), y(0); 309 int temp; 310 ifstream Map("Map1.txt"); 311 if (Map.is_open()) 312 { 313 while(Map >> temp) 314 { 315 Tiles[x][y] = temp; 316 ++x; 317 if (x == 40) 318 { 319 x = 0; 320 ++y; 321 } 322 } 323 } else { 324 cout << "Bad Map1.txt\n"; 325 return -1; 326 } 327 Map.close(); 328 return 0; 329} 330 331void updateBitTile(int Tiles[][30], ALLEGRO_BITMAP* BitTile, ALLEGRO_BITMAP* tiles, ALLEGRO_DISPLAY* display) 332{ //creates a bitmap from tiles instead of drawing all tiles seperately, fucking awesome ryte? 333 al_set_target_bitmap(BitTile); 334 for (int x = 0; x < 40; ++x) 335 { 336 for (int y = 0; y < 30; ++y) 337 { 338 /*switch (Tiles[x][y]) 339 { 340 case 0: 341 al_draw_bitmap_region(tiles, 0, 0, 32, 32, x*32, y*32, NULL); 342 break; 343 case 1: 344 al_draw_bitmap_region(tiles, 32, 0, 32, 32, x*32, y*32, NULL); 345 break; 346 } */ 347 al_draw_bitmap_region(tiles, Tiles[x][y]*32, 0, 32, 32, x*32, y*32, NULL); 348 } 349 } 350 al_set_target_bitmap(al_get_backbuffer(display)); 351 352 // al_save_bitmap("Screenshot.png", BitTile); 353} 354bool Collision(int Tiles[][30], const int& x, const int& y) 355{ 356 if (Tiles[x][y] == 0) 357 return true; 358 return false; 359}

Kris Asick
Member #1,424
July 2001

When I get EXTREMELY stuck with a problem like this, I like to add keyboard-sensitive stepping in my code.

In your case, what this would mean is adding some routines to your tilemap rendering code so that it only draws one tile, shows the result on-screen, then waits for you to press a key. Then it draws the next tile, waits for a keypress, repeat until you press a specific key to signal the program to stop running.

This would at least let you visually see how your tiles are being rendered one by one and you may be able to tell what the trouble is as a result.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

J-Gamer
Member #12,491
January 2011
avatar

You don't need extra code to do that, just a debugger :D

" There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo
"If your body was a business, thought would be like micro-management and emotions would be like macro-management. If you primarily live your life with emotions, then you are prone to error on the details. If you over-think things all the time you tend to lose scope of priorities." - Mark Oates

 1   2 


Go to: