How do you read input? Do you have some function, say, GetKeyboardState, that constantly polls the state of the keyboard and returns which keys are pressed in some gigantic array? Those of you using DirectInput probably know what I’m talking about. Further, how are you passing information between your various subsystems? Do you have some series of complicated interfaces, where classes are forced to know about each other and are forced to change regularly in regards to some minor change in another class? Or are you just shoving information through your system haphazardly, hoping it gets to the right place when it needs to be there?

I’m here to show you a better way.

I expect my audience to have some knowledge of basic object-oriented programming. The two main things you need to understand are what a class is and what an interface is. Implied in this is some passing knowledge of inheritance.

I also make the following disclaimer: this was written at 2 AM, when my eyes were glazed over and my mind was not its sharpest. I apologize if there are errors/typos, and I will do my best to fix anything wrong as it is pointed out to.

A Brief Introduction to Event Passing
Here’s how event passing works, in a simple form:

Some system registers (through a central manager or some other means) for a specific event type. Event types represent the different information that passes through your system. For instance, if the system wants to listen to keyboard events, it would register for a KEYDOWN or KEYUP event.

Then some system fires the event. In the above example, your keyboard handling code would do the firing. When an event is fired, it gets sent to all those that are registered to listen. The listener then determines how to handle that event as it sees fit.

That’s it.

An Argument for Event Passing
What I have above is very simple, but the elegance it can bring to your code is significant. So significant, in fact, that I view it as having the single most profound impact over the way I program.

Take our example above. Let’s say you switch from DirectX to SDL to handle your input. In a polling method, your entire interface might change (although a well designed interface probably wouldn’t). This would require *every* place where you handle input to change. Ouch. In an event driven method, however, nothing changes. Listeners don’t care how they’re getting the events - they don’t care about the source; often they don’t even need to know about the source. They just receive the KEYDOWN event and move happily on their way, oblivious as to whether a DirectX or SDL implementation is pulling the strings.

But let’s move beyond simple input to something else: player tracking. You may have a lot of different systems keeping track of where the player is moving. Does it really make sense that all those systems should have some kind of pointer to the player, knowing its every detail, and further breaking if the specifics of the player change? Not really. But with an event driven scheme, you could be much cleverer about it. Whenever the player moved, you could fire an event, PLAYERMOVED. Anyone interested in this event could then register for it and respond to player movements while being absolutely independent of how the player is handled. Further, if the player is completely removed, you don’t need to do anything special - the player simply stops sending events, and thus there are no events to respond to.

Let me take an example from a piece of code I was working on recently (it’s a non-game related example, so it’s a bit boring). I had a document saving, and whenever that document was saved, I wanted to do some post processing. Sure, I could’ve had the document saver interface with the post processor itself, but this was illogical - why should the document saver need to know about things outside its scope? So I had the document saver fire a quick event, DOCUMENTSAVED, and the post processor listened for that event. Now if I wanted to yank out the post processor or even add another post processor, I wouldn’t need to change (read: break) the document saver at all; I would simply register or not register the post processors as necessary.

There’s a good chance I haven’t convinced you. To be honest, I wasn’t fully convinced when someone first introduced me to the concept If you’re not convinced though, I encourage you to give event passing an honest try. Try it out for one significant project, and you’ll really see the benefits it brings you in code flexibility and maintainability.

A Simple Implementation
I’m going to write this in a very abstract manner (not tied to any specific language). If you’d like to see an implementation, I’d be more than happy to provide some source code.

The first thing we need to define is the concept of an Event. There are about a hundred different ways you can go with this. The way I’m going to show you is flexible and simple, but it is very type-unsafe and slightly inefficient.
An Event has the following:
a type
a list of parameters

The type is pretty self-explanatory; it’s what I’ve been talking about this whole time. KEYDOWN, KEYUP, MOUSEMOVED, MOUSECLICKED, PLAYERMOVED, PLAYERDEAD, etc, are all valid types.

The parameters are values associated with the type. For instance, when a KEYDOWN event is fired, you need to know which key, right? Wouldn’t be much use otherwise. If the MOUSEMOVED event is fired, you need to know the new location of the mouse. And so on. How you choose to set/retrieve these is completely at your discretion. You might have a bunch of different lists storing each different type (float, string, etc) of parameter. For the C#/Java programmers among you, you may wish to have a Vector of Objects that you can cast appropriately.

The next thing we need is an EventListener. As the name so eloquently mandates, an EventListener is something that listens for events. In my implementations, the EventListener takes the form of an interface with one pure virtual method, OnEvent(Event e). Classes which implement EventListener must implement that method. So you might have a player class with code like the following:

Player implements EventListener
OnEvent(Event e)
if (e.type == KEYDOWN)
if (e.param(0) == DOWN) MoveDown()

And then, finally, you need something to register the event listeners to and pass the events along. Like so:

PostEvent(Event e)
RegisterListener(EventListener listener, EventType type)
UnregisterListener(EventListener listener, EventType type)

These are pretty self explanatory, so I won’t say too much about them. RegisterListener simply indicates that a listener should listen to a specific type of event, and UnregisterListener undoes that. PostEvent sends the event to every listener listening to events of the same type as the one posted. How you implement that is up to you, but I might recocmmend looking at Dictionary (C#), HashMap(Java), or std::map(C++).

And that’s all you need. Now when you implement an EventListener, you simply Register it with your EventManager (I often make the EventManager global, since it gets used a lot). When you want to post an event, you post it (along with all its parameters) to the EventManager, which handles passing it along to all your listeners. They EventListeners are free to go on with their merry lives, doing whatever naughty things they want to do with the events.

Other Ways to Implement This
I make no guarantee that the above way is the best way, and I’ll actually outright say it isn’t. But it’s been sufficient for most of my indie needs.

One potential improvement is to make the system more type safe. You could start by specifying a base Event class and then subclassing that for each type of Event, where each subclass contains the necessary parameters. This is safer, more self-documented, and probably more efficient.

Another is to consider using signals (boost::signals, for the C++ programmers among you, or the ‘event’ system already built into C#). These can help avoid the monolithic, all-powerful “EventManager” class that I introduced. Also, depending on your language, they can be safer than having your EventListener be an interface.

Well, there you have it. A fully event-driven system. I promise, if you give it a shot, you’ll find it does wonders for your programming.
And as this was written for a forum, by all means, post your own solutions/advice/recommendations/author-hating-slurs.