Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Programm lagging

Credits go to Edgar Reynaldo for helping out!
This thread is locked; no one can reply to it. rss feed Print
Programm lagging
kebapmanager
Member #14,863
January 2013
avatar

When I create about 70 objects on my screen wich are made of rendering and coliding , my "game" starts lagging a bit , but if I push further and create around 128 objects, my game freezes , or only screen does , because in console everything I chechk is working perfectly fine. Is it possible that its lagging because of allegro , or I am just making too much objects on screen and doing too much stuff with them?

taron 
Member #10,584
January 2009
avatar

What version of allegro?
What are your specs?
OS?
DirectX or OpenGL?
Are you printing a lot to the console?

LennyLen
Member #5,313
December 2004
avatar

IN addition to what taron asked, without seeing your code, it's very difficult to tell you what's causing the lag.

kebapmanager
Member #14,863
January 2013
avatar

allegro version 5.0.9
My specs: Intel Core i3 -540 3.07GHz
4,99GB RAM
ATI Radeon HD 4800 ( 2GB graphics memory)

64bit Windows 7 ultimate
directX or OpenGL , huh none? I only use allegro XD I dont understand :S
I print velY and state changing to my console , just to see if player is working and he is , but nothing is happeninig on the sreen , so screen is forzen but game still working ( maybe since I cant test properly , or better then console)

Since I didint even understand directX and openGL question , maybe thats the problem :S since I dont even know how to make my project use one ?

Evert
Member #794
November 2000
avatar

Are you calling al_flip_display()?

kebapmanager
Member #14,863
January 2013
avatar

Yes ofc I am calling flip display :S , maybe code from main could help you guys out?

Edgar Reynaldo
Member #8,592
May 2007
avatar

kebapmanager
Member #14,863
January 2013
avatar

So this is the render code ( I am using list as you can see)
if(render && al_is_event_queue_empty(event_queue))
{
render = false;

//BEGIN PROJECT RENDER================
for(iter = objects.begin(); iter != objects.end(); ++iter)
(*iter)->Render();

//FLIP BUFFERS========================
al_flip_display();
al_clear_to_color(al_map_rgb(255, 255, 255));
}

Render in player class:

int fx = curFrame * frameWidth;
int fy = animationColumns * frameHeight;

al_convert_mask_to_alpha(image, al_map_rgb(255,255, 255));
al_draw_scaled_bitmap(image, fx, fy, frameWidth, frameHeight, x, y, 16, 19, 0);

Render of a Cube ( 128 objects I create):

al_draw_scaled_bitmap(image, 0, 0, 24, 24, x, y, 24, 24, 0);
As far as I understand its probably not problem in rendering, but in soo much objects created , maybe 128 objects is too much for PC even thought I dont uunderstand how can I run 3D games then wich seem khm , far more complex.

Edgar Reynaldo
Member #8,592
May 2007
avatar

128 objects is not that much when using hardware acceleration, trust me, your objects aren't even that complex. It's far more likely a bug in your code somewhere.

Dereferencing a list iterator and an object pointer will take some time, but should not be noticeable yet. If all else fails use a vector instead, especially if the number of objects doesn't change often or you have a fixed limit to the number of them.

One thing is that you should only be calling al_convert_mask_to_alpha once when you load your objects. After that, all the color you specify (white, in your case) will be cleared to zero alpha.

So, you have checked your x and y values? And they are on screen? Everything else you showed looks okay I believe.

kebapmanager
Member #14,863
January 2013
avatar

I know my objects are not complex I mean its only drawing them , thats why this is soo weird to me.

Dereferecing iterators Il try that till tomorow since I have no clue what that does, or how to do that , Il look up on internet about that or something.

I am calling mask to alpha only once now ( when I create images tnx for the tip )

and by chechking x and y values if you mean about player ones , yes they are working fine , its like screen gets forzen at moment I make over 180 objects , and in console whatever I set to cout seems to work , but with delay , and delay of couting gets bigger and bigger , like I move play or tell him to jimp his Y updates like 7 seconds after I clicked , and further I let my program to work delay is longer , even for exiting I must wait over 10 sec.

So it seems like screen is completly forezn , nothing keeps rendering ,but code is still working , with lagg /delay.

Edgar Reynaldo
Member #8,592
May 2007
avatar

kebapmanager
Member #14,863
January 2013
avatar

Here is my hole main.

#SelectExpand
1#include <iostream> 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_image.h> 4#include <allegro5/allegro_primitives.h> 5#include <allegro5/allegro_font.h> 6#include <allegro5/allegro_ttf.h> 7#include <allegro5/allegro_audio.h> 8#include <allegro5/allegro_acodec.h> 9#include <list> 10#include <math.h> 11 12#include "GameObject.h" 13#include "Player.h" 14#include "Cube.h" 15#include "Globals.h" 16 17using namespace std; 18 19//GLOBALS========================================================================== 20Player *player; 21std::list<GameObject *> objects; 22std::list<GameObject *>::iterator iter; 23std::list<GameObject *>::iterator iter2; 24 25bool keys[] = {false, false, false, false, false}; 26enum KEYS{UP, DOWN, LEFT, RIGHT, SPACE}; 27 28int main(int argc, char **argv) 29//SHELL VARIABLESs======================================================================= 30{ 31 bool done = false; 32 bool render = false; 33 34 int xX; 35 int xY; 36 37 player = new Player(); 38 39 ALLEGRO_BITMAP *playerImage = NULL; 40 ALLEGRO_BITMAP *cubeImage = NULL; 41 ALLEGRO_DISPLAY *display = NULL; 42 ALLEGRO_EVENT_QUEUE *event_queue = NULL; 43 ALLEGRO_TIMER *timer; 44//ALLEGRO INIT============================================================== 45 if(!al_init()) //Initialize Allegro 46 return -1; 47 48 display = al_create_display(WIDTH, HEIGHT); //Create our display object 49 50 if(!display) //Test display object 51 return -1; 52//ADDON INSTALL======================================================== 53 al_install_keyboard(); 54 al_init_image_addon(); 55 al_init_font_addon(); 56 al_init_ttf_addon(); 57 al_install_mouse(); 58 al_init_primitives_addon(); 59 60//PROJECT INIT================================ 61 playerImage = al_load_bitmap("Starseed Pilgrim.png"); 62 player->Init(playerImage); 63 al_convert_mask_to_alpha(playerImage, al_map_rgb(255,255, 255)); 64 65 objects.push_back(player); 66 67 cubeImage = al_load_bitmap("Blocks.png"); 68 69 srand(time(NULL)); 70//TIMER INIT AND STARTUP====================== 71 72 event_queue = al_create_event_queue(); 73 timer = al_create_timer(1.0 / 60); 74 75 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 76 al_register_event_source(event_queue, al_get_keyboard_event_source()); 77 78 al_start_timer(timer); 79//GAME LOOP========================================================= 80 while(!done) 81 { 82 ALLEGRO_EVENT ev; 83 ALLEGRO_MOUSE_STATE mouse; 84 al_get_mouse_state (&mouse); 85 al_wait_for_event(event_queue, &ev); 86 xX = mouse.x; 87 xY = mouse.y; 88 89//INPUT========================================================================== 90 if(ev.type == ALLEGRO_EVENT_KEY_DOWN) 91 { 92 switch(ev.keyboard.keycode) 93 { 94 case ALLEGRO_KEY_ESCAPE: 95 done = true; 96 break; 97 case ALLEGRO_KEY_LEFT: 98 keys[LEFT] = true; 99 break; 100 case ALLEGRO_KEY_RIGHT: 101 keys[RIGHT] = true; 102 break; 103 case ALLEGRO_KEY_UP: 104 keys[UP] = true; 105 break; 106 case ALLEGRO_KEY_DOWN: 107 keys[DOWN] = true; 108 break; 109 case ALLEGRO_KEY_SPACE: 110 keys[SPACE] = true; 111 for(int i = 0; i < 4; i++) 112 { 113 for(int j = 0; j < 4; j++) 114 { 115 Cube *cube = new Cube(xX, xY, cubeImage); 116 objects.push_back(cube); 117 xX +=24; 118 } 119 xX =mouse.x; 120 xY +=24; 121 } 122 } 123 } 124 else if(ev.type == ALLEGRO_EVENT_KEY_UP) 125 { 126 switch(ev.keyboard.keycode) 127 { 128 case ALLEGRO_KEY_ESCAPE: 129 done = true; 130 break; 131 case ALLEGRO_KEY_LEFT: 132 keys[LEFT] = false; 133 break; 134 case ALLEGRO_KEY_RIGHT: 135 keys[RIGHT] = false; 136 break; 137 case ALLEGRO_KEY_UP: 138 keys[UP] = false; 139 break; 140 case ALLEGRO_KEY_DOWN: 141 keys[DOWN] = false; 142 break; 143 case ALLEGRO_KEY_SPACE: 144 keys[SPACE] = false; 145 break; 146 } 147 } 148//GAME UPDATE======================================================== 149 else if(ev.type == ALLEGRO_EVENT_TIMER) 150 { 151 render = true; 152 153 if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 154 { 155 done = true; 156 } 157 158 if(keys[LEFT]) 159 player->MoveLeft(); 160 else if(keys[RIGHT]) 161 player->MoveRight(); 162 else 163 player->ResetAnimation(0); 164 165 if(keys[UP]) 166 player->MoveUp(); 167 else if(keys[DOWN]) 168 player->MoveDown(); 169 else 170 player->ResetAnimation(1); 171 172 //update 173 for(iter = objects.begin(); iter != objects.end(); ++iter) 174 (*iter)->Update(); 175 176 //collisions 177 for(iter = objects.begin(); iter != objects.end(); ++iter) 178 { 179 if( ! (*iter)->Collidable() ) continue; 180 181 for(iter2 = iter; iter2 != objects.end(); ++iter2) 182 { 183 if( !(*iter2)->Collidable() ) continue; 184 185 if( (*iter)->CheckCollisions( (*iter2))) 186 { 187 (*iter)->Collided( (*iter2)->GetID(), (*iter2)); 188 (*iter2)->Collided( (*iter)->GetID(), (*iter)); 189 } 190 } 191 } 192 //cull the dead 193 for(iter = objects.begin(); iter != objects.end(); ) 194 { 195 if(! (*iter)->GetAlive()) 196 { 197 delete (*iter); // he is destroying only specific memory , not the bitmap ( object) itself ,because there is possiblity that there is more objects of same type , using same bitmap in the game.googl about this and learn more you lazy nab ! 198 iter = objects.erase(iter); 199 } 200 else 201 iter++; 202 } 203 204 } 205//RENDER====================================================================== 206 if(render && al_is_event_queue_empty(event_queue)) 207 { 208 render = false; 209 210 //BEGIN PROJECT RENDER================ 211 for(iter = objects.begin(); iter != objects.end(); ++iter) 212 (*iter)->Render(); 213 214 //FLIP BUFFERS======================== 215 al_flip_display(); 216 al_clear_to_color(al_map_rgb(255, 0, 255)); 217 } 218 } 219//DESTROY PROJECT OBJECTS================================================= 220 for(iter = objects.begin(); iter != objects.end(); ) 221 { 222 (*iter)->Destroy(); 223 delete (*iter); 224 iter = objects.erase(iter); 225 } 226 227 al_destroy_bitmap(playerImage); 228 al_destroy_bitmap(cubeImage); 229 230 //SHELL OBJECTS================================= 231 al_destroy_timer(timer); 232 al_destroy_event_queue(event_queue); 233 al_destroy_display(display); 234 235 return 0; 236}

Edgar Reynaldo
Member #8,592
May 2007
avatar

Well, the problem may be in your collision detection routine. Your event loop looks okay as far as I can see. If you have n blocks, you are calling CheckCollisions (n*(n-1))/2 times, which is (n^2 - n)/2 which is O(n^2) time. So at 180 objects, that is 16110 calls per frame and 96,660 calls per second. And that's not to mention each time you dereference an iterator and then dereference a pointer. The second bit can't be helped, but the first part can.

Quote:

#SelectExpand
1 //collisions 2 for(iter = objects.begin(); iter != objects.end(); ++iter) 3 { 4 if( ! (*iter)->Collidable() ) continue; 5 6 for(iter2 = iter; iter2 != objects.end(); ++iter2) 7 { 8 if( !(*iter2)->Collidable() ) continue; 9 10 if( (*iter)->CheckCollisions( (*iter2))) 11 { 12 (*iter)->Collided( (*iter2)->GetID(), (*iter2)); 13 (*iter2)->Collided( (*iter)->GetID(), (*iter)); 14 } 15 } 16 }

If I was you, I would go ahead and switch to using a std::vector (See the SGI STL guide). There is also a problem with your algorithm. iter2 should start at iter + 1, not iter. Second, extract the pointers first.

int sz = (int)objects.size();
for (unsigned int i = 0 ; i < sz ; ++i) {
   Object* o1 = objects[i];
   if (!o1->Collidable()) {continue;}
   for (unsigned int i2 = i + 1 ; i2 < sz ; ++i2) {
      Object* o2 = objects[i2];
      if (!o2->Collidable()) {continue;}
      if (o1->CheckCollisions(o2)) {
         o1->CollidedWith(o2);
         o2->CollidedWith(o1);
      }
   }
}

