Jump to content

  • Log In with Google      Sign In   
  • Create Account

Implementing an event or message system for decoupling


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
6 replies to this topic

#1 makuto   Members   -  Reputation: 851

Like
0Likes
Like

Posted 14 July 2013 - 07:23 PM

I've recently finished implementing a component-entity system (or COM) which is working well. My goal with this new system was primarily to encourage code/component reuse and speed up development of my games.

 

The problem I'm tackling now is how to maintain the decoupling of components (both sibling components and cousin/other-object components). C++ has been my primary method of development for four years now, so when I tried the Blender Game Engine for the last two games I've made, I noticed some things I wanted to implement into my own engine. The "message" actuator was particularly appealing. The ability to send simple text messages or variables to any object (or to all objects/groups) made interaction between objects simple, yet not extremely limited. I'd like to implement something similar in my own engine, at the component->object<-component, and component->group of objects<-all components in group.

 

How should I go about doing this in the best way (judging in order of importance: versatility, simplicity of use, performance)? I've thought about using a static array and storing global flags/variables (such as position) at an object level so that all components can get or set the variables safely. This solution doesn't allow easy/readable indexing, events (only stores data), and is difficult to get right with the dynamic nature of CES/COM objects. 

 

Game Coding Complete suggested using a polymorphism-based "event manager" consisting of events (which contain any data and must inherit from a base class) and event listeners (which are called when an event is heard and must inherit from a base class; these also must cast events to their true types). I want to avoid that much complexity in order to make coding for it easier and less time-consuming, but the functionality is there. 

 

How would you recommend implementing such a system? 


Edited by makuto, 14 July 2013 - 07:37 PM.

Want to get to know my work and I better? See my website: Au 79 Games

I wrote General Tips on the Process of Solo Game Development


Sponsor:

#2 l0k0   Members   -  Reputation: 278

Like
1Likes
Like

Posted 14 July 2013 - 11:11 PM

I have a blog post about a message passing system in a component-entity world that I wrote here: http://afloatingpoint.blogspot.com/2012/09/gameplay-architecture-part-2-message.html.  I'm not sure if I would call it simple (warning: custom memory allocation), but it definitely gets the job done when it comes to sending custom messages now and queuing them for later.  The short version is that I used a sorted heap, a map of message types to listeners, and a pool allocator.


<shameless blog plug>
A Floating Point
</shameless blog plug>

#3 AllEightUp   Moderators   -  Reputation: 4211

Like
4Likes
Like

Posted 15 July 2013 - 12:15 AM

My primary suggestion is to reconsider what it is you are doing and why.  Don't take this to mean you are doing anything wrong, just that you might want to back up and examine your goals and better solutions may present themselves.  At the most simplistic level, a message is nothing but a method of deferring call to code until later in the game loop.  This is specific to an object engine and obviously doesn't apply to things like networking or out of process calls where the pointers won't be usable.  But, in general, most messages are nothing more than deferred function calls.

 

When I was looking at this type of problem for C++11 specifically, I basically wanted to be able to do one of three forms of code:

 

targetObject->Post( DoDamage( 15 ) ); // Basically a "message", just encapsulated in a functor.
targetObject->Post( [=]( Go::Object& obj ){ obj->DoDamage( 15 ); } ); // Lambda variation.
targetObject->Post( std::bind( &TheObject::DoDamage, targetObject, 15 ) ); // Functional variation.

 

Given C++11, all of those variations are equivalent as far as the post function is concerned, they are all just objects (functors) which can be called as "msg()" and will do something.  Now, some disclaimers: std::bind/function are not the fastest things in the world but if you are making so many messages you notice a slowdown you probably have other problems.  Another item, normally I'd avoid copy constructors like the plague except that with C++11 move constructors fix 90% of the performance problems so I don't care much anymore.  Take that with a grain of salt, copying data is still copying data, but the big heavy weight copy items are moved instead of reconstructed.  All said and done, what should be very minor and trivial performance hits for the new features provides for such flexibility that I believe they are well worth the added flexibility.

 

Anyway, with the basic discussion points done, I think this is closer to what you were looking for, you just have to drop the idea of "message/event" and rethink it.  The actual implementation details are a bit tricky since you have concepts such as destroyed objects and all that to deal with, though done properly at the point of deferral that won't be an issue.  Anyway, it's a fair amount of code to post as an example, but if you like the idea and need help, let me know.



#4 makuto   Members   -  Reputation: 851

Like
0Likes
Like

Posted 15 July 2013 - 08:12 AM

I0K0, thanks for the article! I probably won't do it that way because it seems a little too complex for what I'm going for.

 

AllEightUp, that makes a little sense, but I'd preferably avoid the use of functions completely. Optimally, a message would just be a type and some data, then a component can decide what it wants to do with it (or not do anything at all). This makes it extremely easy to make new components work with the messages made for existing components because the messages are decoupled from them. See what I'm going for?


Want to get to know my work and I better? See my website: Au 79 Games

I wrote General Tips on the Process of Solo Game Development


#5 recursively   Members   -  Reputation: 295

Like
1Likes
Like

Posted 15 July 2013 - 11:39 AM

For decoupling, I generally recommend the Publish-Subscribe pattern, which is particularly useful when sending messages over a network or when listening for UI events like mouse clicks, touches, etc..

 

An article showing an implementation in C++: http://rtmatheson.com/2010/03/working-on-the-subject-observer-pattern/



#6 BeerNutts   Crossbones+   -  Reputation: 2945

Like
1Likes
Like

Posted 15 July 2013 - 10:55 PM

FWIW, I wrote a event passing system where a component would post an event either to it's entity (to communicate to components within it's entity), to another entity, or to the entitymanager, which would pass the event to all entities (who have components listening for that event).  Only components who have registered for these events will get notified of the event.  It worked like the observer/subscriber model, but without the polymorphism, rather using callbacks.

 

You can read more about it in my Journal Entries.  I wasn't 100% happy with it, but it can give you an idea.

 

Good luck!


My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

#7 makuto   Members   -  Reputation: 851

Like
0Likes
Like

Posted 16 July 2013 - 08:24 AM

Thanks everyone! I think I'm going to go with the subject-observer pattern as it fits well into the structure I've already established.


Want to get to know my work and I better? See my website: Au 79 Games

I wrote General Tips on the Process of Solo Game Development





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