Page 1 of 2
Signal/Slot Library Suggestion?
Posted: Tue Jun 28, 2011 5:37 pm
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.
Re: Signal/Slot Library Suggestion?
Posted: Thu Jun 30, 2011 6:52 pm
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.
Re: Signal/Slot Library Suggestion?
Posted: Thu Jun 30, 2011 6:56 pm
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.
Re: Signal/Slot Library Suggestion?
Posted: Thu Jun 30, 2011 8:25 pm
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.
Re: Signal/Slot Library Suggestion?
Posted: Thu Jun 30, 2011 9:10 pm
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?
Re: Signal/Slot Library Suggestion?
Posted: Fri Jul 01, 2011 12:08 pm
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.
Re: Signal/Slot Library Suggestion?
Posted: Sun Jul 03, 2011 8:32 pm
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.
Re: Signal/Slot Library Suggestion?
Posted: Sun Jul 03, 2011 8:57 pm
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
?
Re: Signal/Slot Library Suggestion?
Posted: Sun Jul 03, 2011 10:33 pm
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
?
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.
Re: Signal/Slot Library Suggestion?
Posted: Sun Jul 03, 2011 11:49 pm
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
Re: Signal/Slot Library Suggestion?
Posted: Tue Jul 05, 2011 12:39 pm
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.
Re: Signal/Slot Library Suggestion?
Posted: Tue Jul 05, 2011 1:08 pm
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.
Re: Signal/Slot Library Suggestion?
Posted: Tue Jul 05, 2011 1:16 pm
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?
Re: Signal/Slot Library Suggestion?
Posted: Tue Jul 05, 2011 3:14 pm
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.
}
Re: Signal/Slot Library Suggestion?
Posted: Sat Jul 09, 2011 12:10 am
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...?