Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Allegro5: Event Queue Delay Problem

This thread is locked; no one can reply to it. rss feed Print
 1   2   3   4 
Allegro5: Event Queue Delay Problem
GaryT
Member #14,875
January 2013

Okay I'm Really Stuck With This. It's Driving Me Crazy. Please Help :-[ :'(

I have the most Simple Test Program with the game loop timed off VSYNC, and all it does is just move a square around the screen.

Here's what’s happening: When I rapidly press a mixture of the relevant keys to steer the square, a growing increase in delay occurs before the event generated by each key press, changes the direction of the square.

My if(trueevent) check on line: 53 I believe is the correct way to handle: al_get_next_event().

Now, just to stop my program cycle proceeding for when: trueevent == true, but the event isn't one I'm checking for, I've inserted the while loop at line: 50, but it's made no difference.

So I've also added: al_is_event_queue_empty() to stop the program updating the position of the square and drawing it. I've done this partly just to try and find out how things are working.

This still hasn't stopped the delay.

I can only assume I'm doing something fundamentally wrong. I wasn’t expecting to have to do anything additional to my: if(trueevent) check on line: 53

The Most Confusing Point For Me: After rapidly pressing keys for about 5 to 10 seconds and then stopping, the square keeps moving smoothly and changes direction a few times over the next 3 to 4 seconds. Now, surely then, there must be events moving up the queue during these 3 to 4 seconds. But, if this is true, then why does the program continue to update the position and draw the square, even though it’s restricted by: al_is_event_queue_empty

The program is 100% complete, so please try copy and pasting it.

So please can somebody explain what's going on here :-/

#SelectExpand
1#include <allegro5\allegro.h> 2#include <allegro5\allegro_primitives.h> 3 4const int WIDTH = 1200; 5const int HEIGHT = 825; 6 7bool moveup = false; 8bool movedown = false; 9bool moveleft = false; 10bool moveright = false; 11 12int x = 300; 13int y = 300; 14 15bool trueevent = false; 16bool done = false; 17 18int main(void) 19{ 20 //Allegro variables 21 ALLEGRO_DISPLAY *display = NULL; 22 ALLEGRO_EVENT_QUEUE *event_queue = NULL; 23 24 //Initialization Functions 25 if(!al_init()) 26 return -1; 27 28 al_set_new_display_option(ALLEGRO_VSYNC, 1, ALLEGRO_REQUIRE); 29 30 display = al_create_display(WIDTH, HEIGHT); 31 32 if(!display) 33 return - 1; 34 35 al_init_primitives_addon(); 36 al_install_keyboard(); 37 38 event_queue = al_create_event_queue(); 39 40 al_register_event_source(event_queue, al_get_keyboard_event_source()); 41 al_register_event_source(event_queue, al_get_display_event_source(display)); 42 43 44 while(!done) 45 { 46 ALLEGRO_EVENT ev; 47 48 trueevent = al_get_next_event(event_queue, &ev); 49 50 while(trueevent && ev.type != ALLEGRO_EVENT_DISPLAY_CLOSE && ev.type != ALLEGRO_EVENT_KEY_DOWN) // Added To Try And Fix Delay Problem !!! 51 trueevent = al_get_next_event(event_queue, &ev); 52 53 if(trueevent) 54 { 55 if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 56 { 57 done = true; 58 } 59 60 else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) 61 { 62 switch(ev.keyboard.keycode) 63 { 64 case ALLEGRO_KEY_ESCAPE: 65 done = true; 66 break; 67 case ALLEGRO_KEY_TILDE: 68 moveup = true; 69 movedown = false; 70 break; 71 case ALLEGRO_KEY_SLASH: 72 movedown = true; 73 moveup = false; 74 break; 75 case ALLEGRO_KEY_Z: 76 moveleft = true; 77 moveright = false; 78 break; 79 case ALLEGRO_KEY_X: 80 moveright = true; 81 moveleft = false; 82 break; 83 } 84 } 85 } 86 87 if(al_is_event_queue_empty(event_queue)) // Added To Try And Fix Delay Problem !!! 88 { 89 if(moveup) 90 y -= 1; 91 if(movedown) 92 y += 1; 93 if(moveleft) 94 x -= 1; 95 if(moveright) 96 x += 1; 97 98 al_draw_filled_rectangle(x, y, x + 50, y + 50, al_map_rgb(0, 200, 0)); 99 100 al_flip_display(); 101 al_clear_to_color(al_map_rgb(0,0,0)); 102 } 103 } 104 105 al_destroy_event_queue(event_queue); 106 al_destroy_display(display); 107 108 return 0; 109}

EDIT: Just wanted to say that sometimes the problem barely occurs. Most times it's definitely noticeable. Stopping and starting the program seems it can cause this difference.

Also From Further Testing:

1) My trueevent variable only ever returns true when an intended event occurs such as pressing a key.

2) al_is_event_queue_empty() is returning true for every cycle, even when events seem that they must still be on the queue as previously described.

pkrcel
Member #14,001
February 2012

I haven't checked deeper but this

while(trueevent && ev.type != ALLEGRO_EVENT_DISPLAY_CLOSE && ev.type != ALLEGRO_EVENT_KEY_DOWN) // Added To Try And Fix Delay Problem !!!  
    trueevent = al_get_next_event(event_queue, &ev);

..did you put it in to try remove spurious events?

I wouldn't do that, and do the other way round: do not process spurious events and draw only if the scene need to be actually redrawn...you can achieve this using a bool like needsredraw that you set in your switch statement, and your drawing code shoudl be enclosed in an if(queue_empty && needsredraw)

Anyway, lemme check for the rest...I'm at work now and could not read further.

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

Dizzy Egg
Member #10,824
March 2009
avatar

You say "while trueevent" and then after that say "if(trueevent)" which looks wrong to me...

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

GaryT
Member #14,875
January 2013

Thanks pkrcel.

I know what you mean, but the: needsredraw part of: if(queue_empty && needsredraw) is typically, from examples I've seen, set to true in a timer event, which would then result in executing my block of code updating the position and screen.

Because I'm not using a timer, and the game loop FPS is determined by Vsync, then the: needsredraw part, seems perhaps not applicable in this circumstance.

Incidentally, I only found out by chance that setting Vsync to be on prior to creating the display, does in fact time the whole game loop in this simple way. Vsync definitely works in this way (try commenting out) but I'm not even sure if this is the proper way to do it. It probably is, but not totally sure.

Also this is exactly why I'm using al_get_next_event() instead of al_wait_for_event(), since: wait, so far seems to me, to only be able to update the object positions and display the screen, by using a timer. Whereas so far I've only understood it to be possible to use Vsync to time my game loop by using: al_get_next_event() :( :)

EDIT: I agree Dizzy Egg, my apologies for that while loop. It's rubbish, doesn't really make sense, and was just a desperate attempt to try and shake something up to help me see what was happening.

Please read from the start of this reply. I replied to: pkrcel before having a chance to read your reply :)

EDIT 2: The good news is for me, I've tried running the program on my other laptop which is very new and fast, fearing I wouldn't be able to reproduce the issue. Thankfully it's every bit as noticeable on that computer as well.

Important Note For Testing: Sometimes the program starts up and is perfectly okay forever, sometimes just a little bit bad, and sometimes quite naughty indeed. So keep restarting it if you don't experience the problem.

So, how can the event queue be empty if the square's position updates and the direction changes for a few seconds after you pressed the last key.

It's as if there's a build up of events on the queue, which would explain the delayed changes in direction after you stop pressing keys, but at the same time the check: al_is_event_queue_empty() is returning true. This seems to be a direct contradiction and is confusing the hell out of me. >:(

EDIT 3: Just a thought: I suppose if there was some kind of keyboard buffer that was storing up key presses, and in a delayed manner, feeding them to the event queue, as opposed to the key presses being registered directly onto the queue instantly, that this might explain it. That can’t be right though can it. I've never heard of anything like that.

pkrcel
Member #14,001
February 2012

GaryT said:

I know what you mean, but the: needsredraw part of: if(queue_empty && needsredraw) is typically, from examples I've seen, set to true in a timer event, which would then result in executing my block of code updating the position and screen.

Uhm, no?

Actually you've seen those in a timer event BECAUSE the examples you've seen set the framerate through a timer (Mike Gieig's does this in his tutorial), but the idea is that you actually blit to the screen IF there is something NEW to draw (eg. the scene has effectively changed), whichever is the way you time your draw routines.

In your case I was suggesting that you could get off your (now definitely ruled out by your further debugging) spurious events simpy ignoring them AND not drawing when you intercept one of them.

Anyway that was not the case in the first place....shoulda look a bit into it (thou mostly for learning purposes, as I already said in a previous thread, I'm not qualified for good game-loop timing :P )

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

GaryT
Member #14,875
January 2013

I'm drawing something new every frame since the square is moving 1 pixel per frame.

Anyway, it's all my remarks in my last entry that I would love some help with. In particular how it seems the event queue is registering as empty allowing the position and draw update to happen, when events are clearly taking affect/effect (not sure which) a few seconds after pressing the last key. :)

EDIT: Is there a keyboard buffer or something that could be storing key presses and feeding them slowly to the event queue. I guess probably not.

Edgar Reynaldo
Member #8,592
May 2007
avatar

GaryT said:

    trueevent = al_get_next_event(event_queue, &ev);

    while(trueevent && ev.type != ALLEGRO_EVENT_DISPLAY_CLOSE && ev.type != ALLEGRO_EVENT_KEY_DOWN) // Added To Try And Fix Delay Problem !!!  
      trueevent = al_get_next_event(event_queue, &ev);

    if(trueevent)
    {

If the first al_get_next_event returns true then you proceed to change the event as long as it is not a display close or a key down event.

So, say trueevent is true, and it is a key down event. Then you immediately replace it with the next event thereby missing one key down event. And if the second al_get_next_event was false the first event is still skipped. So you are skipping events.

Try this :

do {
while (!al_is_event_queue_empty(queue)) {
   ALLEGRO_EVENT ev;
   al_get_next_event(queue , &ev);// Guaranteed to work because al_is_event_queue_empty returned false.

   if (ev.type == ALLEGRO_EVENT_TIMER) {redraw = true;}
}
if (redraw) {
   Redraw();
}
} while (!quit);

However, you have to be aware the code I just posted will use up 100% cpu because you're not resting at all. That's why you want to use al_wait_for_event instead of al_get_next_event.

do {

do {
   ALLEGRO_EVENT ev;
   al_wait_for_event(queue , &ev);
   if (ev.type == ALLEGRO_EVENT_TIMER) {redraw = true;}
   if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {
      // key pressed, do something
   }
} while (!al_is_event_queue_empty(queue));

} while (!quit);

That way you skip events you don't want by ignoring them, but you don't let them build up in the queue either.

GaryT
Member #14,875
January 2013

Thanks Edgar.

I had previously criticised that while loop I put in, and to be honest it never really properly addressed the issue.

Just as a matter of observation though:

Edgar said:

If the first al_get_next_event returns true then you proceed to change the event as long as it is not a display close OR a key down event.

It is actually "not a display close && a key down event" so no events are missed here.

Anyway please read my remarks from my previous entries explaining how I'm using Vsync to time the game loop.

From my Example Test Program included in this thread, I'm not sure how I could use a timer as you've suggested, without overriding how Vsync takes control of timing the game loop.

Also please notice my explanation of why I use: al_get_next_event().

So another question is: How can al_wait_for_event() be used to determine the FPS at the same time as the FPS being set by the Vsync signal. :)

pkrcel
Member #14,001
February 2012

GaryT said:

Is there a keyboard buffer or something that could be storing key presses and feeding them slowly to the event queue. I guess probably not.

There was a similar question some days ago here....seems the solution goes right into managing input with the event system.

Anyway,

Quote:

I'm drawing something new every frame since the square is moving 1 pixel per frame.

uhm, right...you're setting direction with a SINGLE keypress so you basically have almost always something that needs redraw....that could NOT be the general case in a game but whatever...here the problem is another one.

I'll be damned, lemme just try compile this thing and run it....more on this later.

EDIT: Okay, tried it quite some 20 times and never got your problem. My built-in gfx card is set to let the application decide for VSYNC, I removed the ill-conceived While loop and set a little thingy that display FPS in the upper left corner...it says consistently 60FPS (more or less...float/double approx :P )
I'm sorry but I ain't able to reproduce.

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

GaryT
Member #14,875
January 2013

Thank you very much pkrcel for all your assistance ;)

I feared because of the inconsistency of the issue, that other people might not be able to reproduce it. Because of this I tried it on my other new laptop and got the same issue.

I know you've tried it 20 times or so, so thanks for giving it a go.

Just to be absolutely sure, sometimes for me the program was running for up to about 10 seconds with me quite rapidly pressing the keys before the very noticeable delays started to show and increase.

Just to point out 1 quite literally insane observation, and that is whenever I have 3 to 4 calls to a draw function without changing anything else, this seems to stop the delay. Obviously not a consistent or controlled method I could rely on, but just adds to my confusion.

I still think I'm missing something fundamental in all this. Maybe some other Event Queue checking functions.

Anyway, I'll keep looking into it, and post a thread if/when I find out what's causing it. :)

EDIT: Thanks for that link as well.

EDIT 2: One last question: What version of Allegro5 are you using.

EDIT 3: I've just replaced al_get_next_event() with al_wait_for_event(), correctly set up a timer to handle update position and draw, and: OH blimey, it's still the same. I'll be back. >:(

pkrcel
Member #14,001
February 2012

GaryT said:

One last question: What version of Allegro5 are you using.

Riight, that should have been a concern all the way here, anyway It's a git revision I compiled myself...unfortunately now I cannot tell you WHICH revision since I'm not at that PC, but it's the 5.1 branch for sure.

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

GaryT
Member #14,875
January 2013

Thanks for that info.

I'm using 5.0.8

I will try a later version tonight after I get back from work.

Also please see my last edit.

Cheers.

pkrcel
Member #14,001
February 2012

Well, then.

I tried on this PC (a Delll Vostro 3550 Laptop) the following codem which is just a minor modification of yours:

#SelectExpand
1#include <allegro5\allegro.h> 2#include <allegro5\allegro_primitives.h> 3#include <allegro5\allegro_font.h> 4 5#include <iostream> 6 7const int WIDTH = 800; 8const int HEIGHT = 600; 9 10bool moveup = false; 11bool movedown = false; 12bool moveleft = false; 13bool moveright = false; 14 15int x = 300; 16int y = 300; 17 18bool trueevent = false; 19bool done = false; 20 21double fps, curTime, lastTime; 22 23int main(void) 24{ 25 //Allegro variables 26 ALLEGRO_DISPLAY *display = NULL; 27 ALLEGRO_EVENT_QUEUE *event_queue = NULL; 28 ALLEGRO_FONT *stdFont = NULL; 29 30 //Initialization Functions 31 if(!al_init()) 32 return -1; 33 34 al_set_new_display_option(ALLEGRO_VSYNC, 1, ALLEGRO_REQUIRE); 35 36 display = al_create_display(WIDTH, HEIGHT); 37 38 if(!display) 39 return - 1; 40 41 al_init_primitives_addon(); 42 al_init_font_addon(); 43 al_install_keyboard(); 44 45 stdFont = al_create_builtin_font(); 46 47 event_queue = al_create_event_queue(); 48 49 al_register_event_source(event_queue, al_get_keyboard_event_source()); 50 al_register_event_source(event_queue, al_get_display_event_source(display)); 51 52 lastTime = 0.0; 53 54 while(!done) 55 { 56 ALLEGRO_EVENT ev; 57 58 trueevent = al_get_next_event(event_queue, &ev); 59 60 if(trueevent) 61 { 62 if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 63 { 64 done = true; 65 } 66 67 else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) 68 { 69 switch(ev.keyboard.keycode) 70 { 71 case ALLEGRO_KEY_ESCAPE: 72 done = true; 73 break; 74 case ALLEGRO_KEY_UP: 75 moveup = true; 76 movedown = false; 77 break; 78 case ALLEGRO_KEY_DOWN: 79 movedown = true; 80 moveup = false; 81 break; 82 case ALLEGRO_KEY_LEFT: 83 moveleft = true; 84 moveright = false; 85 break; 86 case ALLEGRO_KEY_RIGHT: 87 moveright = true; 88 moveleft = false; 89 break; 90 } 91 } 92 } 93 94 if(al_is_event_queue_empty(event_queue)) // Added To Try And Fix Delay Problem !!! 95 { 96 curTime = al_get_time(); 97 if(moveup) 98 y -= 1; 99 if(movedown) 100 y += 1; 101 if(moveleft) 102 x -= 1; 103 if(moveright) 104 x += 1; 105 106 fps = 1.0 / (curTime - lastTime); 107 al_draw_filled_rectangle(x, y, x + 50, y + 50, al_map_rgb(0, 200, 0)); 108 al_draw_textf(stdFont, al_map_rgb(100,100,100), 5, 5, ALLEGRO_ALIGN_LEFT, "FPS: %f", fps); 109 al_flip_display(); 110 al_clear_to_color(al_map_rgb(0,0,0)); 111 lastTime = curTime; 112 } 113 } 114 al_destroy_event_queue(event_queue); 115 al_destroy_display(display); 116 al_destroy_font(stdFont); 117 return 0; 118}

with freshly downloaded 5.0.8 binaries (BTW A.cc community...michal's usual link stopped working!), and for the life of me I am unable to reproduce your problem.

FPS is consistent with VSYNC rate, in fact on 60Hz I get 60FPS and if I switch to 40Hz i get 40FPS, and I experience no delay whatsoever in the inputs, the square does change direction only when I actually press a button (I changed yours to match my arrow keys, I am unable to find the slash and the tilde on Italian layout keyboard....well the slash is at its usual place above 7 but still...).

I tried both Release and Debug Builds, both STATIC and DYNAMIC liking....really sorry but I can't reproduce your problem.

Or it's simply me unable to notice the problem? I'm now starting to wonder... ???

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

GaryT
Member #14,875
January 2013

I'm back from work, I'll test some more. Back again soon.

Update:

Well ok, I admit it, what a plonker I am. :D

Please see the revised list. ;D

Well now, there is an improvement in Debug mode, but it ain’t perfect, there's still delays. That side effect I mentioned, well, I left a second call to a draw function in the program and didn't notice. This as I've said before somehow masks the delay problem I'm getting. :'(

So I'll keep at it, but feel very beaten up right now. Thank you though pkrcel for your time and assistance. :)

Edgar: It's supposed to keep going after you let go of a key. That's not the problem.

The problem is this: After releasing the last key press of rapid pressing, the square doesn’t just keep moving, it sometimes changes direction a few times during the following few seconds. This happens on both my HP Laptop using Vista and my Samsung Laptop using Windows 7. So far not on my XP computer at work.

Points I've considered:

1) There are events on the queue during these few seconds. There has to be, else why does it change direction.

2) The code: if(al_is_event_queue_empty(event_queue)) means the square's position can only change and it be redrawn, if all events including key presses and releases have been removed from the queue by: al_get_next_event().

3) From points 1 and 2 then, it seems as if the only way events can be on the queue during these few seconds, and: al_is_event_queue_empty(event_queue) is returning true enabling the program to draw and move the square, is if this: Something equal to or equivalent to: A delayed process such as my imaginary idea of a slow keyboard buffer feeding the key presses to the queue during these few seconds.

4) From point 3 above, why don't all the key presses just enter onto the queue almost instantly. They should also be removed from the queue at the rate of 60 (i.e. my monitor is set to 60Hz) times per second. It's tempting to think the key presses do just enter onto the queue almost instantly, but if this is the case then back to this: why doesn't: if(al_is_event_queue_empty(event_queue)) stop the program updating the squares position and drawing it, then?

Thanks again and I hope somebody can shed some light on this. :-/

I’m off to work now. I’ll check back here when I get home. Cheers.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Okay, well I looked over your program again, and for what you are doing, it should work, except for the fact you don't track key up events. That is the reason it 'keeps going' after you let go of the key. I will test it more when I get home tonight. Actually, this is a slightly modified version of yours with key releases added, and it works just fine for me. :/

#SelectExpand
1#include <allegro5\allegro.h> 2#include <allegro5\allegro_primitives.h> 3 4const int WIDTH = 800; 5const int HEIGHT = 600; 6 7bool moveup = false; 8bool movedown = false; 9bool moveleft = false; 10bool moveright = false; 11 12int x = 300; 13int y = 300; 14 15bool trueevent = false; 16bool done = false; 17 18int main(void) 19{ 20 //Allegro variables 21 ALLEGRO_DISPLAY *display = NULL; 22 ALLEGRO_EVENT_QUEUE *event_queue = NULL; 23 24 //Initialization Functions 25 if(!al_init()) 26 return -1; 27 28 al_set_new_display_option(ALLEGRO_VSYNC, 1, ALLEGRO_REQUIRE); 29 30 display = al_create_display(WIDTH, HEIGHT); 31 32 if(!display) 33 return - 1; 34 35 al_init_primitives_addon(); 36 al_install_keyboard(); 37 38 event_queue = al_create_event_queue(); 39 40 al_register_event_source(event_queue, al_get_keyboard_event_source()); 41 al_register_event_source(event_queue, al_get_display_event_source(display)); 42 43 44 while(!done) 45 { 46 ALLEGRO_EVENT ev; 47 48 trueevent = al_get_next_event(event_queue, &ev); 49 50 while(trueevent && 51 ev.type != ALLEGRO_EVENT_DISPLAY_CLOSE && 52 ev.type != ALLEGRO_EVENT_KEY_DOWN && 53 ev.type != ALLEGRO_EVENT_KEY_UP) 54 { 55 trueevent = al_get_next_event(event_queue, &ev); 56 } 57 if(trueevent) 58 { 59 if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 60 { 61 done = true; 62 } 63 64 else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) 65 { 66 switch(ev.keyboard.keycode) 67 { 68 case ALLEGRO_KEY_ESCAPE: 69 done = true; 70 break; 71 case ALLEGRO_KEY_UP: 72 moveup = true; 73 movedown = false; 74 break; 75 case ALLEGRO_KEY_DOWN: 76 movedown = true; 77 moveup = false; 78 break; 79 case ALLEGRO_KEY_LEFT: 80 moveleft = true; 81 moveright = false; 82 break; 83 case ALLEGRO_KEY_RIGHT: 84 moveright = true; 85 moveleft = false; 86 break; 87 } 88 } 89 else if(ev.type == ALLEGRO_EVENT_KEY_UP) 90 { 91 switch(ev.keyboard.keycode) 92 { 93 case ALLEGRO_KEY_UP: 94 moveup = false; 95 break; 96 case ALLEGRO_KEY_DOWN: 97 movedown = false; 98 break; 99 case ALLEGRO_KEY_LEFT: 100 moveleft = false; 101 break; 102 case ALLEGRO_KEY_RIGHT: 103 moveright = false; 104 break; 105 } 106 } 107 } 108 109 if(al_is_event_queue_empty(event_queue)) // Added To Try And Fix Delay Problem !!! 110 { 111 if(moveup) 112 y -= 1; 113 if(movedown) 114 y += 1; 115 if(moveleft) 116 x -= 1; 117 if(moveright) 118 x += 1; 119 120 al_draw_filled_rectangle(x, y, x + 50, y + 50, al_map_rgb(0, 200, 0)); 121 122 al_flip_display(); 123 al_clear_to_color(al_map_rgb(0,0,0)); 124 } 125 } 126 127 al_destroy_event_queue(event_queue); 128 al_destroy_display(display); 129 130 return 0; 131}

GaryT
Member #14,875
January 2013

Please See My Revised Content In My Previous Entry. ::)

Thomas Fjellstrom
Member #476
June 2000
avatar

Also please see the keyboard or mouse examples on the wiki.

You DO NOT want to skip arbitrary events. And using a timer to handle drawing is a much better solution than what you've got so far. The loop on the wiki is a decent starting point. After you can add interpolation later if you find your game stutters too much.

Basically what the examples do is force all events to be handled before drawing, and drawing will happen a maximum of N times per second based on the timer rate (which in the examples is 60). It automatically handles frame skipping, and making sure the event queue is drained fully so there is no "delay problem" which is caused by the event queue getting backed up.

--
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

Edgar Reynaldo
Member #8,592
May 2007
avatar

Okay I tried it without the key releases, and there is a delay at times if you jam on the keys and then try to change direction. It can be a noticeable pause, and it seems like it is way more than 1/60 sec.

Your way is unconventional, but I guess it should work, and not the way it is right now.

Edit - Look at the way SiegeLord does it

Thomas Fjellstrom
Member #476
June 2000
avatar

GaryT said:

Please See My Revised Content In My Previous Entry.

That's what I was replying to. your code just doesn't work as is.

--
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

Edgar Reynaldo
Member #8,592
May 2007
avatar

