Allegro Wait for Event(Pretty slow)
Lísias de Castro

Hey guys. I am doing an engine to make things easier while creating my games.
I could make it work, but not on the way it is taught in most of tutorials. I mean, when I try to use the funcion al_wait_for_event to get mouse or keyboard events it takes like "forever" to read them. To fixe it I had to create 2 new variables and these are them: ALLEGRO_KEYBOARD_STATE and ALLEGRO_MOUSE_STATE. When I use them the program runs pretty smoth, but when I try to let the ALLEGRO_EVENT handle it, the program doesn't behave as well as I expected it to.

My code is something like this...

#SelectExpand
1/* 2 * File: main.c 3 * Author: Bean Dragon 4 * 5 * Created on 19 de Junho de 2015, 18:16 6 */ 7 8#include <Place/place.h> 9#include <stdio.h> 10 11int main(int argc, char ** argv) { 12 al_init(); 13 PLACE * where = place_standard(0); 14 if (!where || !where->start(where))exit(-1); 15 image_next_front(&where->image_global, image_set("Background", "G:/TheGreat/Image/Background/Nature-Green.jpg")); 16 if (!image_next_front(&where->image_global, image_set("Twinsen Front", "G:/TheGreat/Image/sprite/twinsen/twinsen-front-up.png")))exit(-1); 17 if (!image_next_front(&where->image_global, image_set("Twinsen Back", "G:/TheGreat/Image/sprite/twinsen/twinsen-back.png")))exit(-1); 18 if (!image_next_front(&where->image_global, image_set("Twinsen Side", "G:/TheGreat/Image/sprite/twinsen/twinsen-side-up.png")))exit(-1); 19 if (!image_next_front(&where->image_global, image_set("Sasuke Front", "G:/TheGreat/Image/sprite/mine/sasuke-front.png")))exit(-1); 20 if (!image_next_front(&where->image_global, image_set("Sasuke Back", "G:/TheGreat/Image/sprite/mine/sasuke-back.png")))exit(-1); 21 if (!image_next_front(&where->image_global, image_set("Sasuke Side", "G:/TheGreat/Image/sprite/mine/sasuke-side-right-step.png")))exit(-1); 22 long int id, max = 10, selected = 0, percent = (max / 100 > 0.0) ? max / 100 : 1.0; 23 double x_speed = percent, y_speed = percent; 24 where->map_set(where, object_set(0, "Map", 0, 0, x_speed, y_speed, image_search(where->image_global, "Background"))); 25 where->map->next_front(&where->object, object_set(0, "Twinsen", 320, 1000, x_speed, y_speed, image_search(where->image_global, "Twinsen Front"))); 26 int x = 0, y = 0; 27 for (id = 1; id < max; id++) { 28 x = (rand() % (int) area(where->map->width, where->map->width_zoom)); 29 y = (rand() % (int) area(where->map->height, where->map->height_zoom)); 30 where->map->next_front(&where->object, object_set(id, "Sasuke", x, y, 1.0, 1.0, image_search(where->image_global, "Sasuke Front"))); 31 } 32 STATUS camera_first_adjust = Off,destiny_ready = Off; 33 while (where->running(where)) { 34 if (!camera_first_adjust) { 35 where->camera_object(where, object_search(where->object, selected)); 36 camera_first_adjust = On; 37 } 38 OBJECT * object; 39 for (object = where->object; object != NULL; object = object->next) { 40 if (object->id == selected && timer_get(&object->timer)) { 41 if (where->mouse_left_down(where)) { 42 destiny_ready = On; 43 } 44 if(destiny_ready){ 45 object->x_route = where->mouse_x_get(where); 46 object->y_route = where->mouse_y_get(where); 47 destiny_ready = Off; 48 } 49 if (where->key_press(where, ALLEGRO_KEY_LEFT)) { 50 object->x_route = object->x - object->x_speed; 51 where->camera_object(where, object); 52 if (!strcmp(object->name, "Twinsen")) { 53 object->image_set(object, image_search(where->image_global, "Twinsen Side")); 54 } 55 if (!strcmp(object->name, "Sasuke")) { 56 object->image_set(object, image_search(where->image_global, "Sasuke Side")); 57 } 58 object->flip = ALLEGRO_FLIP_HORIZONTAL; 59 } 60 if (where->key_press(where, ALLEGRO_KEY_RIGHT)) { 61 object->x_route = object->x + object->x_speed; 62 where->camera_object(where, object); 63 if (!strcmp(object->name, "Twinsen")) { 64 object->image_set(object, image_search(where->image_global, "Twinsen Side")); 65 } 66 if (!strcmp(object->name, "Sasuke")) { 67 object->image_set(object, image_search(where->image_global, "Sasuke Side")); 68 } 69 object->flip = 0; 70 } 71 if (where->key_press(where, ALLEGRO_KEY_UP)) { 72 object->y_route = object->y - object->y_speed; 73 where->camera_object(where, object); 74 if (!strcmp(object->name, "Twinsen")) { 75 object->image_set(object, image_search(where->image_global, "Twinsen Back")); 76 } 77 if (!strcmp(object->name, "Sasuke")) { 78 object->image_set(object, image_search(where->image_global, "Sasuke Back")); 79 } 80 } 81 if (where->key_press(where, ALLEGRO_KEY_DOWN)) { 82 object->y_route = object->y + object->y_speed; 83 where->camera_object(where, object); 84 if (!strcmp(object->name, "Twinsen")) { 85 object->image_set(object, image_search(where->image_global, "Twinsen Front")); 86 } 87 if (!strcmp(object->name, "Sasuke")) { 88 object->image_set(object, image_search(where->image_global, "Sasuke Front")); 89 } 90 } 91 if (where->key_press(where, ALLEGRO_KEY_ALT)) { 92 if (where->key_press(where, ALLEGRO_KEY_Z)) { 93 if (where->key_press(where, ALLEGRO_KEY_EQUALS)) { 94 object->width_zoom += 0.1; 95 object->height_zoom += 0.1; 96 } 97 if (where->key_press(where, ALLEGRO_KEY_MINUS)) { 98 object->width_zoom -= 0.1; 99 object->height_zoom -= 0.1; 100 } 101 if (where->key_press(where, ALLEGRO_KEY_0)) { 102 object->width_zoom = 1.0; 103 object->height_zoom = 1.0; 104 } 105 } 106 if (where->key_press(where, ALLEGRO_KEY_S)) { 107 if (where->key_press(where, ALLEGRO_KEY_EQUALS)) { 108 object->x_speed += 0.1; 109 object->y_speed += 0.1; 110 } 111 if (where->key_press(where, ALLEGRO_KEY_MINUS)) { 112 object->x_speed -= 0.1; 113 object->y_speed -= 0.1; 114 } 115 116 } 117 if (where->key_press(where, ALLEGRO_KEY_A)) { 118 if (where->key_press(where, ALLEGRO_KEY_EQUALS)) { 119 object->angle += 0.1; 120 al_rest(0.1); 121 } 122 if (where->key_press(where, ALLEGRO_KEY_MINUS)) { 123 object->angle -= 0.1; 124 al_rest(0.1); 125 } 126 if (where->key_press(where, ALLEGRO_KEY_0)) { 127 object->angle = 0.0; 128 al_rest(0.5); 129 } 130 } 131 if (where->key_press(where, ALLEGRO_KEY_T)) { 132 if (where->key_press(where, ALLEGRO_KEY_EQUALS)) { 133 object->color.a++; 134 } 135 if (where->key_press(where, ALLEGRO_KEY_MINUS)) { 136 object->color.a--; 137 } 138 if (where->key_press(where, ALLEGRO_KEY_0)) { 139 object->color.a = 255; 140 } 141 } 142 } 143 if (where->key_press(where, ALLEGRO_KEY_TAB)) { 144 selected++; 145 if (selected >= max)selected = 0; 146 camera_first_adjust = Off; 147 al_rest(0.5); 148 } 149 if (where->route(object, object->x_route, object->y_route)); 150 else { 151 if (object->where == NORTH || 152 object->where == NORTHEAST || 153 object->where == NORTHWEST) { 154 if (!strcmp(object->name, "Twinsen")) { 155 object->image_set(object, image_search(where->image_global, "Twinsen Back")); 156 } 157 if (!strcmp(object->name, "Sasuke")) { 158 object->image_set(object, image_search(where->image_global, "Sasuke Back")); 159 } 160 } 161 if (object->where == SOUTH || 162 object->where == SOUTHEAST || 163 object->where == SOUTHWEST) { 164 if (!strcmp(object->name, "Twinsen")) { 165 object->image_set(object, image_search(where->image_global, "Twinsen Front")); 166 } 167 if (!strcmp(object->name, "Sasuke")) { 168 object->image_set(object, image_search(where->image_global, "Sasuke Front")); 169 } 170 } 171 if (object->where == WEST) { 172 if (!strcmp(object->name, "Twinsen")) { 173 object->image_set(object, image_search(where->image_global, "Twinsen Side")); 174 } 175 if (!strcmp(object->name, "Sasuke")) { 176 object->image_set(object, image_search(where->image_global, "Sasuke Side")); 177 } 178 object->flip = ALLEGRO_FLIP_HORIZONTAL; 179 } 180 if (object->where == EAST) { 181 if (!strcmp(object->name, "Twinsen")) { 182 object->image_set(object, image_search(where->image_global, "Twinsen Side")); 183 } 184 if (!strcmp(object->name, "Sasuke")) { 185 object->image_set(object, image_search(where->image_global, "Sasuke Side")); 186 } 187 object->flip = 0; 188 } 189 } 190 timer_start(&object->timer); 191 } else if(timer_get(&object->timer)){ // control the enemies or characters 192 if (where->route(object, object->x_route, object->y_route)) { 193 object->x_route = (rand() % (int) area(where->map->width, where->map->width_zoom)); 194 object->y_route = (rand() % (int) area(where->map->height, where->map->height_zoom)); 195 } else { 196 if (object->where == NORTH || 197 object->where == NORTHEAST || 198 object->where == NORTHWEST) { 199 if (!strcmp(object->name, "Twinsen")) { 200 object->image_set(object, image_search(where->image_global, "Twinsen Back")); 201 } 202 if (!strcmp(object->name, "Sasuke")) { 203 object->image_set(object, image_search(where->image_global, "Sasuke Back")); 204 } 205 } 206 if (object->where == SOUTH || 207 object->where == SOUTHEAST || 208 object->where == SOUTHWEST) { 209 if (!strcmp(object->name, "Twinsen")) { 210 object->image_set(object, image_search(where->image_global, "Twinsen Front")); 211 } 212 if (!strcmp(object->name, "Sasuke")) { 213 object->image_set(object, image_search(where->image_global, "Sasuke Front")); 214 } 215 } 216 if (object->where == WEST) { 217 if (!strcmp(object->name, "Twinsen")) { 218 object->image_set(object, image_search(where->image_global, "Twinsen Side")); 219 } 220 if (!strcmp(object->name, "Sasuke")) { 221 object->image_set(object, image_search(where->image_global, "Sasuke Side")); 222 } 223 object->flip = ALLEGRO_FLIP_HORIZONTAL; 224 } 225 if (object->where == EAST) { 226 if (!strcmp(object->name, "Twinsen")) { 227 object->image_set(object, image_search(where->image_global, "Twinsen Side")); 228 } 229 if (!strcmp(object->name, "Sasuke")) { 230 object->image_set(object, image_search(where->image_global, "Sasuke Side")); 231 } 232 object->flip = 0; 233 } 234 } 235 timer_start(&object->timer); 236 } 237 } 238 if (where->key_press(where, ALLEGRO_KEY_ESCAPE) || 239 where->type(where, ALLEGRO_EVENT_DISPLAY_CLOSE))where->stop(where); 240 where->camera_mouse(where); 241 where->update(where); 242 where->show(where); 243 } 244 where->destroy(where); 245 return (EXIT_SUCCESS); 246}

The code is the same in the main function. Only the speed changes.
When I try to catch the event through event.keboard.keycode or event.mouse
it makes the code slow. But when I use the ALLEGRO_MOUSE_STATE and KEYBOARD_STATE
it goes so fast. So I imagine there's something wrong in al_wait_for_event, or it
doesn't accept to be called through dll?

Since now Thanks...

torhu

It's <code> </code> for the tags ;)

APPEND:
I don't see the call to al_wait_for_event in your code, maybe you could post that part? It would also be interesting to see how you control the main loop speed.

By the way, you have a lot of code duplication. For starters, I would use a switch instead of a bunch of if statements. And you don't need to repeat things like where->key_press(where, ALLEGRO_KEY_ALT) a million times. Keep it short and clear, split the code into functions or macros if you need to. Also, I would probably keep the input information in a struct INPUT, not inside PLACE. And I'm not sure why you use function pointers, but maybe you have a reason ;)

Lísias de Castro

The part of the code that updates the events is just the running function.
And here it is:

PLACE_CALL STATUS PLACE_TYPE place_running(PLACE * to) {
    if (to && to->machine.running) {
        al_wait_for_event(to->machine.plugin.event_row,&to->machine.plugin.event);
        al_get_keyboard_state(&to->machine.plugin.key); // the keyboard and
        al_get_mouse_state(&to->machine.plugin.mouse); // mouse only responds fast
        return (On); // if I call the state's functions
    }
    return (Off); // if I only try with al_wait_for_event it goes slow
}

Thanks for let me know about how to use the tag code in here.
I use to do [code] like this.
And about the key, I changed the code. See if it is better now. About the function's pointer, I like using this way, for the C to be more like oriented object. I have tested the engine with about 1.000.000 objects and it was running in my i5 with 4gb. ;D

torhu

Calling al_get_keyboard_state and al_get_mouse_state should not make things go faster. The problem has to be somewhere else in your code. Remove the calls to al_get_keyboard_state and al_get_mouse_state, and try to get your code working without them. Print some logging information to see where in your code you are, and what the values of important variables are. Maybe even just putting things like `fprintf(stderr, ".");` in the loop, then you can see how often it runs, where the delays are, etc.

Lísias de Castro

As I said, I have tried to use the code without the state's function, but it goes slow and I had to rewrite all the parts of the keyboard and mouse calls. If I hadn't I wasn't disturbing you guys.. be sure about that. I did the same code with other graphic library and it worked, but when I tried to use it on linux, it didn't show some images. So I changed to allegro again. I thing I got a little experience now. ::) I have watched the device manager and it doesn't see to have any memory leak. it is running smoth. What should be the next step dude?

here is one of the codes that responds normally(repair it has the sugested printf() testing it, but I commented it because this way there's no problem):

#SelectExpand
1PLACE_CALL STATUS PLACE_TYPE camera_mouse_move(PLACE * to) { 2 if (to && to->map && to->machine.plugin.event_row) { 3 ///printf("x:%d y:%d\n",to->machine.plugin.mouse.x,to->machine.plugin.mouse.y); 4 int space = 25; 5 if (to->machine.plugin.mouse.x > 0 && to->machine.plugin.mouse.x <= space) { 6 to->map->x -= to->map->x_speed; 7 } 8 if (to->machine.plugin.mouse.x >= to->machine.width - space && 9 to->machine.plugin.mouse.x <= to->machine.width) { 10 to->map->x += to->map->x_speed; 11 } 12 if (to->machine.plugin.mouse.y > 0 && to->machine.plugin.mouse.y <= space) { 13 to->map->y -= to->map->y_speed; 14 } 15 if (to->machine.plugin.mouse.y >= to->machine.height - space && 16 to->machine.plugin.mouse.y <= to->machine.height) { 17 to->map->y += to->map->y_speed; 18 } 19 return (On); 20 } 21 return (Off); 22}

and here is the slow code:

#SelectExpand
1PLACE_CALL STATUS PLACE_TYPE camera_mouse_move(PLACE * to) { 2 if (to && to->map && to->machine.plugin.event_row) { 3 ///printf("x:%d y:%d\n",to->machine.plugin.event.mouse.x,to->machine.plugin.event.mouse.y); 4 int space = 25; 5 if (to->machine.plugin.event.mouse.x > 0 && to->machine.plugin.event.mouse.x <= space) { 6 to->map->x -= to->map->x_speed; 7 } 8 if (to->machine.plugin.event.mouse.x >= to->machine.width - space && 9 to->machine.plugin.event.mouse.x <= to->machine.width) { 10 to->map->x += to->map->x_speed; 11 } 12 if (to->machine.plugin.event.mouse.y > 0 && to->machine.plugin.event.mouse.y <= space) { 13 to->map->y -= to->map->y_speed; 14 } 15 if (to->machine.plugin.event.mouse.y >= to->machine.height - space && 16 to->machine.plugin.event.mouse.y <= to->machine.height) { 17 to->map->y += to->map->y_speed; 18 } 19 return (On); 20 } 21 return (Off); 22}

torhu

Your code looks a little better now, but still lots of code that looks very similar. I'm also wondering why you have lots of ifs but almost no else causes.

I think code like this:

 if (!strcmp(object->name, "Twinsen")) {
                        object->image_set(object, image_search(where->image_global, "Twinsen Back"));
                    }
                    if (!strcmp(object->name, "Sasuke")) {
                        object->image_set(object, image_search(where->image_global, "Sasuke Back"));
                    }

Should be just:

object->direction_set(object, NORTH);
The object should know what to look like.

What should be the next step dude?

Listen to what people with experience tell you (and do some debugging) ;D

APPEND:
I don't see the difference between those two pieces of code.

Lísias de Castro

About the debbuging, I use to do this always. But when I check the code, and there's no problem there, I use to comment it for the program not to go slow. When I changed the code to state and it did work well I commented the printf function.
And about the direction, I don't want to do a function like direction_set, because functions make the program slower than to call the variable directly on the main loop I guess. I reduced the number of functions in order to speed up my code.. And about the verification of the character, I couldn't figure out a way to make it better, if you have a suggestion I would appreciate. Thanks :D 8-) ... ah, about the ifs, I didn't use else, because I could see no reason to use. Because when you use else, you can only do one of the works, but when you use only ifs, it doesn't deppends on the other parts. And about my english, its a crap I now... but here in Brasil the don't care a shit about study. :(

torhu

And about the direction, I don't want to do a function like direction_set, because functions make the program slower than to call the variable directly on the main loop I guess. I reduced the number of functions in order to speed up my code..

You probably would not notice the function call overhead in your code, it probably takes thousands of extra calls per second for it to matter. And having the same code many times can also make your code slower, because there is more code to transfer to the CPU, and it takes up space in the CPU cache that could be used for other code instead. But what always matters is how readable and maintainable your code is 8-)

Lísias de Castro

This is exactly the "L" of the question. I think I should not to call any more functions than those... only if it is really necessary. Don't you think that if I use object->direction_set instead of object->where = direction it will be more slow? ??? and do you think my code is not readable enough? if yes, what should I do to make it more readable?

torhu

Shorter code means less code to read, less code to understand, less code to debug, less code to change, a larger part of the code on screen at the same time, etc. Less is more.

If you have several copies of the same (or almost the same) code, you are probably Doing it Wrong™ :(

Lísias de Castro

All right. But the above code has many codes which look like the other, but each one do a different thing... if you don't show me where I shall change I won't guess it.... This is the best way I could figure the problem out. So if you have I suggest to improve my code, please post it. But until now I could not have any Idea on how to fix the al_wait_for_event's problem. :-/

torhu

I already gave a concrete example how to shorten your code ;)

If you want, I can try to debug and fix your code. Then you have to upload all code and graphics, so I can debug it here.

Lísias de Castro

I can post it if you will... but I have no idea on how to do this through the forum. Could you explain me, please? ;D

torhu

Just attach the files to your reply. I think I won't be able to look at it until tomorrow, but I think you can just replace the files with new ones if you change your code in the mean time.

Lísias de Castro

Alright brother. I am posting only the library place.
Because the main.c is in here yet.
In the place's zip there's more than one folder, because of the auxiliar libraries that I made, like symbol, status, timer, object, allegro5_plugin, etc. Thanks for your patience dude. 8-)

torhu

You forgot the images, I can't run it without them ;)

Lísias de Castro

My bad... I put the images into a folder named image.. inside it there are 2 folders. The background and the sprite folder. You will have to make some modifications on the directory in main.c... but I think you will figure it out easy. And, I don't know if you got it, but I reimplemented the timer function... The objects are now controled by time in the main.c. 8-)

torhu

Well, I got it to build in VS 2008. Now I just need the version of your code that has event-based input, have you still got that?

Lísias de Castro

I don't have it anymore dude. And I have found a bug. I think I won't be able to be using the library symbol.h. I works for a while and somewhere it crashes away.
I have ran it in gcc - mingw with netbeans... did it runs well in VC? ???
I will take a little time now and try to reimpletent it through event. As soon as I get it done I will post the code.

torhu

There was a missing return statement in symbol.c, funny the compiler didn't warn you about it. That could be why it crashes.

It works just fine in VC. I had to change the code a bit, VC 2008 doesn't support C99 features like having declarations after statements.

By the way, I can recommend using some sort of version control. I use Mercurial for everything, even your code now. It's very convenient ;)

I'll look at your new code when it's ready 8-)

Lísias de Castro

The animations played well ??? ;D
I posted the place's folder again.
This time it has the code you have
and one more file named "place_old.c"
This file is using al_wait_for_event.
I tried to run it here and it continued
to respond slow. The only way it to
respond fast and without bugs was
through state's functions... :-/

And about this version control, do you
mean to make some defines with macro? ???

Thomas Fjellstrom

And about this version control, do you
mean to make some defines with macro? ???

Nope. Things like git, mercurial, subversion, sourcesafe, cvs, etc.

Lísias de Castro

I have never used them before..
What's the purpose of the programs?
I have found the site, but it doesn't
explain how to use...
Thanks ;D

torhu

Thanks, I'll look at it tomorrow. From what I can see right away, there are some problems. This is how I do it:

  1. When you get an input event, update the mouse and keyboard state in the game. Do this in a loop until you get a timer event.

  2. Then run the game logic (move stuff, change how things look, etc).

  3. Now, if al_is_event_queue_empty returns true, update the screen. If not, goto 1.

About the version control, maybe this can explain it: http://hginit.com/01.html

Lísias de Castro

I have tried to use the techniques that you told.
But the character disappeared sometimes and the
loop had the same results(I mean slow).

Thomas Fjellstrom

Events are only slow if you don't make sure to drain/use-up all the events before drawing the next frame. They back up, and will start slowing all input and rendering down.

Lísias de Castro

If this way I am using is wrong, why it does work when I catch by the state's function?!
The al_wait_for_event behavior is not the same as al_get_keyboard_state and al_get_mouse_state. It is working normally with the last 2, even with a lot of objects on the screen. Behind them there are great deal of memory to handle, and even so it works well with those damned functions ??? ...
I will wait for thoru's answer in order to see if he could figure the bug out.

Thomas Fjellstrom

State doesn't get backed up if you don't check it often enough. Events do.

Try this.

Lísias de Castro

Hey Thomas. I have tried exactly the way you show me right now.
But it kept in the same way as before. The only choice I am seeing
now is continue to use the al_state functions. When I try to use
the function camera_mouse_move which catches the axis from the mouse,
it only updates when I move the axes. This way I am not able to do a
function like "mouse_over". Because I have to move the mouse to prove
it is in somewhere. Otherwise, with al_get_mouse_state, I don't need to
move the mouse to verify that it is in somewhere in on the screen.
I think the problem here is the way the function al_wait_for_event was
designed to. I think it has been designed not to get a lot of memory from
the program, but it coast some important factors. :(
About the keyboard.keycode, it is not very good either, because I am only
able to get one key at time. While with al_get_keyboard_state I am able to
use multiple keys, just like on the example I posted in here. It's a shame
that the events catched by al_wait_for_event does not work like that... I
guess it could be using less memory in the whole system. :'(

Thomas Fjellstrom

That same code and code like it works great for many people. It is extremely likely you are doing something wrong.

I don't need to
move the mouse to verify that it is in somewhere in on the screen.

You can just store the last position of the mouse somewhere and use that :P

Quote:

it coast some important factors.

It really doesn't.

Lísias de Castro

By creating two more variables I am getting more memory from the system in anyway.
It could be really wise doing this? ???

Thomas Fjellstrom

Two integers isn't going to make a lick of difference. The state functions create a much larger struct to store its data.

Lísias de Castro

But this suggestion could only solve my mouse problem. What about the keyboard, there is a way to get multiple keys through events too? ???
And thinking about structures, If I don't register the mouse and keyboard events inside the event_row it won't get my memory I think. Can you tell me if those registers that I did not do could be worth the variables state. Instead of load the mouse and keyboard register I load the keyboard and mouse states.

Thomas Fjellstrom

But this suggestion could only solve my mouse problem. What about the keyboard, there is a way to get multiple keys through events too?

Each key press comes with one or more (usually more) events. A KEY_DOWN, a KEY_UP and sometimes a KEY_CHAR (sometimes many if key repeat is on).

When you get an event, you store it in your game some place where you can check to see what keys are pressed. With events you can even avoid losing key presses. With the keyboard state struct, you always store all key state. if you stored it yourself, you'd only have to store what keys you need.

torhu

I don't think I have anything to add, I agree with Thomas ;)

Lísias de Castro

All right. So I have to figure out how to do it myself.
Anyway thank you all.

Neil Roy

You seem to me to be worried about all the wrong things. Function calls slowing things down by an amount that nobody can notice and 8 bytes of memory taken up by using two variables to store values, when you're program is slowing down.

I have variables I store the values into, if someone cannot afford 8bytes of memory these days, it's time to take up a new hobby, knitting maybe. ;)

I use all of the suggestions that Thomas and torhu suggest and my games run smoothly. Actually, I can think of a few improvements after reading this (I probably don't use enough functions either). About functions, your compiler can do some things which make these just as fast, inline functions etc... for example, so I wouldn't worry about those. The benefits you gain from organizing your code far outweighs any speed or memory losses you will get! When you have repeating code, you have an increased chance of getting a bug that will be more difficult to track down. Also, you can update a function and you're done, no need to search through your code and update who knows how many lines of code (and if you forget to do one, as I have, you are really screwed because they can be a bitch to track down!).

Another thing is that the event queue can be cleared if you think it is getting bogged down, although I prefer to deal with what is in there, that could be a solution depending on your situation.

Personally, I have a key array where I store the state of each keypress as it comes in (thereby emptying the queue) then dealing with them later on and resetting the key state in that array. This becomes very important if someone is holding down a key and the queue is getting filled up with that keypress, you want to clear it out of there. Same for the mouse.

I would also check your timers, make sure they're set properly. Try profiling your code to see where it is being slowed down etc. But the problem is not with Allegro.

In my own Deluxe Pacman 2 game, my main game loop is something like this (I can't post the actual code, it is too lengthy)

(coded in C 2011, so some may need to be altered for VC)

#SelectExpand
1while(!done && !pacman.dead) { 2 al_wait_for_event(event_queue, &event); 3 4 switch(event.type) { 5 case ALLEGRO_EVENT_DISPLAY_CLOSE: 6 // do stuff here 7 break; 8 case ALLEGRO_EVENT_KEY_DOWN: { 9 int k = event.keyboard.keycode; 10 switch(k) { // deal with some keypresses here 11 case ALLEGRO_KEY_ESCAPE: 12 // do stuff here 13 break; 14 case ALLEGRO_KEY_UP: 15 // do stuff here 16 break; 17 } 18 // store all keypresses here 19 pressed_key[k] = true; 20 break; 21 } 22 case ALLEGRO_EVENT_KEY_UP: { 23 int k = event.keyboard.keycode; 24 switch(k) { // deal with some key up events immediately 25 case ALLEGRO_KEY_LCTRL: 26 case ALLEGRO_KEY_RCTRL: 27 // do stuff here 28 break; 29 } 30 // reset key array member to indicate it is no longer pressed 31 pressed_key[k] = false; 32 break; 33 } 34 case ALLEGRO_EVENT_TIMER: 35 // update player and enemy movement here 36 } 37 38 if(redraw) { // set true usually when there is movement or timer etc 39 // update display 40 } 41}

Note, I don't have mouse code in here, but I would deal with it by adding in a new CASE to do with it as I do keyboard if needed and setting variables to store the mouse values. Variables only take up 4 bytes of memory (8 bytes for 64bit) so when modern computers measure RAM in the gigabytes, I wouldn't worry about a few extra variables. ;)

Thomas Fjellstrom

Neil, that loop doesn't seem to be draining the event queue every frame ;) Maybe you trimmed a little too much out when posting?

Neil Roy

Neil, that loop doesn't seem to be draining the event queue every frame ;) Maybe you trimmed a little too much out when posting?

Hmmm... you seem to be right about that. I may need to insert a while loop in there to drain it. Never noticed that before, but then it never slows down or causes me problems. I may have to do that. :)

Edit 2: OH, I see what you are talking about, yeah... I did leave some out! I probably shouldn't have as it is the point of it all... but my display update part ACTUALLY looks like this! ;)

if((redraw == true) && (al_is_event_queue_empty(event_queue) == true)) {
   redraw = false;

   if(!update_screen(cplayer)) {
      shut_down();
      exit(1);
   }

   al_flip_display();

   frames++;
   fps = (double)frames / (al_get_time() - start_time);
}

I guess I did trim that down a tad too much. :P (not sure why I put `== true` in there)

Anyhow, that will not redraw t he screen while the queue is not empty, so it just runs in that loop handling all the events before it updates the display and continues.

Bruce Pascoe

@Thomas:
So draining the event queue (as via while loop) is encouraged then? I remember reading in another thread here that the common wisdom is not to do that, but rather to only pump through one event at a time. I don't remember what the thread was now...

Thomas Fjellstrom

@Thomas:
So draining the event queue (as via while loop) is encouraged then? I remember reading in another thread here that the common wisdom is not to do that, but rather to only pump through one event at a time. I don't remember what the thread was now...

The only argument I know about is really just a stylistic choice.

while(!done)
{
  wait_for_event(&evt);
  if(evt.type == TIMER)
  { 
    draw == true;
  }

  if(draw == true && queue_empty(queue)) 
  {
    drawStuff(); 
  } 
}

Vs.

#SelectExpand
1while(!done) 2{ 3 while(!queue_empty(queue)) 4 { 5 if(!get_next_event(&evt)) 6 break; 7 8 if(evt.type == TIMER) 9 { 10 draw = true; 11 } 12 } 13 14 if(draw) 15 { 16 drawStuff(); 17 } 18}

I happen to prefer the former, with the single loop. But they are functionally equivalent.

Neil Roy

I happen to prefer the former, with the single loop. But they are functionally equivalent.

Agreed. I may change my code to look more like the second example you posted though. The extra loop makes it more readily apparent as to what it is doing, which to me is more important.

I am wondering though if this setup could possibly lead to some "hiccups" in the game? That is to say, you're playing it and the characters seem to jump perhaps or possible delays due to an event queue being too full? On faster systems this would probably not be an issue, but on slower systems I am wondering if it would be? Maybe extra code in there that sets a limit on how long the game stays in that loop emptying the queue before perhaps it is forced to redraw.

Thomas Fjellstrom

If you have too many events to handle in a given frame, the drawing of that frame may be skipped. Basically what the loops do (when they check for the queue being empty) is give you "frame dropping" in case your loop takes too long to execute in the time you asked for given the logic timer. You can get two or more timer events in the queue, but not actually act until the queue empties.

If things are SUPER slow, you're just never going to render. At that point you want to force a minimum draw interval. that slow's the actual logic, but it may be better than never rendering anything ;) In the end, dropping too many frames or slowing logic is usually bad and you need to be able to reduce the complexity of your scene and/or logic to get back to a decent frame and logic rate.

Lísias de Castro

Well. I have looked in many sites and could not discover out a single way to deal multiple keys with keyboard.keycode. This code that Ney have posted can't show either.
So I decided to knit. I've heard the allegro community was the best helping people... :'(

Thomas Fjellstrom

This code that Ney have posted can't show either.

A single event carries one key. But you can store key state in your code, so you can then check to see if more than one of the keys you care about are currently pressed, and for how long as the event carries the time the key was first pressed.

You don't have to process your movement logic when a key is pressed, rather you handle it when you do you get your logic timer event.

Quote:

I've heard the allegro community was the best helping people... :'(

We're not bad. But it seems to some of us that you've been ignoring helpful advice and just want us to give you code.

What I (and others) suggest is in the key down event, you store the key state in an array like Neil suggested, in the key up event you clear that state, and in your timer event, you process your logic, like movement, and actions based on the current state stored in your array. That way, you can tell that multiple keys are pressed, and logic happens at even intervals, instead of whenever you get input events.

I'm basically trying to get you to understand what you need to do so you can do it yourself, rather than giving you the solution as code. Give a man a fish, etc.

Neil Roy

I've heard the allegro community was the best helping people.

This community is helpful, but if you're looking for someone to write code for you, you might want to hire someone. I doubt you will get much better anywhere else.

I just posted my own code (or a skeleton of it) that works for me.

Quote:

Well. I have looked in many sites and could not discover out a single way to deal multiple keys with keyboard.keycode.

If you need more than one key to be pressed at the same time, than you need to avoid things like:

if(ALLEGRO_KEY_A) {
  // do stuff if 'A' is pressed
}
else if(ALLEGRO_KEY_B) {
  // do stuff if 'B' is pressed
}
else if(ALLEGRO_KEY_C) {
  // do stuff if 'B' is pressed
}

The above code will only respond to one keypress at a time.

if(ALLEGRO_KEY_A) {
  // do stuff if 'A' is pressed
}
if(ALLEGRO_KEY_B) {
  // do stuff if 'B' is pressed
}
if(ALLEGRO_KEY_C) {
  // do stuff if 'B' is pressed
}

...the above code will respond to every keypress, like when more than one are pressed.

You might want to create a key array like key_pressed[] and set the keys that are pressed, then you can deal with them later in your code with...

k = event.keyboard.keycode;
if(key_pressed[ALLEGRO_KEY_A] && key_pressed[ALLEGRO_KEY_B]) {
  // do stuff if both keys are pressed at once
}

If you look in the code I posted earlier you will see I do precisely that. I deal with certain keys that need to be dealt with immediately, and the rest are stored in the array to be dealt with as needed. In my game I detect two keys at once for example if the player presses CTRL+ARROW, the game knows to speed up in the direction pressed.

It's really straight forward coding. If you don't know how, you will need to experiment and think it through like everyone else. It's why you don't see everyone programming. :)

torhu

If he's going to store the keyboard and mouse state anyway, he might just as well use Allegro's state functions :P

Another way to do it when using events is to do the relevant movement logic as each event is received. That way nothing gets missed, and the order of keypresses is not partially lost.

Thomas Fjellstrom

I don't think you actually want to do the logic as soon as the events come in in all cases. It really depends on what you want to do. Maybe tell the "thing" that some event came in, and then it handles that in its logic update. In the end it just moves the state around.

Thread #615529. Printed from Allegro.cc