Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I stumbled upon SJ Brown's tutorial on making games in the past. It's a great page, one of the best I've read. However, like you, I didn't like the calls to isinstance, or the fact that all the listeners receive all the events.</p> <p>First, isinstance is slower than checking that two strings are equals, so I ended up storing a name on my events and test for the name rather than the class. But still, the notify function with its battery of <em>if</em> was itching me because it felt like a waste of time. We can do two optimizations here:</p> <ol> <li>Most listeners are interested in only a few types of events. For performance reasons, when QuitEvent is posted, only the listeners interested in it should be notified. The event manager keeps track of which listener wants to listen to which event.</li> <li>Then, to avoid going through a tons of <em>if</em> statements in a single <em>notify</em> method, we will have one method per type of event.</li> </ol> <p>Example:</p> <pre><code>class GameLoopController(...): ... def onQuitEvent(self, event): # Directly called by the event manager when a QuitEvent is posted. # I call this an event handler. self._running = False </code></pre> <p>Because I want the developer to type as little as possible, I made the following thing:</p> <p>When a listener is registered to an event manager, the event manager scans all the methods of the listener. When one method starts with 'on' (or any prefix you like), then it looks at the rest ("QuitEvent") and binds this name to this method. Later, when the event manager pumps its event list, it looks at the event class name: "QuitEvent". It knows that name, and therefore can directly call all the corresponding event handlers directly. The developer has nothing to do but adding onWhateverEvent methods to have them working.</p> <p>It has some drawbacks:</p> <ol> <li>If I make a typo in the name of the handler ("onRunPhysicsEvent" instead of "onPhysicsRanEvent" for example") then my handler will never be called and I'll wonder why. But I know the trick so I don't wonder why very long.</li> <li>I cannot add an event handler after the listener has been registered. I must un-register and re-register. Indeed, the events handlers are scanned only during the registration. Then again, I never had to do that anyway so I don't miss it.</li> </ol> <p>Despite these drawbacks I like it much more than having the constructor of the listener explicitly explain the event manager that it wants to stay tuned of this, this, this and this event. And it's the same execution speed anyway.</p> <p>Second point:</p> <p>When designing our event manager, we want to be careful. Very often, a listener will respond to an event by creating-registering or unregistering-destroying listeners. This happens all the time. If we don't think about it then our game may break with <em>RuntimeError: dictionary changed size during iteration</em>. The code that you propose iterates over a copy of the dictionary so you're protected against explosions; but it has consequences to be aware of: - Listeners registered because of an event will not receive that event. - Listeners unregistered because of an event will still receive that event. I never found it to be a problem though.</p> <p>I implemented that myself for the game I am developing. I can link you to two articles and a half I wrote on the subject:</p> <ul> <li><a href="http://niriel.wordpress.com/2011/08/06/who-controls-the-controllers/" rel="nofollow">http://niriel.wordpress.com/2011/08/06/who-controls-the-controllers/</a></li> <li><a href="http://niriel.wordpress.com/2011/08/08/the-event-management-is-in-place/" rel="nofollow">http://niriel.wordpress.com/2011/08/08/the-event-management-is-in-place/</a></li> <li><a href="http://niriel.wordpress.com/2011/08/11/the-first-screenshot-of-infiniworld/" rel="nofollow">http://niriel.wordpress.com/2011/08/11/the-first-screenshot-of-infiniworld/</a></li> </ul> <p>The links to my github account will bring you directly to the source code of the relevant parts. If you cannot wait, here's the thing: <a href="https://github.com/Niriel/Infiniworld/blob/v0.0.2/src/evtman.py" rel="nofollow">https://github.com/Niriel/Infiniworld/blob/v0.0.2/src/evtman.py</a> . In there you'll see that the code for my event class is a bit big, but that every inherited event is declared in 2 lines: the base Event class is making your life easy.</p> <p>So, this all works using python's introspection mechanism, and using the fact that methods are objects like any other that can be put in dictionaries. I think it's quite pythony :).</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload