I'm new to this event system, and nobody around me knows what I'm talking about. I'm about two weeks into Allegro, and this has been bugging me.
Here's a snatch of code I'm working on, everything is initialized;
Suppose I press the X button before I put in a number. I'm trying to get the third if, the getevent line, to understand that there is an event in the queue and act accordingly. This code serves no actual purpose, but I want to understand exactly how queues store data. I thought the queue would store the input, and then getevent would recognize that there's something in it and save the event in ev, which the next piece would pick up. But in practice, the line doesn't return true.
If somebody could explain this, rather than correct this, I'd appreciate it.
You should have a single "message pump" loop something like this:
Alright, I was wondering if you could explain some things:
Also, I'm confused how al_get_next_event can work with only one argument. I need to give the queue, right?
Yes, that's where I got this.
bool al_get_next_event(ALLEGRO_EVENT_QUEUE *queue, ALLEGRO_EVENT *ret_event)
Take the next event out of the event queue specified, and copy the contents into ret_event, returning
true. The original event will be removed from the queue. If the event queue is empty, return false and
the contents of ret_event are unspecified.
It still looks like it needs two parameters. Unless I'm misunderstanding something.
Yes, it needs both arguments.
Okay, that makes sense.
Let me see if I get the gist here; the event queue almost always has something in it; a timer. Every tick kicks the previous event out of the queue, so that's why the program wouldn't just "remember" the close button. But then why do we keep checking if the event is ALLEGRO_EVENT_TIMER and passing the location based off of that? The timer is always ticking, so all the program would do is act off of the autonomous timer and wouldn't react to user input like DISPLAY_CLOSE, right? I know that's not how it works, but then where am I misunderstanding this?
Queues can hold an infinite number of events. Nothing is removed from the queue until you take something out of it. Functions like al_get_next_event() and al_wait_for_event() removes the oldest element off the queue. You process that event. Then you wait for the next event, etc.
...Dammit, now I'm confused again.
Let me run this one by you; The al_get_next_event sees the timer's tick, then gets rid of it and copies it into event. Have I got it so far?
But the rest of the code only works if the event type is ALLEGRO_EVENT_TIMER. The event holder can only hold one event, right? So what is the point of repeatedly going through input if all you're passing is the location of event, which is holding a timer tick? Or is there an difference between an event queue and ALLEGRO_EVENT event?
Normally the queue would hold a variety of event types: a timer tick, a mouse movement, a key press, a close window, etc. You can register one or many different sources to the same queue.
So you copy (move) the event out of the queue, check what type it is, and do something. Repeat.
Is it just implied that there's more than one source? Here's what I'm seeing:
if (event.type == ALLEGRO_EVENT_TIMER) {
input(&event);
The first line checks if the event holder is a timer tick, and the second line uses the event, that tick in input. All that is being used in this example is the ticks. Nothing but. There is no check if the event is a mouse input, or a display close. Why would the input be concerned with the timer? What purpose is there to carrying the timer tick to input? Or am I supposed to just use this as a template and add my own checks for events? Something like:
Does this even make sense? Are my thoughts coming through at all?
I don't understand Trent's example either. Perhaps he assumes you aren't going to use events to process input, and instead are just going to poll keyboard/mouse states and look at the event's timestamp.
For games it's easiest to process everything all at once per timer tick. While using events for input guarantees you won't lose any data, it means you have to somehow work that into your timer logic.
So some people take the lazy approach because it usually works without any problems: just check for timer ticks, and then use al_get_keyboard_state() to check if a certain key is pressed at that moment in time.
...and then react to it, right? The poling method just checks over and over if a key is pressed, then performs some action based on the poll results?
That kind of makes sense... I'm away from my Visual Studio at the moment, let me get back to you tomorrow.
If you use input polling, you would still wait for a timer tick. Once you get a tick, you poll the keyboard state once and then check to see if whatever keys you are interested in were pressed.
The whole point of the timer tick is to make sure your game runs at a constant speed. If you know you are always checking 60 times per second, then you can simplify the rest of the logic. e.g., If the LEFT key is pressed during that tick, you might move your character over by exactly four pixels.
Maybe it'll help if I explain the event loop from the wiki:
Hope this helps.
Before I take the time to write something, have you read the tutorial on the wiki? you know those which says events and input?
I followed the tutorials, and I get the individual examples, but the tutorials don't cover anything other than that specific example.
Anyway, I tried building a routine that checks whether there's input on the display, and passes the event to another function that deals with the event. Suppose I click on the X button;
Of course, this doesn't work. The input doesn't doesn't recognize that the event coming in is the display close.
I know that there are easier ways to pull this off, but I want to makes sure I can use this kind of setup to receive mouse or keyboard input. I still don't think I'm understanding the queue thing, or I'm not thinking properly. Sorry for sticking with this problem, but I'm going to have to learn this if I'm going to get close to designing my own game.
I think you're thinking about this the wrong way. Just because there is a timer event in the queue doesn't mean there is another event in the queue, so you may be waiting a while until that event comes.
The event queue will give you the oldest event first, and the rest in ascending order of time received. You could get a key / mouse click event at anytime, and it has nothing to do with a timer event or with a display close event. Don't expect events in any certain order, or you will be disappointed. They will be in the order they happened, but that is all you can expect.
1) When you get a timer event, you should probably set a redraw flag, and you need to update any objects that you have by the amount of time passed.
2) When you get a display close event, then break out of your program loop.
3) When you get other events, send them to each of your objects so they can deal with them as that is the input in your program.
So something like this might work better for you :
This kind of event loop only draws when the timer ticks, will wait for the next event before continuing on, and will process all events that are in the queue before redrawing again.
So something like this might work better for you :
Which seems to be functionally equivalent to the one in the tutorial.
Eh...
Repetition helps reinforce memory?
Okay, I think I get it now... kind of... I see the problem with the code. I have other problems with this, but this is all I have on the subject of event queues.
Thank you so much, everyone. I appreciate it.
Actually, the loop I posted should be using al_wait_for_event, not al_get_next_event. I edited it to fix that, and made the drawing code clearer as well.
It's not quite the same as the wiki because of the explicit calls to Update, ProcessEvent, and Display, but the principle is the same.
It's not quite the same as the wiki because of the explicit calls to Update, ProcessEvent, and Display, but the principle is the same.
The only difference is that the wiki example is so simple it doesn't use separate functions to handle updates, events, or displays. Otherwise its functionally identical.
Reynaldo is right, though, I like seeing the same thing done different ways.It makes it a bit easier to understand what does what.
The major difference is that his nests an extra loop, which isn't really necessary, since we can just skip over the drawing if the queue isn't empty. But I suppose it might be a little easier to follow.