GaryT said:

Points I've considered:

1) There are events on the queue during these few seconds. There has to be, else why does it change direction.

2) The code: if(al_is_event_queue_empty(event_queue)) means the square's position can only change and it be redrawn, if all events including key presses and releases have been removed from the queue by: al_get_next_event().

3) From points 1 and 2 then, it seems as if the only way events can be on the queue during these few seconds, and: al_is_event_queue_empty(event_queue) is returning true enabling the program to draw and move the square, is if this: Something equal to or equivalent to: A delayed process such as my imaginary idea of a slow keyboard buffer feeding the key presses to the queue during these few seconds.

4) From point 3 above, why don't all the key presses just enter onto the queue almost instantly. They should also be removed from the queue at the rate of 60 (i.e. my monitor is set to 60Hz) times per second. It's tempting to think the key presses do just enter onto the queue almost instantly, but if this is the case then back to this: why doesn't: if(al_is_event_queue_empty(event_queue)) stop the program updating the squares position and drawing it, then?

I am seeing the same behavior, the events are getting backed up in the queue, but it is still returning empty otherwise it couldn't draw.

This is an equivalent event processing to yours, and it has the same problems :

#SelectExpand
1 2 while(!done) 3 { 4 ALLEGRO_EVENT ev; 5 6 do { 7 gotevent = al_get_next_event(event_queue , &ev); 8 } while (gotevent && 9 ev.type != ALLEGRO_EVENT_DISPLAY_CLOSE && 10 ev.type != ALLEGRO_EVENT_KEY_DOWN); 11 12 if(gotevent) 13 { 14 // set motion / close / whatever 15 } 16 17 if(al_is_event_queue_empty(event_queue)) // Added To Try And Fix Delay Problem !!! 18 { 19 // process one logic and one drawing frame 20 } 21 }

You can replace that with :

    if(gotevent)
    {
      // set motion / close / whatever
    }
    else 
    {
      // process one logic and one drawing frame
    }

because al_get_next_event returns false if the queue is empty.

Here is the code for al_is_event_queue_empty, get_next_event_if_any, and al_get_next_event :

events.c#SelectExpand
215/* Function: al_is_event_queue_empty 216 */ 217bool al_is_event_queue_empty(ALLEGRO_EVENT_QUEUE *queue) 218{ 219 ASSERT(queue); 220 221 return (queue->events_head == queue->events_tail); 222} 223 224 225 226/* circ_array_next: 227 * Return the next index in a circular array. 228 */ 229static unsigned int circ_array_next(const _AL_VECTOR *vector, unsigned int i) 230{ 231 return (i + 1) % _al_vector_size(vector); 232} 233 234 235 236/* get_next_event_if_any: [primary thread] 237 * Helper function. It returns a pointer to the next event in the 238 * queue, or NULL. Optionally the event is removed from the queue. 239 * However, the event is _not released_ (which is the caller's 240 * responsibility). The event queue must be locked before entering 241 * this function. 242 */ 243static ALLEGRO_EVENT *get_next_event_if_any(ALLEGRO_EVENT_QUEUE *queue, 244 bool delete) 245{ 246 ALLEGRO_EVENT *event; 247 248 if (al_is_event_queue_empty(queue)) { 249 return NULL; 250 } 251 252 event = _al_vector_ref(&queue->events, queue->events_tail); 253 if (delete) { 254 queue->events_tail = circ_array_next(&queue->events, queue->events_tail); 255 } 256 return event; 257} 258 259 260 261/* Function: al_get_next_event 262 */ 263bool al_get_next_event(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *ret_event) 264{ 265 ALLEGRO_EVENT *next_event; 266 ASSERT(queue); 267 ASSERT(ret_event); 268 269 _al_mutex_lock(&queue->mutex); 270 271 next_event = get_next_event_if_any(queue, true); 272 if (next_event) { 273 copy_event(ret_event, next_event); 274 /* Don't increment reference count on user events. */ 275 } 276 277 _al_mutex_unlock(&queue->mutex); 278 279 return (next_event ? true : false); 280}

I don't see anything wrong with these functions so far. So IDK what to tell you.

I tried adding in some text display, the delta time and the fps. dt is around 0.016 and fps is around 60. But now that I added that in, the delay disappeared. I don't know what is going on. :/ Working in debug mode right now. Added in number of events processed and it did it again. Added in max number of events processed and it stopped doing it again. :-/

Peter Wang
Member #23
April 2000

Remember the input events are added to the queue by a background thread. You should check that it's actually doing that in a timely manner (I can't remember how the Windows port works right now).

GaryT
Member #14,875
January 2013

Thank you both.

Right then, I've just downloaded Microsoft Visual C++ 2010 Express on my other Laptop, The newest one, which uses Windows 7.

I've simply created the same file path from c: to where my pre-built binary needs to be, and freshly downloaded the correct binary to this folder.

Now, I've copied my program project folder to the other computer, Windows 7 :D. I've compiled it as usual and: Exactly the same delay as my Vista Laptop, perhaps slightly worse. I've checked the .exe size and is exactly the same, what I'd expect.

Yes this might be an unusual thing to suspect, but I wanted to be sure that it wasn't anything to do with my Vista computer. Incidentally on my XP computer, which I tested the .exe on yesterday, there's no delay whatsoever.

So it seems the way I'm doing it just doesn't work the way it looks like it should do. Again please read through my points 1, 2, 3 and 4 in my previous entry. I think they’re valid, and if al_get_next_event() was removing events each cycle, then at 60 FPS I don't see how the queue could GET BACKED UP. But perhaps I'm missing something. Please explain. :)

Thomas: You said "force all events to be handled before drawing" I thought that's what my: if(al_is_event_queue_empty(event_queue)) is supposed to do.

Anyway, it doesn't work properly, so I have to change the way I'm doing it. I CONCEDE. Edgar: Yes my way is unconventional, and I also guess it should work, but unless there's something I'm missing, Allegro it seems is just not supposed to be used this way. Damn! :(

Everybody: I don't want to time my game loop using a timer. I want it to be timed by the Vsync signal. That's why I've set Vsync to be on and I'm not using a timer.

What's the correct/proper way to do this. Please help me with this. Please! :-*

Please address this point as well: I've been setting Vsync on to time my game loop off the Vsync signal. As soon as a timer is used in the conventional way, but at the same time as Vsync being used like I'm trying to use it, the timer then determines the FPS, which isn't surprising, but not what I want.

Thank you Edgar for the link. I've had a look and I'm trying to understand how the "FPS is limited by the vsync". I can’t see any call to Vsync, so I'm struggling to understand this aspect. Please explain. :)

Anyway, I've tried the method of completely draining the event queue using a while loop and I still get the same delay issue.

It seems to me that it's extremely likely to do with Vsync. When I turn it off, although there's an increase in cpu usage (not as much as I was expecting though) there's clearly no delay.

So I'm still feeling a bit beaten up. :'(

EDIT: Peter Wang, that's the most reassuring reply I've had so far. I've noticed you are on the development team, but unfortunately for me I'm still a beginner.

Anyway, there's no chance I could understand the depths of your suspicion any time soon, but it exactly falls in line with the behaviour I'm getting and my imaginary idea of a keyboard buffer (that I previously mentioned in this thread) feeding the key presses into the queue slowly at times.

Well I'll wait for further replies. Thank You Peter. :)

I'm late for work. I'll check here tonight.

SiegeLord
Member #7,827
October 2006
avatar

GaryT said:

I can’t see any call to Vsync

The implication is that the display was created with the ALLEGRO_VSYNC option set to ALLEGRO_REQUIRE/ALLEGRO_SUGGEST. I know it doesn't work on some platforms, but that's a bug to be fixed in Allegro.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

GaryT
Member #14,875
January 2013

Thank you again SiegeLord :)

I'm starting to feel much better now having received Peter's and your replies :)

I'll look at your example a bit more when I get home. Cheers.

Peter Wang
Member #23
April 2000

When you press a key Windows sends an WM_KEYDOWN message which we duly process. But when you hold it long enough for the auto-repeat to kick in, Windows seems to send repeated WM_KEYDOWN messages at a lower rate (probably the repeat rate) and, bizarrely, blocks other WM_KEYDOWN messages from getting through. I'll try to investigate further later, but maybe some Windows experts can chime in. (edit: probably Wine-specific bug)

I wasn't able to reproduce in Windows XP.

 1   2   3   4 


Go to: