Signal/Slot Library Suggestion?

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Signal/Slot Library Suggestion?

Post by XianForce »

Well, I'm at a point in my component entity system, where I want to code in some sort of event, or trigger, system. After using some of Google's magic, it seems a signal/slots implementation would fit my needs best. The two I've heard of most are boost.signals and sigc++, where most people prefer sigc++'s speed over boost.signals. Yet, whenever I google signal/slots, one of the first results is the sigslot library, but I haven't found much any information on it, aside from what's available on the project page... So can anyone recommend one to use?

For now, I don't anticipate too many signals being sent. What I had in mind was a signal for entity movement, and a signal if entities collide. This way, when an entity moves, I can check that entity against every other entity, so that I don't check static entities together. Then when they collide, another signal is sent, which would allow me to handle the collision accordingly, so I can (for example) destroy an enemy when a bullet hits it. But, that being said, I will end up creating more signals later on.

I'd rather not roll my own system, considering I only have a basic understanding of signal/slot, and there already seems to be a few alternatives.

Thanks in advance for your time :)... If anything seems confusing, or if you need more information, just let me know.
User avatar
bnpph
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
Posts: 75
Joined: Thu Mar 10, 2011 12:30 pm

Re: Signal/Slot Library Suggestion?

Post by bnpph »

Are you sure signals/slots are what you need?

I have never used them, but I always thought they were designed for GUI things.
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: Signal/Slot Library Suggestion?

Post by XianForce »

bnpph wrote:Are you sure signals/slots are what you need?

I have never used them, but I always thought they were designed for GUI things.
Yeah. It's a design where a signal has any number of slots connected to it. The slots are essentially function pointers. So when you call the signal, those slots get called. Very clean for GUI things, but I think it's also perfect for what I want to accomplish. I need a messaging system of sorts, but this method seems like a more direct implementation.
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Signal/Slot Library Suggestion?

Post by Falco Girgis »

XianForce wrote:
bnpph wrote:Are you sure signals/slots are what you need?

I have never used them, but I always thought they were designed for GUI things.
Yeah. It's a design where a signal has any number of slots connected to it. The slots are essentially function pointers. So when you call the signal, those slots get called. Very clean for GUI things, but I think it's also perfect for what I want to accomplish. I need a messaging system of sorts, but this method seems like a more direct implementation.
So if you know that they're essentially function pointers (that can be easily implemented), why are you so hasty to add another gigantic, pointless dependency to your project (like the Boost library), when you can quite easily roll your own?

I was hesitant to respond, because I firmly believe that "messaging systems" are overkill for game development.
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

Re: Signal/Slot Library Suggestion?

Post by avansc »

GyroVorbis wrote:
XianForce wrote:
bnpph wrote:Are you sure signals/slots are what you need?

I have never used them, but I always thought they were designed for GUI things.
Yeah. It's a design where a signal has any number of slots connected to it. The slots are essentially function pointers. So when you call the signal, those slots get called. Very clean for GUI things, but I think it's also perfect for what I want to accomplish. I need a messaging system of sorts, but this method seems like a more direct implementation.
So if you know that they're essentially function pointers (that can be easily implemented), why are you so hasty to add another gigantic, pointless dependency to your project (like the Boost library), when you can quite easily roll your own?

I was hesitant to respond, because I firmly believe that "messaging systems" are overkill for game development.
Actually, a lot of boost is part of the next/new C++ standard. Just throwing that out there for the pointless comment, altho I know you were not trying to say boost is pointless.

anyways, could you show an alternative to a messaging system to make complex event triggers trivial like they are with a robust message system?
Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: Signal/Slot Library Suggestion?

Post by XianForce »

avansc wrote: anyways, could you show an alternative to a messaging system to make complex event triggers trivial like they are with a robust message system?

Yeah... I'd like to see that too. I've been turning this over in my mind for quite some time and I really just couldn't think (or even find over the vast expanse of the internet) a different method of implementation :/.

EDIT: Also, the reason I even posted this thread in the first place was so I could stray away from larger dependencies like Boost, and find a (recommended) simple/fast signal/slot implementation.
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

Re: Signal/Slot Library Suggestion?

Post by avansc »

XianForce wrote:
avansc wrote: anyways, could you show an alternative to a messaging system to make complex event triggers trivial like they are with a robust message system?

Yeah... I'd like to see that too. I've been turning this over in my mind for quite some time and I really just couldn't think (or even find over the vast expanse of the internet) a different method of implementation :/.

EDIT: Also, the reason I even posted this thread in the first place was so I could stray away from larger dependencies like Boost, and find a (recommended) simple/fast signal/slot implementation.
In my opinion a message system is a very nice tool to have at your disposal, I am not saying its necessary, and would love to hear about any clevar tricks to achieve some of the same functionality without one.

I have some code you might wanna look at for ideas, its not the best code out there, but should be a decent base to start of off.

here is the code for the event system (event same as message in this instance)
https://github.com/avansc/qLib/tree/master/qEvent

here is an example of how you would use it.
https://github.com/avansc/qLib/blob/mas ... native.cpp


If you have any questions let me know, would be happy to bounce ideas around.
Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: Signal/Slot Library Suggestion?

Post by XianForce »

Thank you :). I've been walking around through some of it, the only thing I don't understand is, why have a listener and handler? To me it seems like an unnecessary step, considering (from what I see at least), the only purpose of the listener, is to call the handler :o?
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

Re: Signal/Slot Library Suggestion?

Post by avansc »

XianForce wrote:Thank you :). I've been walking around through some of it, the only thing I don't understand is, why have a listener and handler? To me it seems like an unnecessary step, considering (from what I see at least), the only purpose of the listener, is to call the handler :o?
Well I certainly wont claim to have the best design to a message system, but here is my reasoning to have a abstract listener to a handler as well.

Lets say we want to make something like a landmine, so basically we want to have some object that listens for some event. But generally a generic listener is only called by a defined event, lets say a key press, or an explicit key stroke or whatever.

So what I would do I create a listener called something like cMonitorListener, and what It would do is call a piece of code that does whatever we want each loop/ or perhaps each time a assigned sub space is changed. so in our landmine application I would just have a piece of code that would look if any entities have walked on it. then that would call the event handler that does the "boom" could be a piece of code, a script, whatever.

all while keeping your process messages loop/construct the same.

Also, having an abstract listener also makes it really easy to isolate messages, you literally don't have to do any special handling if your message dispatch loop is robust enough.

So lets assume I have 10000 listeners, but only 5 of those are really listening for key strokes, Now I don't have to loop though 10k listeners to not sent messages to 19995 of them.
Rest assured you can still to this with only having one kind of listener, but I feel that extending a base listener makes it a bit more clearer.

one caveat of the way I did things, is that anything that needs to have an event listener and handler added to it, needs to be a component. but that is nice about that is that it really easy to add, remove and change event listeners at run time with no real issue.
Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: Signal/Slot Library Suggestion?

Post by XianForce »

Oh, I see. After looking at your code, my idea seems much less... elegant? Haha. Anyways, I was just going to have a map of message types and signals, with the message types being integers. But I was going to implement hash strings, to provide a way to add scripted events. Any hard coded messages would be linked up with respective systems (who would then dispatch to the appropriate component(s)). Then I had a sort of dynamic trigger system planned, where after creating a new message type, you could "link" it to a certain component. When that message came around, it'd be given to the component's OnMessage function, and it'd handle it accordingly.

But, I'm sure I could do something similar to what you've done, and take away the use of signal/slot. I would elaborate on how, but I have a headache, and can't really think well at the moment :o
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Signal/Slot Library Suggestion?

Post by Falco Girgis »

In my opinion, you need to draw a very important distinction here, before you go off and create an engine of a million completely independent objects with a million listeners and a bunch of unnecessary overhead. Avansc's advice is spot-on, but I believe that something like that should only be used for EXTENDABLE components, not components that are core to an engine.

As a game developer (or any kind of real-time developer), when I hear the word "listener" or "message," I cringe. You know why? Because there is only one way to implement these. As a continuous poll in your update loop. It's essentially the least efficient method of inter-object communication possible.

Why do entities have to "emit signals/messages" when they collide or move for collision to be handled? Why does an input structure have to "emit" signals when a button is pressed? These events are the core functionality of any engine. Why bother creating a gigantic layer of abstraction that is going to do nothing but slow things down and convolute your design?

For example, I push the up button. This is supposed to move my character around the screen. I have two options. I can perform a single if(input.keyDown(KEY_UP)) check in an appropriate subsystem (partySystem, movementSystem, whateverTheHell), OR I can emit a message through a generic message system where every "listener" connected has to check if this is the kind of message they're looking for. That's potentially HUNDREDS of if statements versus a single one. The cost? A direct dependency on two classes that are quite obviously dependent. The moral of the story, don't be so eager to make every class a standalone console application with a completely generic interface. That is taking object-oriented programming to the other extreme and complicating your task rather than making it easier.

There is NOTHING wrong with two dependent objects having pointers to each other.

Now for the second part of your question. Hard-coded object-object interactions are preferred for core engine components. Now what about extendable components? That's where avanc's post comes in. We handle it similarly. For example, in ES, you can attach Lua components called "behaviors" that extend the core functionality of an engine.

Avansc gave the example of a landmine. That's a really good example, because it requires custom logic for a post-collision explosion. The hard-coded engine-provided collision component is handling the actual collision check behind the scenes, then we create a custom "Behavior" object to perform special-purpose code once that collision has been detected.

The method that we have chosen to use is "trigger-based." It's essentially a listener, but it is ONLY for extendable components (behaviors), not for core components. We have a predefined set of events like OnCollide(), OnTalk(), OnEnterBattle(), OnExitBattle(), OnLoad(), OnQuit(), etc, etc. that Behaviors can listen to. You can listen for one trigger, no trigger, or every trigger. It doesn't matter.

But we aren't doing any signal/slots bullshit to implement this. It's nothing more than a simple abstract class with purely virtual methods declared for these triggers. Each different "Behavior" component inherits from this abstract base and implements any special logic in its trigger function (then registers itself to listen in its constructor). Then every frame, the BehaviorSystem iterates through each trigger (QT SIGNAL) and invokes the corresponding trigger method (QT SLOT) for any Behavior registered to listen.

By drawing this distinction you are keeping your engine simple, efficient, and extendable. There are times when too much abstraction or object-orientation just convolutes a design and impacts performance negatively, especially in real-time applications like video games.
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: Signal/Slot Library Suggestion?

Post by XianForce »

Yes, that's exactly what I wanted to use it for haha. When I was referring to "handling collision", I suppose I wasn't clear. I already have a Physics subsystem that checks for the collision, and fixes the overlap, but for the custom logic that should occur as a result of the collision, I need some sort of trigger system... I was just going to use signals/slots in my approach... But after the discussion here, probably not haha.
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: Signal/Slot Library Suggestion?

Post by Falco Girgis »

XianForce wrote:Yes, that's exactly what I wanted to use it for haha. When I was referring to "handling collision", I suppose I wasn't clear. I already have a Physics subsystem that checks for the collision, and fixes the overlap, but for the custom logic that should occur as a result of the collision, I need some sort of trigger system... I was just going to use signals/slots in my approach... But after the discussion here, probably not haha.
Then ignore the first half of my post and pay attention to the second and avansc's post.

You can achieve the exact same thing with a simple abstract base class. And especially considering these are only for "extendable" special-purpose components, do you see now what a terrible idea adding an additional library to handle this was?
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

Re: Signal/Slot Library Suggestion?

Post by avansc »

GyroVorbis wrote: For example, I push the up button. This is supposed to move my character around the screen. I have two options. I can perform a single if(input.keyDown(KEY_UP)) check in an appropriate subsystem (partySystem, movementSystem, whateverTheHell), OR I can emit a message through a generic message system where every "listener" connected has to check if this is the kind of message they're looking for. That's potentially HUNDREDS of if statements versus a single one. The cost? A direct dependency on two classes that are quite obviously dependent. The moral of the story, don't be so eager to make every class a standalone console application with a completely generic interface. That is taking object-oriented programming to the other extreme and complicating your task rather than making it easier..
I agree that if you are gonna have some event trigger that is at the core you can make it a simple hard coded function pointer or what not.

also, I wanted to add that there is no need to explicitly check for message/listeners type compatibility. you can only reference the needed listeners for a specific listener.

something like this.
btw, i use message and events as an interchangeable term in this case.

Code: Select all

multimap<unsigned int, listener*> listeners;

listeners.insert(pair<unsigned int, listener*>("trigger id", p_Listener));
//and so on for each event listener...

//event queue
list<event> eventQueue; // events get pushed on here, then we dispatch what ever is on the queue each loop.

void dispatchEvents()
{
	list<event>::iterator e_itr; // iterator for events in the queue
	for(e_itr = eventQueue.begin();e_itr != eventQueue.end();e_itr++)
	{
		pair<multimap<unsigned int, listener*>::iterator, multimap<unsigned int, listener*>::iterator> listenerRange;
		listenerRange = listeners.equal_range((*e_itr)->GetID()); // event has the special ID so we can look up all the relevant listeners.
		
		multimap<unsigned int>::iterator l_itr; // iterator for only the listeners that are associated with our current event.
		for(l_itr = listenerRange.first;l_itr != listenerRange.second;++l_itr)
		{
			(*l_itr).ON_EVENT(*e_itr); // signal the listener that a event has happend and pass the event along.
		}
	}
	
	eventQueue.clear(); // flush the event buffer.
}
Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: Signal/Slot Library Suggestion?

Post by XianForce »

I just read through your post a second time, and here's where I get a little confused when you explain how you do it.
GyroVorbis wrote: Then every frame, the BehaviorSystem iterates through each trigger (QT SIGNAL) and invokes the corresponding trigger method (QT SLOT) for any Behavior registered to listen.
QT SIGNAL and QT SLOT... That's just a signal/slot implementation, isn't it...?
Last edited by XianForce on Sat Jul 09, 2011 8:12 am, edited 1 time in total.
Post Reply