That should get you a modest speed increase. I'm not sure how using vector's iterator compares with indexing in terms of speed. It might be negligible in which case you could simply change your declaration of object to be of type std::vector. I would still extract the Object*'s from the iterator though, instead of dereferencing them multiple times (dereferencing is when you access the object pointed to by a pointer or in this case, iterator).

After that you should look into quad trees and space partitioning to reduce the number of collision checks necessary.

kebapmanager
Member #14,863
January 2013
avatar

And sadly I cant write iter2 = iter+1
I get bunch of errors saying I cant add int to list ...

But ignore what I wrote up , because I dont need to do iter2=iter+1 ,since its loop inside of loop and first loop wich is iter is like equal 1 for example , second loop wich is iter2 is at beginig same as iter , but after 1st chechk its not , because iter wont add +1 untill second loop is done ( Sry for bad english )

EXPLANATION =============================

#SelectExpand
1#include <iostream> 2using namespace std; 3 4int main() 5 { 6 for (double i=1; i<4; i++) 7 { 8 for(double j=i; j<4; j++) 9 cout <<"i: "<< i << " j; " << j <<endl; 10 } 11 system ("PAUSE"); 12 return 0; 13 14 }

If you run this , result will be:
i: 1 j; 1
i: 1 j; 2
i: 1 j; 3
i: 2 j; 2
i: 2 j; 3
i: 3 j; 3
Wich clearly shows that iters will be same at one point , but will be ignore and it will continue , so j (iter 2 ) will only be equal to i(iter) in 1 out of 3 cases untill i changes.

As far as I can understand this should work just fine?( but maybe creates unneccesery chechks ....)

Edgar Reynaldo
Member #8,592
May 2007
avatar

And sadly I cant write iter2 = iter+1

Oh, sorry bout that. It would be nice if list supported pointer addition, but you can do it a different way.

#SelectExpand
1 2#include <cstdio> 3#include <list> 4 5using namespace std; 6 7int main(int argc , char** argv) { 8 9 list<int> lint; 10 11 for (int i = 0 ; i < 5 ; ++i) {lint.push_back(i);} 12 13 for (list<int>::iterator it = lint.begin() ; it != lint.end() ; ++it) { 14 int i = *it; 15 list<int>::iterator it2 = it; 16 ++it2; 17 while (it2 != lint.end()) { 18 int i2 = *it2; 19 printf("%i vs %i\n" , i , i2); 20 ++it2; 21 } 22 } 23 24 return 0; 25}

