[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Event handling

Ian Crawford wrote:

> > It probably needs a layer on top of this. Based on a rant by John
> > Carmack in his .plan, I had the idea of doing an unified event system,
> > that has most everything as event emitters or sinks. For example, the
> > timer is an emitter, and sound and video processing are sinks for it.
> > Anyway. Too much vapor for the moment, I'll shut up.
> I've chosen to handle events a little differently in my game.  I've
> written a very simple event queue class (Yes, a class.  I using C++
> because I think OOP just makes sense... call me weird...) that events
> can be appended to as they occur.  Somewhere in the main loop, they are
> processed.  I've done this because game events can be generated by any
> number of things: user input, network traffic, a collision, someone's
> health dropping to 0, a certain time being reached...  I've found this
> quite easy to work with, so far.
> I like you idea of emitters and sinks, though.  If you ever get
> something like this going, I'd love to see it in code.

That idea is from the Java 1.1 event model. It is a generalized version
of what you said. Instead of processing everything in the main loop
(with something like a giant switch statement), sinks subscribe to
emitters, which will send events directly to the interested sinks.

For example, think of a game with a Quake-like console. You have a
keyboard input emitter and two sinks (for that kind of events), one for
regular game input, and another for console input. When the player
presses the console key during the game, the game input sink object
either unsubscribe itself from the emitter or simply start ignoring the
events, then it activate the console, which activate its console input
sink, which subscribe itself to the keyboard input emitter to get the
keyboard events. When the player closes the console, the console and its
sink are destroyed, unsubscribing the sink. The game sink object
resubscribe itself (or stop ignoring events) and everything is back to

The advantage is that objects will only see the events they are
interested in, and that there is no cascading of events like some OO
event models (a big switch with a default sending the event to the next
object in the chain), which incurs a lot of method calls, slowing things
down. Performance goes up, since only the objects interested in the
event will be invoked.

The downside is that it adds bookkeeping, emitter keeping tab of all the
sinks they must send events to, sinks remembering to unsubscribe
themselves in due time (usually in the destructor)...

Interestingly, I am reversing from my idea and no longer think it is
good for games. That emitter/sink model is excellent, but it lacks
serialization of events, since they don't go thru a single event queue.
But it could be adapted, with instead a single emitter (the event queue)
and multiple sinks which the queue automatically hands the events as
needed (no need to poll the queue).

But the most innovative idea in the Carmack rant was to make
*everything* into an event, including time, so that just recording the
events occuring would enable perfect demo recording, unlike Doom (which
could get "out of sync"). You could even automate testing using this,
and you're not even forced to follow real-time, you can make testing a
batch job! For example, say you emit a "time tick" event every 10 ms. In
a real game, the tick would happen every 10 ms, as supposed to, but you
could batch-test games by simply sending them as fast as possible, with
the necessary input in between the ticks. The game would go very fast,
but the game would be identical to when it was recorded, just faster!

Pierre Phaneuf
Ludus Design, http://ludusdesign.com/