Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

The Observer Design Pattern

Discussion in 'Scripting' started by MrPriest, Jan 11, 2015.

  1. MrPriest

    MrPriest

    Joined:
    Mar 17, 2014
    Posts:
    202
    Hello everyone.
    I'm thinking of implementing it (naturally...) in my code.
    I was thinking of another way to implement it, I wanted to know if it is a valid way, if anyone tried it, any cons/pros?

    The Basic Observer
    In the game code you set an observer that should get the events from that specific code/class/object.
    Once an event happens, it notifies its' observer, and the observer does its thing (be it manipulate score, achievement, etc...)
    But in this case, you have to have a different observer for each class, one for a score system, one for achievements, etc...
    I was thinking, why not have one big observer that collects all of the events?

    The Big Brother
    One observer gets all of the game's events sent to it.
    While the game runs, it checks if it has a stack of events from the last, or the same frame, etc...
    For each of them, it checks the sender, and sends the event to the observer that matters.

    Now, I can think of a few things that might pose a problem;
    1. The Big Brother might get too many events in its queue, it might cause a slowdown in event management. A score might update too late, causing the game to continue for bit more (in the good case) after it was supposed to end, the game takes a few more seconds to restart or show a menu after the player dies, etc... (Basically, a bottle neck).
    2. I still have to manage a number of different observers. Though in this case, I keep them in one area and do not have to look for them.
    3. There might be a racing condition to insert an event into the queue.

    The Final Question
    Did someone try this? Maybe it's the norm? Is there a better way (I doubt there isn't, I did not use events that much really) to implement an even system?
    I'd love to hear feedback, ideas, maybe existing topics that are related?

    Thanks for reading!
     
  2. RockoDyne

    RockoDyne

    Joined:
    Apr 10, 2014
    Posts:
    2,234
    Totally not an observer pattern. I'll try to get to the questions, but first some education. The observers in the pattern are basically people watching TV. The observers are subscribed to a channel, but the station has no idea who the observers are. The station just broadcasts a message and is blissfully unaware of whether anyone actually receiving it.
    In C#, an object just subscribes a function to an event, and the event gets called as per the routine. The broadcaster has no notion of who the subscribers are, or even that there are subscribers, it just calls the event regardless.


    As for the big brother idea, it sounds terrible if for no other reason than you are sticking a middle man in between interactions that are probably meant to be lightweight. I have no idea why you would actually want some kind of arbiter executing or executing (this time in the death panel sense) interactions that are meant to be up to the listener/subscriber (whatever you want to call it). It sounds over-designed and probably far more trouble than it's actually worth.
     
  3. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    @MrPriest : The Big Brother class you are talking about is basically using the Mediator pattern. It is used for exactly the situations you describe. As code base increases and there is more and more communication going on all of this communication code itself can muddy up the class specific code. With the Mediator you make your Big Brother object and all communication goes through this central system. It will collect all of the messages and distribute them to the appropriate places. Basically it is just applying Single Responsibility by running all communication through this Mediator.

    However, as @RockoDyne stated the Observer pattern has a different focus. With it the idea is you do not actually use any specific communication class and instead just publish your events. Any other objects can subscribe to receive those events and the object publishing the events has no idea who (or if any) are actually receiving its messages.

    You can however, combine the two and this is exactly the method I prefer. I have a NotificationsManager class. It is a singleton. Objects subscribe to various notifications through this class. They also publish to either a specific subscriber or broadcast to all subscribers. This gets me the best of both patterns while getting rid of the downside of both patterns.
     
    MrPriest likes this.
  4. MrPriest

    MrPriest

    Joined:
    Mar 17, 2014
    Posts:
    202
    I see, thank you both for your replies!

    I am just working on ideas, I'll probably try it in a simple chess game project ("Simple" meaning, I don't have to think of inventing any other aspect of the game, but will still have challenges and learning experience working on it)

    Thank you again for your look on things (and fixing my understanding of it)
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    If you want an example... I have it in my spacepuppy framework available on google-code.

    Here is the Notification class:
    https://code.google.com/p/spacepupp...e/browse/trunk/SpacepuppyBase/Notification.cs

    You inherit from this Notification class to define a 'type' of Notification a script may dispatch. This allows for type safe registering of notifications, and to define any parameters that may come with them (think like how EventArgs are in .Net's event system).

    It also has a group of static methods that take care of preparing GameObjects seamlessly for you. So when you register to listen for or post notifications, you do it through these static methods.



    This here is the code that does the actual heavy lifting though:
    https://code.google.com/p/spacepupp...unk/SpacepuppyBase/INotificationDispatcher.cs

    I used to have a design where 'Notification' was a static class (sort of singleton), and it stored all the relationships of who was listening for what. But as the number of Notifications registered for grew, it got VERY slow. You can see that old version here:
    http://jupiterlighthousestudio.com/spacepuppy_unity_framework_and_unity_notification_system/

    I wrote an article about it, and it's now outdated.

    This new version attaches a script to those GameObjects that have something registered for it, and that takes care of the work for you, and thusly is much faster. The global registrar is still in 'Notification', but that's just unavoidable.

    You'll notice that everything is actually based around the interface 'INotificationDispatcher'. And the code doing the lifting isn't a MonoBehaviour/Component itself, and instead is consumed by a component. This is because I wanted it designed so that even NONE GameObject/Components could also dispatch notifications.
     
    AdmiralThrawn and MrPriest like this.
  6. MrPriest

    MrPriest

    Joined:
    Mar 17, 2014
    Posts:
    202
    This is interesting.
    I much prefer to write things myself, however, I will go over this!
    It's a waste not to learn from anothers past experiences.

    Thank you very much!
     
    AdmiralThrawn likes this.
  7. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    I'd like to understand your motivation but I don't know what "required", "dig out a reference", "entity hierarchy", and "directly" mean. I don't know if these are terms you made up, or ones that you think are ubiquitous.
     
  8. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    'required':
    means that the object you attach the listener to (the component that dispatches an event) has to had. You need to know exactly which component is going to send it up, and what about if there are several components? Then you have to register with each component individually.

    'entity hierarchy':
    earlier in this article I mention, and link to, my entity design
    Here is the article:
    http://jupiterlighthousestudio.com/organizing-a-group-of-gameobjects-in-unity/

    'dig out a reference':
    you have to find the GameObject within the entity hierarchy, then get the components, and individually reference.

    'directly':
    My Notification system allows you to just register a notification listener with the root of the entity, and any and all notifications dispatched from within the entity will be received. With events, you can't indirectly do this, you have to directly register with each component.




    Think of it like unity messages. You don't need direct references to things. One component sends a message, and all components on the GameObject you send it to receives the message (or in a hierarchy if you use SendMessageUpwards).

    This acts like Messages, but in the reverse order, and with type safety (instead of string names).

    Here we register with a component, gameobject, or even cluster of gameobjects (entity), to listen for a specific 'notification'. Then when that object dispatches that notification, it doesn't care who is listening (observer pattern), it just gets received by all observers.
     
  9. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    It seems to me like you're reinventing the wheel. Static events and indirection through event forwarding* seem to solve the problems you're talking about, as I understand them.

    * e.g.
    Code (CSharp):
    1. abstract class ActionTaker: MonoBehaviour {public event Action takeAction;}
    2. class ChildEntity1: ActionTaker {} class ChildEntity2: ActionTaker {}
    3.  
    4. class RootEntity: MonoBehaviour {
    5.     public event Action<ActionTaker> takeAction;
    6.  
    7.     void Awake() {
    8.         foreach (var actionTaker in GetComponentsInChildren<ActionTaker>())
    9.             actionTaker.takeAction += () => takeAction(actionTaker);
    10.     }
    11. }
     
    Last edited: Jan 12, 2015
  10. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    static event would be for a more global aspect.

    This isn't for globals (though a global option is included, but it's a minor addition).
     
  11. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    I'll give you an example. All my enemies, players, and even debris and obstacles have the ability to harm. May that harm be they shot a projectile, they have a bump surface (spikes), they swung a sword, they have an AOE (fire, electric field), whatever. They all have scripts that take care of this action, BUT this script may or may not be the same class, or have a consistent interface, or even position in the entities hierarchy. The sword could be in the hand bone of a model, the bump surface a collider right on the root of the entity. We don't know.

    When this script operates that it's striking something, it needs to inform both the entire entity that this happened, and the entity that it happened. An "OnStrike" notification.

    This could be seen as similar to 'OnCollision', both the parties involved are sent this message.

    So the entity being struck has a script somewhere in its hierarchy (for organizational purposes) that needs to react to this. It needs to receive this message. Also the entity that does the striking has some sound effect that plays on it, and this is done in a different script than the script performing the strike.

    So, BOTH entities have a need to listen for this event to occur, but doesn't know exactly who in each other's hierarchy is signaling it (especially not the one being struck, since it didn't do the signaling).

    So the play sound effect script registers with its root that it wants to be told about any time it strikes something.

    And the got hit reaction script registers with its root that it wants to be told if its been struck.

    Then the striking script signals the roots of both its own entity, and the entity it struck, that this occurred. And as a result these observers perform the task desired.

    Code (csharp):
    1.  
    2. //in sword script
    3. void OnTriggerEnter(Collider other)
    4. {
    5.     //determine if collision is a legite sword strike, calculate damage, strikingEntity, strikingWeapon, and who was struck
    6.    
    7.     var n = new WeaponStruckNotification(damage, strikingEntity, strikingWeapon, struckObject);
    8.     Notification.PostNotification<WeaponStruckNotification>(this, n, true);
    9.     Notification.PostNotification<WeaponStruckNotification>(struckObject, n, true);
    10. }
    11.  
    12.  
    13. //in struckObject reaction script
    14. void Start()
    15. {
    16.     Notification.RegisterObserver<WeaponStruckNotification>(this.FindRoot(), this.OnWeaponStruck);
    17. }
    18.  
    19. void OnWeaponStruck(WeaponStruckNotification n)
    20. {
    21.     this.Health -= n.Damage;
    22.  
    23.     if(n.StrikingWeapon.HasKnockback)
    24.     {
    25.         //do knockback
    26.     }
    27. }
    28.  
    29. //in entity that did the striking
    30. void Start()
    31. {
    32.     Notification.RegisterObserver<WeaponStruckNotification>(this.FindRoot(), this.OnWeaponStruck);
    33. }
    34.  
    35. void OnWeaponStruck(WeaponStruckNotification n)
    36. {
    37.     //play sound effect
    38. }
    39.  
    I wouldn't say its reinventing the wheel. It's taking the decouple nature of 'messages', and adding the type safe nature of '.net events', and expanding on both by giving it an understanding of my 'entity hierarchy design'. It's its own deal that perform a task that I find very useful... static events can't really do that without some mediator in between handling who receives what messages...

    I also have another system in my framework (no source available for this one) that basically allows design time, no code, registering for various events that then trigger some other component I call 'triggerables' (it's oddly a lot like the 'event' system unity released in their new UI system, but before I even saw their new UI system). And these Notifications integrate easily with them as well.



    Anywho, if you don't see the benefit of it, that's fine. Either you don't need this in your designs, or maybe I'm just not describing it well enough. At the end of the day... I have use for it, someone else might (I've seen this design done before, just not as robustly... like here: http://wiki.unity3d.com/index.php?title=NotificationCenter ). Don't use it.

    I merely shared it because OP was talking about basically doing what I had already done. Figured they'd find looking at what I created useful.
     
    Last edited: Jan 12, 2015
    TuxedoDuck and AdmiralThrawn like this.
  12. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    I think you put so much work into this that your mind is closed to the idea of it already having been created, an in a more usable way. This is something that happens to humans. It's not a problem with you if you were ignorant of information; it's only a problem if you can't explain to yourself and others why you're still holding on to beliefs that you can't rationalize.

    Personally, I think your last post is a more complicated way of doing this:
    Code (CSharp):
    1. struct WeaponStruckEventArgs {}
    2.  
    3. abstract class Weapon {
    4.     public event Action<WeaponStruckEventArgs> struck;
    5.  
    6.     void OnTriggerEnter(Collider other) {
    7.         struck(new WeaponStruckEventArgs());
    8.     }
    9. }
    10. class Sword: Weapon {}
    11.  
    12. abstract class RespondsToSwordStrike {
    13.     Sword sword; // This can be from your "FindRoot()".
    14.     void Awake() {sword.struck += args => {};}
    15. }
    16. class StruckObject: RespondsToSwordStrike {}
    17. class StrikingkObject: RespondsToSwordStrike {}
    I might be totally off-base.
     
  13. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    What if there are 100 swords in the scene?

    What if some entity needs to listen for when its struck by ANY of those swords?

    What about all the other weapons that might exist? The spikes, the fire, there's LOTS of them. They're not a 'Sword', there's no 'Sword' component to 'get' and attach my listener to. I'd have to some abstraction of a weapon (an AbstractWeapon class, or IWeapon interface) that all weapons would have to implement... and STILL I'd have to search for ALL known weapons out there in existence and register with them. What I do when a new enemy spawns, now everyone needs to be informed that this new enemy spawned so it can register with that one as well. And no a 'static event' won't work here, because then we'll receive the event whenever the sword strikes ANYTHING, not just me.

    Of course, the weapon itself could instead signal to some defined class on the thing it struck. But now that requires a 'signal receiver' class type on the receiver that it searches for and signals to. This would resolve having to know all known weapons in the scene. BUT, now any time I want to receive this message I have to implement some 'IWeaponStruck' interface or something.

    OR, you could use the built in Unity 'Messages', which allows one object to send a message to another. BUT, this is not type safe and uses strings, which I don't like.

    This takes care of that. It allows sending notifications to and from objects, type safely, and with out tight coupling. Just like unity messages, but a little more robust.

    Hey, and guess what, it's already written! I don't have to do any work to use it... cause it's done.




    Don't get me wrong, I still use events. Where events are useful!
     
    Last edited: Jan 12, 2015
  14. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Its worth noting that the event system introduced in 4.6 does a lot of this for you out of the box. And it uses real C#, instead of strings to do this.

    Its pretty much what @lordofduct wrote, but with the architecture build in for you.
     
  15. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    @lordofduct, I can't help us without example code to assess.
    You will never not have to do work. You will enable yourself to go into deeper flow states, wherein you use your code with decreasing conscious effort, with practice, but it will never be done with zero cost from your cognitive resources and time banks. Each person who uses what you've created will need to go through this. The less code there is, the more flow is possible.

    @BoredMormon, what system are you referring to? I tried the Inspector-based hookups, but they're set up the same as the SendMessage @lordofduct is talking about, which is to say, you take action on other objects, as opposed to making yourself do something in reaction to a UI event. That's no way to manage complexity. Things will happen, and you'll have no idea why. It would be a useful system if it were implemented so that your Game Object's methods could be assigned to be triggered by an event elsewhere.
     
    Last edited: Jan 13, 2015
    AdmiralThrawn likes this.
  16. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    The EventSystem is far more usable then you are giving credit for. Yes, EventSystem is a replacement for SendMessage. But it does a lot more. You can also dynamically subscribe to listeners, the same as with regular .NET events. As another bonus it uses actual interfaces to make the call, instead of strings. The documentation on the EventSystem is not great as yet, but check out the ExecuteEvents class and the various interfaces provided for the UI. You can (should) also write your own interfaces.

    If you needed it you could add a layer of abstraction in the middle to provide for a full blown mediator system.
     
  17. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    Jessy, I don't think you're understanding what we're describing.

    You mostly seem like a competent developer from what I've seen from you around here, you probably have your way of solving problems. I have my ways. You're attempting to explain why I shouldn't do it my way... but you aren't understanding why I do it my way... so, your argument just isn't getting through to me.

    And yes, BoredMormon is right, it's a LOT like the EventSystem released in 4.6. My partner and I were floored when it came out and he was like, "dude... you use this thing just like we use our existing trigger/notification system." Only difference is it has 1 or 2 things it does that I don't, and I have 1 or 2 things I can do that it doesn't.

    I'm not going to spend any more energy attempting to explain it further.
     
  18. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I personally think the EventSystem was a far more significant change then the UI tools in 4.6. It didn't get anywhere near as much love as it deserves. Even the docs treat it as "This thing we had to do to make the UI work, don't worry about it". If you can take the time to work through the docs and figure out how it works it is a very powerful system.
     
    lordofduct likes this.
  19. MrPriest

    MrPriest

    Joined:
    Mar 17, 2014
    Posts:
    202
    True, I did not notice the event upgrade.
    GUI is just more attractive for non-coders, and me being somewhat new to Unity, did not go over the entire change log.
    Thanks for alerting me to this, though.
    I'm not originally a C#, embedded or game programmer so while I program for a while now in the industry, I did not have the need to learn (other than definition) about those patterns, sadly. I truly am thankful for such communities.
     
  20. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    Why would anyone do that if, like lordofduct's system, it doesn't solve problems that aren't already solved? It either won't happen without potential ambassadors like yourself explaining why it does something new and useful, or it won't happen at all. I'm not a believer, but I'm open to convincing.

    A TL;DR blog post isn't the way to go about this kind of thing. Display an impressive, flashy chunk of functionality, and explain its inner workings later. Hooking up events in the Inspector is like that, except for the part about it not actually solving any problems due to the hookups being backwards.
     
    Last edited: Jan 13, 2015
  21. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Which they can, through the AddListener method. Or via assignment in the inspector.

    I'm still struggling to see how the EventSystem is hooking things up backwards. In the classic version of the observer pattern the event owner is responsible to own the list of objects that the event needs to be sent too. Responding to an event without the event owner taking some action is a matter of polling for the event every frame. This is expensive on a large scale, and is why .NET events were introduced in the first place.

    If you want the mediator pattern, where events go into a large pool and are then distributed out, then its simply a matter of hooking up two EventSystems back to back, with some useful mediation code in the middle.

    On the other hand if you can't see the benefits of the EventSystem for your project then you are welcome to ignore it completely.
     
  22. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    Neither do I see how the hookups are backwards.

    I already demonstrated a piece of code that does what I'm talking about. Jessy attempted to describe a "better" way to do it... but his way of doing it actually didn't work if there are more than one weapon/sword in the scene, since you'd have to register with EVERY weapon/sword.

    My example showed that you didn't have to register with every weapon/sword. I didn't even need to know IF there was a sword! I could remove the sword, and put an axe script in place, and the observers wouldn't need to know. They just listen to the entity root for if A weapon struck anything, or was struck by something.


    As for the part that makes it similar to the EventSystem, that's the other half of it, my 'trigger' system. And I didn't even show you that, because I'm not sharing it at this time in its code form. I can show an image of it in the browser.
     
    Last edited: Jan 13, 2015
  23. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377


    So, this is the inspector of a 'Trigger' that is integrated with the 'NotificationSystem'.

    You'll see when the trigger has a target, there is the 'Advanced Target Settings'. Here is where you can configure how we treat the target. By default it always just calls all the 'ITriggerableMechanisms' on the target (any script that implements that interface).

    There are 4 modes of operation though.

    Trigger All On Target - default setting, triggers all ITriggerableMechanisms

    Trigger Selected Target - select a specific ITriggerableMechanism script that is part of the target GameObject to select, include a possible argument. In the image where its selected it's 'undefined' meaning no arg will be sent. But if you click the || button next to it, you'll get the option to set a value.

    Send Message - calls SendMessage on the target GameObject using the built in Unity SendMessage system. I never use this, but I added it just in case. You will notice that I included an argument this time, messages allow one argument. I decided to use a float.

    Call Method On Selected Target - this is my preferred method, rather than the 'SendMessage'. The editor reflects out all known methods on the target and lists them in a drop down. I chose 'Trigger' in this case. If the method has arguments that are needed to call it, it the editor will display them (hence no || next to the arg). If the type of the argument is something like 'object', you get to select the type of arg to send... if the type is something that can't be inherited from (like any of the struct types), it will not let you select a type for it, and force you to use the required type.

    These 'args' are using my VariantReference script:
    https://code.google.com/p/spacepupp...owse/trunk/SpacepuppyBase/VariantReference.cs
    https://code.google.com/p/spacepupp.../Inspectors/VariantReferencePropertyDrawer.cs
    This is what allows you to select the type of that argument. Here's the drop down:




    You may notice that I include the tooltip over the 'Observed Hit Target' property. This is unique to the 'T_OnWeaponStruck' trigger... it allows you to listen to if a specific part of the entity was struck (say the head, arm, whatever), rather then listening to the entire entity that the component is attached to.




    Note I also have a generic trigger that allows hooking into any notification known in the system. A dropdown box lists all notification types found.



    See some notifications have special info that needs more options than just 'what notification to listen to', such as the 'T_OnWeaponStruck' which had that extra optional 'ObservedHitTarget' property.

    But if you just want to listen for any generic old notification, this component is all you need.




    Now, I might write multiple scripts that dispatch a 'OnStruck' notification.

    A designer, who doesn't like to do a lot of code, knows that all the weapons do this. So when they're building up a mob of some sort, they'll drop in the model, attach a movement motor, attach a health script, attach a combat motor, and a weapon, and what not.

    Now, they want to do some unique things. This entity, when struck, cries out a specific cry, and plays some particle effect.

    Here's that 'Hit_React' target that was being targeted in the first image above.



    These are unique to this 'croc' enemy type. And the designer doesn't have to write any code. They just wire this all up, and they're done.

    NOTE, this is not listening for the weapon it owns to strike anything. It's listening for if IT is struck by a weapon. This weapon could be any of the players on screen (multiplayer?) or even other enemies. We have large enemies who will kill, pick up, and throw smaller enemies at the players. I can listen for ALL of those strikes with out needing to know who they are prior to being struck.




    So just like I don't need to care about what 'T_' or other scripts may listen for these Notifications when I write my code, all I have to do is dispatch a notification to/from (yes poly-directional here, because you keep bringing up something being 'backwards').

    Also, I don't have to care about who triggered these ITriggerableMechanisms. If my designer/artist says he needs a script that turns an entity into a ragdoll and then explodes that ragdoll... I just write that into a script. Because it's an ITriggerableMechanims, an 'I_ExplodeRagdollsToBits'... all the designer/artist has to do is going and pick a 'T_' for the event/notification he wants to explode on, and point it at the mechanism.
     
    Last edited: Jan 13, 2015
    TuxedoDuck likes this.
  24. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    I think you're talking about seeing, for example, what a button triggers. I want to hook up my methods to a button, not hook a button up to someone else's methods. If what I wanted was so strange, it wouldn't be the basis of modern programming.
    The event owner must own the list, but the user must not know anything about that list, if it is functioning correctly. The add/remove accessors of a C# event can be useful. The list itself, much less so, hence the lack of Microsoft bothering to make it user-friendly.
     
    Last edited: Jan 13, 2015
  25. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    Wait, you say its backwards because there's an 'AddListener' and 'RemoveListener' function?

    They're the SAME thing as += and -=. With .Net events its just some syntax sugar covering up the underlying 'add' and 'remove' functions.

    Microsoft used the += and -= syntax because they were building their events off the existing 'delegates' which also used += and -=. Which again, really are just function calls. Same dang functions.
     
  26. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    No, I don't see why you'd think that.
     
  27. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    You're telling BoredMormon that EventSystem is backwards, because .Net events do it differently, and that is... they have 'add/remove' accessors.

    BUT, EventSystem HAS add and remove functions!

    My notification system HAS add and remove functions!

    The list remains encapsulated.
     
  28. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    Dude srsly, I'm ubsubscribing from this thread.

    Remember earlier when you were patronizing me by saying:

    You know, I smiled and didn't rip you a new for that pile of condescending nonsense.

    But I'm done now... I think you need to take your own advice from that quote. And maybe you are closed to the idea of this being useful to anyone, because you can't see the usefulness yourself. This is something that happens to humans. It's not a problem with you if you are ignorant of information; it's only a problem if you can't explain to yourself and other why you're still holding onto the beliefs that you can't rationalize.

    Unsubscribed from thread.
     
    TuxedoDuck likes this.
  29. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    You need to listen to every entity root that interests you. If you want to subscribe at the root, and not to individual weapons, that's fine. Forward the events.
    Code (CSharp):
    1. class WeaponStrike: MonoBehaviour {
    2.     public static event Action<WeaponStrike> addedToScene;
    3.     public event Action<WeaponStruckEventArgs> struck; // sent for all the weapons.
    4.  
    5.     Weapon[] weapons;
    6. }
    7.  
    8. abstract class RespondsToWeaponStrike {
    9.     void Awake() {
    10.         WeaponStrike.addedToScene += strike => strike.struck += args => {};
    11.     }
    12. }
    Edit: I just saw the unsubscribe notification. Oh well. Hopefully this is still helpful to someone. It's not that @lordofduct created something bad. He just created a more verbose, self-maintained version of something that's built into the language already.
     
    Last edited: Jan 13, 2015
  30. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,377
    You didn't read what I said, if you think that you need to register with every entity, you missed what I said.

    I said it repeatedly through out the thread. The weapon can post a notification to the entity it struck, so that the entity it struck receives the notification from ANY weapon. So thusly that entity only has to listen to itself.

    Sort of like the 'OnCollisionEnter' message which dispatches on BOTH the hitter and the hittie.

    As I said before, the dispatching can be poly-directional.

    Giving me both the capabilities of events, AND of SendMessage, but in a type safe manner that understands my entity model.

    .Net events DO NOT DO THIS

    If you can't understand that, not my problem, enjoy your day.
     
    TuxedoDuck and Silly_Rollo like this.