Jump to content

  • Log In with Google      Sign In   
  • Create Account


Global Event Manager System


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
12 replies to this topic

#1 metsfan   Members   -  Reputation: 653

Like
0Likes
Like

Posted 30 January 2013 - 10:35 PM

I know this has been discussed before, but I couldn't find a thread that really answered a few questions that have been bouncing around my head for a few days now.  I have in my game a global EventManager system.  The way this system works is that any class can override the IEventHandler interface, and register itself to listen for events in the EventManager.  Each event name is a string for now, but it will probably be a hashed string later.  Then, an event handler must override the HandleEvent method of IEventHandler, and any time an event it is registered for is triggered, this callback is hit.  

 

In theory, this seems like a sound system.  However, I have noticed a few anti-patterns I have had to use in order to achieve it.  The first is that it is a Singleton.  Now, I am well aware of the evils of Singletons, and their effect on code when overused, however I am having a tough time finding another way of doing it.  The EventManager is used in nearly every class that does anything meaningful, meaning it would need to be injected as a dependency in a ridiculous number of objects.  At this point, I'm asking myself this question:  I know Singletons are bad because it creates tight coupling between two classes and it hides the fact that this class needs the Event Manager.  But if the EventManager is used by nearly every class, then isn't it inherently tightly coupled with the entire application?

 

Another anti-pattern that I am noticing is the fact that event passing can be tough to follow and debug.  I can't just step through the stack trace to see exactly what is happening when an event is fired.  You kind of have to "know" which classes are listening to which events.  This works fine now because I'm the only one on this project, but once this project starts becoming bigger, and I bring on new devs, it's going to be a nightmare for them to follow the event handlers (and once the codebase gets large it may be tough for me, the original author, to remember all the places that I'm putting event handlers).  So my question is, is there any better way?  

 

Sorry, I know this is kind of a long post, but I hope someone out there that knows more than me can help smile.png.  Thanks.



Sponsor:

#2 Hodgman   Moderators   -  Reputation: 27892

Like
2Likes
Like

Posted 30 January 2013 - 10:40 PM

So my question is, is there any better way?

Cheeky answer: Don't use the global event manager anti-pattern tongue.png

 

Would it be possible to just link individual objects that need to communicate together directly, using delegates?



#3 metsfan   Members   -  Reputation: 653

Like
0Likes
Like

Posted 30 January 2013 - 10:47 PM

So my question is, is there any better way?

Cheeky answer: Don't use the global event manager anti-pattern tongue.png

 

Would it be possible to just link individual objects that need to communicate together directly, using delegates?

 

I thought of that, but theres two problems I'm seeing with that:

 

1) It seems to couple classes that inherently have nothing to do with eachother.  Example:  When a rock drops, I want a sound to play.  I don't want my physics engine being coupled with my audio engine.  So what's the solution?  I could have an intermediary object like "PhysicsRockDropDelegate" that calls the AudioPlayer, but that's not much better...is it?

 

2) The delegate pattern allows for only one class to be the "delegate".  So for instance, when a character moves, nearly every subsystem will need to be notified.  How to do this without broadcasting a global event, while also not tightly coupling the character movement system with nearly every other subsystem?



#4 Hodgman   Moderators   -  Reputation: 27892

Like
9Likes
Like

Posted 30 January 2013 - 10:58 PM

The point of delegates is that the physics and sound systems don't have to know about each other (when contrasting with interfaces, anyway).
The next layer up in the code base, which does know about physics and audio can then glue together those two independent modules.
 
e.g. In this C# code, when the physics body's HitTheGround method is called, the sound effect's Play method is called, even though physics and sound are completely independent of each other.
class Position { };
//physics module
class RigidBody
{
	public delegate void OnTouch(Position pos);

	public void AddOnTouch(OnTouch e)
	{
		m_onTouchEvents.Add(e);
	}

	public void HitTheGround()
	{
		foreach (var e in m_onTouchEvents)
			e(m_position);
	}

	private List<OnTouch> m_onTouchEvents = new List<OnTouch>();
	private Position m_position = new Position();
}
//audio module
class SoundEffect
{
	public void Play(Position where)
	{
		/*...*/
	}
}
//game (can glue the above together)
class RockEntity
{
	public RockEntity()
	{
		m_body.AddOnTouch(m_sound.Play);
	}
	private RigidBody m_body = new RigidBody();
	private SoundEffect m_sound = new SoundEffect();
}
Which language are you using? I can translate that into C or C++ if you like...

Edited by Hodgman, 30 January 2013 - 11:04 PM.


#5 metsfan   Members   -  Reputation: 653

Like
0Likes
Like

Posted 30 January 2013 - 11:13 PM

This is a great code sample, thank you.  I am using C++, but I don't need a translation, I am more interested in concepts here, and anyway I know C# quite well.  I didn't realize you were talking about delegates in the C# sense, I was thinking of them more in the Objective-C sense.  From the C# sense, I see what you mean: rather than registering an event with a global "Event Manager", you register the callback method directly with the object that performs the event.  I will think on this.  Thank you for your suggestions.



#6 Amr0   Members   -  Reputation: 1035

Like
2Likes
Like

Posted 31 January 2013 - 02:14 AM

I'm building an editor for an engine in C++/win32, and I'm using a simple event system, or rather a delegate system similar to C#. I'm finding it very useful in keeping things modular, and it's sufficient for the needs of a GUI application. Have a looksie: http://code-section.com/entry/2/c-a-simple-event-system


Edited by Amr0, 24 January 2014 - 08:09 AM.


#7 Servant of the Lord   Crossbones+   -  Reputation: 17272

Like
0Likes
Like

Posted 31 January 2013 - 12:24 PM

The point of delegates is that the physics and sound systems don't have to know about each other (when contrasting with interfaces, anyway).
The next layer up in the code base, which does know about physics and audio can then glue together those two independent modules.
 
e.g. In this C# code, when the physics body's HitTheGround method is called, the sound effect's Play method is called, even though physics and sound are completely independent of each other.

[...snip...]

 

1) Is that your recommended method of managing events, or are you just showing an example of delegates?
2) This pattern is also sometimes referred to as signals-and-slots, right?

3) Do you find it actually beneficial to use in games, or just desktop applications?

Event processing is one of the areas I have difficulty implementing neatly. mellow.png


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#8 L. Spiro   Crossbones+   -  Reputation: 12330

Like
7Likes
Like

Posted 31 January 2013 - 04:45 PM

I am not Hodgman, but I agree with his philosophy on events. These are my views on the subject and do not necessarily represent the views of all Australians.

1) Is that your recommended method of managing events, or are you just showing an example of delegates?

Somewhat both. Events and delegates are 2 different things and each has their place. Delegates don’t replace events, but they offer an alternative and often better way of tickling tackling some things. Also, delegates are basically event-handlers, meaning they are not mutually exclusive, but when you do it this way it is less abstract and much easier to debug.
Abstract global event systems are bad.

2) This pattern is also sometimes referred to as signals-and-slots, right?

Erm, close enough…
Events, delegates, and signals and slots are 3 different things really, but some of that is just semantics and implementation.
Signals are basically events and slots are basically delegates. The main difference is that “signals and slots” refers to the whole send/handle events system whereas delegates are just the things that handle events.

3) Do you find it actually beneficial to use in games, or just desktop applications?

It is certainly more widely useful in desktop applications which are event-driven. Nothing happens until you click a button or type into the keyboard.
Games are different. It is definitely an error to make a global event system that tries to push your game into a heavily event-driven state. Events in games are better suited for handling script-related events, such as a player walking into a certain area of the map and triggering an in-game cinematic.
There are times and places for event-based systems in games, but outside of this example there are very few.

Event processing is one of the areas I have difficulty implementing neatly. mellow.png

Likely a sign that you intuitively realize that event systems in games are not to be used the same way they are in event-based desktop applications.
Event systems are to be used sparingly in games and only after much planning and pondering.
A global event system is an anti-pattern as was already mentioned. Humans are like desktop applications and dogs are like games. Both can eat chocolate cake, but the dog will likely die from it.


L. Spiro

Edited by L. Spiro, 31 January 2013 - 04:59 PM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#9 Hodgman   Moderators   -  Reputation: 27892

Like
5Likes
Like

Posted 31 January 2013 - 05:53 PM

Is that your recommended method of managing events, or are you just showing an example of delegates?
Do you find it actually beneficial to use in games, or just desktop applications?

Well I hate global/centralized 'event managers', after having used quite a few very over-complicated ones before, and yes, I much prefer 'plugging components together' like in the example, via delegates/slots/callbacks/functors/what-have-you.
Yes this use useful for games, not just GUIs. Actually, many over-complicated 'entity/component systems' have some kind of complex event routing built into them, when the above example would solve the same problem easier.

That said, these days I do personally like to reduce abstraction in the flow of control in my code, and find that events/callbacks/virtual/etc all obfuscate the flow of control... So, i like to be more explicit about what the 'current operation' is. In the above example, I'd rather have the physics module generate an entire collection of ground-collision-points, and then fire an event, which the sound module uses to then spawn ground-collision audio effects for that entire collection.

#10 Servant of the Lord   Crossbones+   -  Reputation: 17272

Like
1Likes
Like

Posted 31 January 2013 - 05:55 PM

It is certainly more widely useful in desktop applications which are event-driven. Nothing happens until you click a button or type into the keyboard.
Games are different. It is definitely an error to make a global event system that tries to push your game into a heavily event-driven state. Events in games are better suited for handling script-related events, such as a player walking into a certain area of the map and triggering an in-game cinematic.
There are times and places for event-based systems in games, but outside of this example there are very few.

Event processing is one of the areas I have difficulty implementing neatly. mellow.png