Or you can use vector (which in this case you should). It supports std::vector<Type>::iterator operator+(std::vector<Type>::iterator , int);

kebapmanager
Member #14,863
January 2013
avatar

Thank you alot for showing me all this , you are amazingly good at this O.o.

Il try to replace list with vectors and see what is gonna happen. Il let you know the results :)

===================================== SOLUTION =================================

#SelectExpand
1int sz = (int)objects.size(); 2 for (unsigned int i = 0 ; i < sz ; ++i) { 3 GameObject* iter = objects[i]; 4 5 if( ! (iter)->Collidable() ) continue; 6 7 for (unsigned int i2 = i + 1 ; i2 < sz ; ++i2) { 8 GameObject* iter2 = objects[i2]; 9 10 if( !(iter2)->Collidable() ) continue; 11 12 if( (iter)->CheckCollisions( (iter2))) { 13 14 (iter)->Collided( (iter2)->GetID(), (iter2)); 15 (iter2)->Collided( (iter)->GetID(), (iter)); 16 } 17 } 18 }

Just like edgar suggested I switched to vectors , and now I can create 256 cubes before getting small lagg , and it stops rendering at 300 , wich I think will be fine for now , since my agme project is very small and I probbaly wont have more then 50 objects on screen , but I still wanted to learn something more and solve this problem , Thank you everyone for the help :)

(edit : typos)

Btw if anyone wants to tell me why is this way working soo much better, fell free to pm me because I am trying to figure it out myself now , but its not working :P

pkrcel
Member #14,001
February 2012

IIRC direct access to random access containers (like a vector) is constant complexity (O(1)) while for non-random access (like a list) it's linear (O(n) n being the number of items in the container), and that's a big difference for large numbers.

Thou I think the most of the improvement comes since you decreased the times you call the Collision routine itself.

And that's also what Edgar suggested to do further, in case of many more objects, you should partition your space so that you only check for meaningful collisions.

Usually this is called the "broad" phase of collision detection, followed by a "narrow" one that is usually exactly like yours, checking for only objects that are "close enough" to actually collide.

It is unlikely that Google shares your distaste for capitalism. - Derezo
If one had the eternity of time, one would do things later. - Johan Halmén

Edgar Reynaldo
Member #8,592
May 2007
avatar

The difference comes from all the pointer dereferencing that a list does, which a vector does not. A list's items are linked together by pointers to the next and the previous node, and to get from one to the other you have to return *next. Jumping from address to address slows the computer down significantly in cases like this. A vector works so much faster because all it takes to access the vector is to do some pointer addition.

kebapmanager
Member #14,863
January 2013
avatar

Thank you for explanation , but why is there list library then? , why would anyone use it if its soo much slower.
I also looked up what a list and vector libraries can do , and its about 80% same.

Anyhow thank you for explanation , even thought I still wonder how big games avoid this kind of problems ...

pkrcel
Member #14,001
February 2012

Well, first of all there are MARKED differences between the two containers:

- Vectors support fast random-access ( constant time ) but are quite slow at inserting and removing objects in the middle

- conversely, lists support only a slower sequential access ( linear time ) but are extremely efficient in removing and inserting objects anywhere in the list (which is constantly sorted by comparison) in constant time.

So based on the type of operations (and algorythms) you will end up doing more frequently on the container you can choose the one that best fits your needs: handy link

Secondly, AAA games implement all of those tricks here you just had a tip to, like spatial division of objects for a very efficient broad collision phase, custom memory management for quick allocation/deallocation, deadly optimized routines for the most frequent tasks, hard-core custom containers, shader tricks...etc..etc..etc...basically thou, you'll be digging this hard only when really pushing the resources available to their limit.

It is unlikely that Google shares your distaste for capitalism. - Derezo
If one had the eternity of time, one would do things later. - Johan Halmén

Go to: