Announcement

Collapse
No announcement yet.

Trouble with EventDispatchers/Delegates with Child/Parent Classes

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Trouble with EventDispatchers/Delegates with Child/Parent Classes

    I'm using 4.22

    My Goal: Have a LivingCreature super class that holds all my players and enemies. Have it contain a "CreatureHasDied" event dispatcher that announces to all other living creatures when one has died.

    How I'm trying it:

    LivingCreature has an Event Dispatcher called "CreatureHasDied"

    BaseEnemy, a child of LivingCreature, Binds to event "CreatureHasDied" with it's own custom event CreatureDied. When an enemy that is a child of BaseEnemy dies, it calls BaseEnemy::CreatureDied. I want it to be announced to all the other creatures so if they are tracking that creature for some reason, they can remove it from the lists.



    For some reason, my bind just fails. Calling LivingCreature::CreatureHasDied does not Announce to Enemies that are children of BaseEnemy, when BaseEnemy should be bound as a listener to that event.

    I'm just doing someone majorly wrong. Can someone maybe show some examples of a similar system or tell me what I might be missing?

    Thanks,

    HyenaGames - Chris Vogel

    #2
    A dispatcher is "owned" by a specific instance of a class (the "Target" input). When you call a dispatcher, it will fire events that are bound to that specific instance's dispatcher. So it looks like you have it set up so that calling LivingCreatureDied will only call CreatureDied on the instance that actually died. If you want other instances to "listen" for a dispatcher on another instance (the "subject"), you need to explicitly bind the listeners' events to the dispatcher on the subject, meaning that the "Target" input on the Bind Event node needs to receive a reference to the subject.

    In your case, it's probably not a great idea to bind events on every creature to dispatchers on every other creature, since this would eventually require a huge number of binds (e.g., 190 bindings for 20 creatures [edit] or is it 380?). A better way might be to implement a "manager" object that handles all death events. I'd probably do this with an Actor subclass that gets instantiated when a level is loaded, but there are probably cleaner ways to do it.

    The basic outline would be:
    A) Creature notifies the "DeathManager" when it has died
    B) DeathManager notifies every "interested" object when it receives a death event

    You could do this by making sure LivingCreature has a reference to your active DeathManager instance. Create an event on DeathManager called something like "IHaveDied" that takes an Actor object reference and have LivingCreature call IHaveDied when it dies, passing itself as the Actor parameter. In DeathManager, create an event dispatcher called "SomeoneDied" that also takes an Actor parameter, then have IHaveDied call SomeoneDied and plug the IHaveDied Actor parameter into the SomeoneDied Actor parameter. Finally, have LivingCreature bind to SomeoneDied on DeathManager (you'll need to work out the timing so that it happens after the DeathManager instance has been constructed) and do whatever you want in response to it.

    There are other ways to do this that could be better or worse, depending on the specifics.

    There's also a plugin that makes these kinds of "announce to everybody" events much easier to implement, but it has limitations (e.g., actor components can't "listen" for events, and passing data through events is kind of cumbersome): https://www.unrealengine.com/marketp...server-pattern

    Hope that helps...
    Last edited by DsyD; 05-07-2019, 11:50 AM.

    Comment


      #3
      Thanks DsyD! I did have a misunderstanding on how those listens worked. I was thinking it was listening to the 'class' not the instance. Your info definitely helped!

      Comment


        #4
        Np. Also, in your specific case of actors "tracking" other actors, it might be better to bind events only when tracking starts. E.g., if A is considering tracking B, first have A check to see if B is alive, then if yes, bind a "Stop Tracking" event in A to the "Death" event dispatcher in B. That would probably reduce overhead a lot if you have lots of actors (and the "default" for each actor isn't to always track every other "living" actor).

        Comment


          #5
          announces to all other living creatures when one has died.
          Interfaces are probably best practice here imo, because creatures shouldn't have to know anything about each other.
          In addition, the Blueprint wiring or connecting of all these n-n actors could be chaos, making code harder to maintain.
          In any event you should probably try and leverage 'Create Event' to get away from red event dispatcher crossed wires.
          Overall, Interfaces are more abstract and maybe trickier to learn. But long-term they're essential for UI / Interface work.
          But a lot is personal preference. I rarely use ED's anymore (mostly objects / events created dynamically at game time)....
          Last edited by EntrpriseCustomr; 05-07-2019, 03:38 PM.

          Comment


            #6
            As stated above event dispatchers are probably not what you want in this case and interfaces will do just fine. I don't think either is particularly difficult to implement. If you want to see a simple breakdown of how to create an interface or properly use an event dispatcher check out video #24 and #26 in the link below.
            https://www.youtube.com/playlist?lis...1jewB5s78zQHIy

            Comment


              #7
              Interestingly, Epic in this Livestream chose Event-Dispatchers over Interfaces for this. Curious, it'd be interesting to hear more. Interfaces being more 'loosely coupled', and arguably an easier form of communication to wire into lots of diverse classes, would seem like the natural / flexible solution here (for distributing 'player has died' notifications etc). And the least work too imo.... I wonder if a dedicated programmer had been part of the Livestream, would they have made the same call???
              Last edited by EntrpriseCustomr; 05-12-2019, 10:51 PM.

              Comment


                #8
                Probably depends on the actual application...with Dispatchers the caller (object with the dispatcher) doesn't need references to the listening objects, it just fires the event and doesn't care if anything is listening. With Interfaces the caller needs to get references to the called objects somehow...I think there are situations where one is easier to deal with than the other, and others where it's vice versa, but I find it hard to express exactly which is better in general terms...

                Comment

                Working...
                X