Likely a sign that you intuitively realize that event systems in games are not to be used the same way they are in event-based desktop applications.
Event systems are to be used sparingly in games and only after much planning and pondering.

 
I definitely realize the difference - I use the Qt framework, which handles almost everything through signal-and-slots. I use the signals and slots in my non-game applications, but in my games I do two things: I have gamestates with Update(deltaTime) calls for frame-to-frame changes, and I also have events (like OpenMainMenu or CurrentAreaHasChanged) - the vent part is probably the anti-pattern you are talking about, but I can't really see better big-picture solutions despite being not very pleased with it.
 
Part of my dissatisfaction is the grammatical tense of my events: Some are commands: OpenMainMenu asks/tells the Main Menu to open, while others are messages: CurrentAreaHasChanged lets other systems know that the area has already changed. But they are using the same system, and the whole thing just feels 'off' to me. Right now it's not so bad, since the events are mostly GUI (OpenMainMenu) or input events (MoveForward), but I'm still not completely satisfied with it.
 
I suppose all my 'command' events should be direct function calls, and only the 'message' events should be events... Hmmm. But having something like "OpenMenuButtonWasPressed" as a message just for another class at a higher level to then directly call a function seems to require more boilerplate code with pretty much the same result.
My system is definitely 'abstract' in that one message is completely unrelated to another. It's 'global' in the sense that any active gamestates receive the messages ("virtual React(message)") and can send messages (thisGameState->GameStructure.SendMessage(message)) but it's not 'global' in the sense of a global variable.
 

I don't have my thoughts straight on this issue, and definitely appreciate any insight you can give. I've previously read several of the entries on your journal, including this one.


It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.

[Fly with me on Twitter] [Google+] [My broken website]

All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.                                                                                                                                                       [Need free cloud storage? I personally like DropBox]

Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal


#11 L. Spiro   Crossbones+   -  Reputation: 12330

Like
0Likes
Like

Posted 31 January 2013 - 06:34 PM

The main thing Hodgman and I dislike about major global event systems is the abstraction—they basically violate the single-responsibility principle (not to mention the debugging nightmare). It is easy to get carried away with them such that the single system ends up handling all types of events from and to anywhere and anything.

I prefer to divide the workload into related subsections and within those subsections I decide on the best system to use, such as delegates, virtuals, etc. You also mentioned something that I was going to use as a classic example of what often gets treated as event-based but should not be: input.
Actually, proper input handling could be an entire new thread/discussion, and I have been asked to post about it on my blog so I will eventually, but for now we can get straight to one of the big questions left open by an event-based input system: When do you handle those events?
As soon as you detect the button was pressed? Even in single-threaded systems, while the timing may be predictable (it will always happen just before the game cycle update (which could be both a Tick() and a Draw() or just a Draw())) it has problems with fixed-step implementations. If you tell Mario to jump but logical updates won’t happen for another 30 milliseconds, what data do you change? Logic should only happen during a logical update, so adjusting Mario’s jump status and upward velocity between logical updates as the result of an input event is out-of-place.

Then you get into multi-threaded systems where doing these kinds of updates out-of-place is not just a logical fallacy but a bug farm.

 

 

On the one hand, good advice is not to over-engineer things.  Event systems are often more than what is really necessary for a lot of things.  Divide the load into related sub-systems and think about what is really the bare minimum necessary for it to work, and keep options such as delegates and virtuals on the table.  The link you posted is somewhat of an event in concept (changing a state and passing data to the new state) but the system was engineered only for that specific task and with those specific classes.  Using an abstract and general-purpose event system would get the same results but would be a case of over-engineering.

 

On the other hand, using events to handle input is actually under-engineering.  Smooth and consistent input-handling is a non-trivial task that events alone simply can’t handle.

 

Separate things into related buckets and think about what is neither too much nor too little.

 

 

L. Spiro


It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#12 web383   Members   -  Reputation: 741

Like
0Likes
Like

Posted 03 February 2013 - 10:32 PM

Which language are you using? I can translate that into C or C++ if you like...

For those of you using C++.  How do you implement your delegates? 

 

I've found several resources on the internet:

 

This looks to be very popular.  The code looks insane.

http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates

 

This is a very novel solution using templates

http://molecularmusings.wordpress.com/2011/09/19/generic-type-safe-delegates-and-events-in-c/

 

This also looks to be a fairly simple design, using polymorphism.

http://nocturnal.insomniacgames.com/index.php/Common#Event.h (implemented here - https://github.com/HeliumProject/Foundation/blob/master/Event.h)

 

I know there is also boost::bind and boost::function.  Which delegates does everyone prefer?



#13 Hodgman   Moderators   -  Reputation: 27892

Like
0Likes
Like

Posted 03 February 2013 - 11:27 PM

I know there is also boost::bind and boost::function.  Which delegates does everyone prefer?

On an up-to-date C++ compiler, you've got std::bind and std::function, along with the C++ lambda syntax -- so those would be the default choices these days.

 

Personally, I like to just use C-style function pointers in most situations (and hand written functions to bind them to C++ objects)...






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS