Allegro.cc - Online Community

Allegro.cc Forums » Installation, Setup & Configuration » Allegro5 set_keyboard_rate

Credits go to Audric and Edgar Reynaldo for helping out!
This thread is locked; no one can reply to it. rss feed Print
Allegro5 set_keyboard_rate
HiroNakashimi
Member #17,081
May 2019

I'm having an issue when people hold down a key, it seems to generate many events which flood the queue and causes game lag. Note that if I do absolutely nothing with these keyboard events (no redrawing, no recalculations, nothing) and immediately "continue" in my game loop, I still get enormous lag.

Changing my keyboard settings (via the configuration panel of windows) to a slower repeat rate reduces the lag to almost nothing, which strengthens me in my assumption about the event queue being flooded.

However, as I can't ask everybody to change their keyboard settings for this program, I'm looking for a code solution. In Allegro4, there is apparently a set_keyboard_rate function. This seems to be exactly what I need. Unfortunately, circumstances (this is part of a coding assignment) force me to use Allegro5, where this function does not exist (yet?).

Is there a different function in Allegro5 which has a similar effect?
If not, is there a different way to do this? Any hints on making such a function myself?

Any help kindly appreciated!

Audric
Member #907
January 2001

I think there must be a problem on your side, because "doing nothing" takes no time, it's what you should do when your game loop finds an event that you don't need to react to.
Can you show your code for the event loop ?

HiroNakashimi
Member #17,081
May 2019

Thanks for taking an interest Audric!
Will share code as soon as I can get my hands on it (currently at different location) but basically it's like this:

#SelectExpand
1while(!quit){ 2 3 wait for event 4 5 if(capture input) continue 6 7 update engine (includes rendering) 8 9 check if quit 10}

I literally use the "continue;" to skip to the next iteration of the while loop, so as to avoid the (costly) engine update operations.

(The post-reply button on this page doesn't seem to do anything, so I'm using edit to add additional information.)

The "capture input" checks whether certain keys are pressed or released. If they have, I conclude the event was a key event (we are given a wrapper "Allkit" so as to shield us from Allegro itself - not sure why though - but the result is that we can't properly test the type of event, hence this workaround-conclusion). Then the method will return true so as to trigger the "continue".
If no buttons were pressed or released, then the event should be a timer event, and the engine updates happen.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I would surmise to say you are not filtering input correctly, and so you end up drawing a frame for every keyboard repeat or every event.

This 'Allkit' sounds problematic, if you can't test the event type directly, that's silly.

You can't post a reply because you are the most recent person to post. You can however edit and send to top. But you can post again now, because I did. ;)

HiroNakashimi
Member #17,081
May 2019

Edgar, you are exactly right. Even though the events for the key in question (arrow up and down) were explicitly caught, and these were the only keys being pressed, there were still non-timer events leaking through and causing the rest of the loop to be run through.

A function is_timer_event() was made available in the Allkit wrapper. Using this, no more keyboard events are leaking through and the lag has disappeared.

Thanks you both for taking the time to help me out on this. Much appreciated!

If I could impose on your time some more: when parts of the logic in the game loop start getting heavy, there's inevitable lag. But sometimes this is simply the result of badly written / non performant code. I'm thinking it would be very useful to have something to keep track of the amount of time spent in the different parts of the game loop so as to know where to focus for improvements.
E.g. create a class which stores function calls & amount of time spent (via a call to function_has_started and function_has_ended for every function in the game loop). After a certain number of game loops or time passed, it could then calculate and print (to terminal):

-> update systems: x %
---> update MovementSystem: y %
------> Apply movement to all relevant entities: a %
------> Remove out-of-screen elements: b %
------> Create new elements in buffer: c %
---> update CollisionSystem: z %
---> update RenderSystem: ... %

However, optimising the game loop is something I assume everyone in this area is concerned with, so tools for this probably exist already. Could you point me to tools / techniques which are commonly used in this area?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

There are a few things you can do in this situation.

When the logic + drawing take more than 1 frame / TargetFPS, you need to make a decision what to do. Do you get behind and always present one frame per logic update? No, you implement frame skipping. This means processing more than one logic frame (as many as there are, up to a limit) per visual update. However, this means visual information has been lost between displays.

Another option is to only process one timer tick, even if there are many in the queue. This will make your program slow down gracefully. Extra timer events are simply dropped.

As to your questions of performance timing, there are options there as well. In its day, gprof was a good profiler. Now it is horribly broken. MSVS has a good profiler if you can figure out how to use it. And then there are other in-code options like high performance timer counts. It so happens I have some cross platform high performance timers in my library.

The implementation is really simple, if you're on windows you use QueryPerformanceCounter, and if you're on Linux or OSX you use clock_gettime.

I've uploaded the timing code from my library as a stand alone include and source file, along with the license. See the attached zip file.

The workhorse of the function is here :

#SelectExpand
1ProgramTime ProgramTime::Now() { 2#if defined _WIN32 3 LARGE_INTEGER qpf; 4 LARGE_INTEGER qpc; 5 QueryPerformanceFrequency(&qpf); 6 QueryPerformanceCounter(&qpc); 7 return ProgramTime((double)qpc.QuadPart/(double)qpf.QuadPart); 8#elif defined __linux__ 9 timespec ts; 10 int ret = clock_gettime(CLOCK_REALTIME , &ts); 11 (void)ret; 12 EAGLE_ASSERT(ret == 0); 13 double rt = (double)ts.tv_sec + (double)ts.tv_nsec / pow(10 , 9); 14 return ProgramTime(rt); 15#else 16 #error "ProgramTime::Now() is not implemented on this platform" 17#endif 18}

Go to: