12
\$\begingroup\$

I guess I've decided that I really like event handlers. I may be suffering a bit from analysis paralysis, but I'm concerned about making my design unwieldy or running into some other unforeseen consequence to my design decisions.

My game engine currently does basic sprite-based rendering with a panning overhead camera. My design looks a bit like this:

SceneHandler

Contains a list of classes that implement the SceneListener interface (currently only Sprites). Calls render() once per tick, and sends onCameraUpdate(); messages to SceneListeners.

InputHandler

Polls the input once per tick, and sends a simple "onKeyPressed" message to InputListeners. I have a Camera InputListener which holds a SceneHandler instance and triggers updateCamera(); events based on what the input is.

AgentHandler

Calls default actions on any Agents (AI) once per tick, and will check a stack for any new events that are registered, dispatching them to specific Agents as needed.

So I have basic sprite objects that can move around a scene and use rudimentary steering behaviors to travel. I've gotten onto collision detection, and this is where I'm not sure the direction my design is going is good. Is it a good practice to have many, small event handlers? I imagine going the way I am that I'd have to implement some kind of CollisionHandler.

Would I be better off with a more consolidated EntityHandler which handles AI, collision updates, and other entity interactions in one class? Or will I be fine just implementing many different event handling subsystems which pass messages to each other based on what kind of event it is? Should I write an EntityHandler which is simply responsible for coordinating all these sub event handlers?

I realize in some cases, such as my InputHandler and SceneHandler, those are very specific types of events. A large portion of my game code won't care about input, and a large portion won't care about updates that happen purely in the rendering of the scene. Thus I feel my isolation of those systems is justified. However, I'm asking this question specifically approaching game logic type events.

\$\endgroup\$

2 Answers 2

22
\$\begingroup\$

Event based design mostly involves implementing the Reactor design pattern.

Before starting to design components you should give a look to the limitations of such pattern (you may find a plenty information about this).

The first and foremost of the problems is that the handlers have to return quickly, as every one that did some serius work on GUI based frameworks and javascript based applications knows well.

When you develop every application with a decent complexity you will, sooner or later, face some handler that does a complex job that requires time.

In these cases you can distinguish two situations (not necessarily mutually exclusive):

Complex event-related responsibilities and complex event-unrelated responsibilities.

Complex event-related responsibilities:

In the first case you merged too many responsibilities into a single component handler: too much actions are taken in response to an event or there are running synchronizations for example.

In this case the solution is to split the handler into different handlers (in different objects if necessary) and let an handle to fire events instead of call directly the handling code. This will let you to allow an higher priority event to be managed before since your primary handler has returned after appending events to the event queue.

Another solution is to let an external entity to fire events and let the others to subscribe if interested in (the timing event is the most trivial example you can generalize).

Complex event-unrelated responsibilities:

The second case happens when there is an intrinsic complexity in the action to take after an event: you have to compute a fibonacci number after an event for example.

Here the Reactor pattern basically fails, worth little to split the fibonacci generation algorithm into little chunks that fire events upon termination in order to trigger the next step.

Here the solution is to mix a threaded design to the reactor, the good news is that if the complexity is intrinsic (so you are reading the right section) it is very likely that it is possible to start and independent thread that does the work and that needs to know little or nothing about the rest of the Reactor-related components.

To handle this kind of situations, I found useful to adopt a job queue over a flexible thread pool.

When an handler needs to start a long action, it encapsulates that action into a job unit to be put into the job queue. This encapsulated action needs to have a mean to trigger events into the reactor thread. The job queue manager may run into its own thread or in the reactor thread and react to the "newJob" event.

The job queue manager does the follow:

  • it allocates a job unit to a thread from the flexible thread pool using its shedule algorithm if the pool is able to provide one thread ( there is a free thread or a new thread creation is allowed)

  • listen the pool itself to see if a job unit finished so a thread can be recovered to execute one more pending unit, if any.

Using the event firing mechanism a job unit may trigger events to notify the completition, the update state, warnings, errors or whenever is needed. The flexible thread pool ensures a good use of resources while avoids dead thread to hang the whole system; the job queue allows you to choose which kind of priority assign to different kind of actions since you know that they will requre a consistent amount of computational resource.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ +1 for being very thorough. A few links for the curious reader would be awesome. \$\endgroup\$ Nov 28, 2011 at 15:44
1
\$\begingroup\$

In most situations using events over other options can often improve speed and decentralization. I think if you can use lots of events you should go for it.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .