Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Sand Game Help

This thread is locked; no one can reply to it. rss feed Print
Sand Game Help
Bingocat
Member #15,424
December 2013

I'm a beginner to c++ and allegro, so the code is bad. Whenever the amount of sand gets near or above 2000 the game freezes. Is there a better way to do collision with it?

#SelectExpand
1#include <allegro5\allegro.h> 2#include <allegro5\allegro_primitives.h> 3#include <allegro5\allegro_font.h> 4#include <allegro5\allegro_ttf.h> 5 6int width = 640; 7int height = 480; 8 9struct Particle 10{ 11 int x; 12 int y; 13 int prevX; 14 int prevY; 15 bool active; 16 bool collision; 17}; 18 19void InitSand(Particle sand[], int maxSand); 20void NewSand(Particle sand[], int maxSand, int x, int y, int &sandNum); 21void UpdateSand(Particle sand[], int maxSand); 22void DrawSand(Particle sand[], int maxSand); 23void CollideSand(Particle sand[], int maxSand); 24 25ALLEGRO_FONT *font18 = NULL; 26 27int main() { 28 int FPS = 60; 29 bool done = false; 30 bool redraw = true; 31 const int maxSand = 10000; 32 Particle sand[maxSand]; 33 int mouseX; 34 int mouseY; 35 bool mouseHold = false; 36 int sandNum = 0; 37 38 al_init(); 39 al_init_primitives_addon(); 40 al_init_font_addon(); 41 al_init_ttf_addon(); 42 al_install_mouse(); 43 InitSand(sand, maxSand); 44 45 ALLEGRO_DISPLAY *display = NULL; 46 ALLEGRO_EVENT_QUEUE *event_queue = NULL; 47 ALLEGRO_TIMER *timer = NULL; 48 49 display = al_create_display(width, height); 50 event_queue = al_create_event_queue(); 51 timer = al_create_timer(1.0 / FPS); 52 font18 = al_load_font("arial.ttf", 18, 0); 53 54 al_register_event_source(event_queue, al_get_display_event_source(display)); 55 al_register_event_source(event_queue, al_get_mouse_event_source()); 56 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 57 58 al_start_timer(timer); 59 60 61 while (!done) { 62 ALLEGRO_EVENT ev; 63 al_wait_for_event(event_queue, &ev); 64 65 if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 66 done = true; 67 else if (ev.type == ALLEGRO_EVENT_TIMER) { 68 redraw = true; 69 70 for (int i = 0; i < maxSand; i++) { 71 if (sand[i].active) { 72 sand[i].prevX = sand[i].x; 73 sand[i].prevY = sand[i].y; 74 } 75 } 76 77 UpdateSand(sand, maxSand); 78 CollideSand(sand, sandNum); 79 } 80 else if (ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) { 81 if (ev.mouse.button == 1) 82 mouseHold = true; 83 else if (ev.mouse.button == 2) { 84 InitSand(sand, maxSand); 85 sandNum = 0; 86 } 87 } 88 else if (ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) { 89 if (ev.mouse.button == 1) 90 mouseHold = false; 91 } 92 else if (ev.type == ALLEGRO_EVENT_MOUSE_AXES) { 93 mouseX = ev.mouse.x; 94 mouseY = ev.mouse.y; 95 } 96 97 if (mouseHold) { 98 NewSand(sand, maxSand, mouseX, mouseY, sandNum); 99 } 100 101 if (redraw && al_is_event_queue_empty(event_queue)) { 102 redraw = false; 103 104 al_draw_textf(font18, al_map_rgb(255, 255, 255), 0, 100, 0, "Amout of sand: %i %i %i", sandNum, mouseX, mouseY); 105 DrawSand(sand, maxSand); 106 al_flip_display(); 107 al_clear_to_color(al_map_rgb(0,0,0)); 108 } 109 } 110 111 al_destroy_display(display); 112 al_destroy_event_queue(event_queue); 113 al_destroy_timer(timer); 114 return 0; 115} 116 117void InitSand(Particle sand[], int maxSand) { 118 for (int i = 0; i < maxSand; i++) { 119 sand[i].active = false; 120 sand[i].x = 0; 121 sand[i].y = 0; 122 sand[i].collision = false; 123 } 124} 125void NewSand(Particle sand[], int maxSand, int x, int y, int &sandNum) { 126 for (int t = 0; t < 5; t++) { 127 for (int i = 0; i < maxSand; i++) { 128 if (!sand[i].active) { 129 sand[i].x = x + rand() % 10 - 5; 130 sand[i].y = y + rand() % 10 - 5; 131 sand[i].active = true; 132 sandNum++; 133 break; 134 } 135 } 136 } 137} 138void UpdateSand(Particle sand[], int maxSand) { 139 for (int i = 0; i < maxSand; i++) { 140 if (sand[i].active) { 141 sand[i].y += 1; 142 } 143 } 144} 145void DrawSand(Particle sand[], int maxSand) { 146 for (int i = 0; i < maxSand; i++) { 147 if (sand[i].active) { 148 al_draw_pixel(sand[i].x, sand[i].y, al_map_rgb(255, 195, 33)); 149 //al_draw_filled_rectangle(sand[i].x, sand[i].y, sand[i].x + 5, sand[i].y + 5, al_map_rgb(255, 195, 33)); 150 } 151 } 152} 153 154void CollideSand(Particle sand[], int maxSand) { 155 for (int i = 0; i < maxSand; i++) { 156 if (sand[i].y >= height) 157 sand[i].y = height; 158 if (sand[i].active) { 159 for (int j = 0; j < maxSand; j++) { 160 if (sand[j].active && i != j) { 161 if (sand[i].x == sand[j].x && sand[i].y == sand[j].y) { 162 if (sand[i].prevY <= sand[j].y) 163 sand[i].y = sand[j].y - 1; 164 } 165 } 166 } 167 } 168 } 169}

hyreia77
Member #13,742
November 2011

I see two main issues: yes the collision and the other is the drawing. Let's tackle the drawing first. That's a slightly easier fix.

You're drawing 10,000 pixels to the screen 60 times a second.
Drawing individual pixels is surprisingly slow this way. You're making 10,000 calls to whatever is drawing your screen in under 1/60th of a second.
Solution:
First: use al_put_pixel(). The difference is al_draw_pixel uses current blender and transformation settings. If you're just trying to put pixels use that.
Second: al_lock_bitmap() your target bitmap before you start drawing the pixels then al_unlock_bitmap() it when you're finished. That holds off all drawing to that until it's unlocked, so it can do it in one batch (theoretically anyway).

Now, the collision is much more complicated: you're testing 10,000 objects against 9,999 other objects. That's 99,990,000 tests I think. If all you're doing is stopping the sand from falling when it encounters more sand, instead consider just testing the next pixel it might move to to see if it's sand colored. al_get_pixel, but be sure to lock the bitmap before you start this process for the same reason.
If you're going to reuse that color, I would instead draw all the sand to a "sand bitmap" that is clear other than sand, then draw that to the buffer.

This is from my experience, maybe try that and see if anyone comes along to tell you otherwise.

Go to: