1

i'm currently working on a small game-engine and i'm kinda stuck on finding the right pattern. First here are some code snippets to understand what i'm trying to achieve :

  • The Unit : the ability-caster/target ( throw the ability or receive it)

    public class Unit
    {
    
     public string Name { get; set; } // Unit name
    
     public List<BaseAbility> MyAbilities{get; set;} // abilities that an unit has.
    
    }
    
  • The Ability :

    public abstract class BaseAbility
    {
        public string Name {get; set;} // ability name
    
        public Unit Caster { get; set; } // ability caster (owner)
    
        public List<BaseEffect> EffectList {get; set;} // effects that an ability possess
    
        // apply all effects that this ability has on the selected target
        public virtual void DoAbility(Unit target) 
        {
            foreach (BaseEffect eff in this.EffectList)
            {                
                eff.CalculateEffect(target);
            }
        }
    
        // here we gonna subscribe to some events 
        public abstract void initListeners();
    
    }
    
  • The Effect :

     public abstract class BaseEffect
     {
       public BaseAbility Owner { get; set; } // each effect belong to an ability
    
       protected string Name { get; set; } // effect name
    
       public EventDispatcher Event { get; set; } // the event to dispatched when this effect is called or used
    
       //apply effect on target
       public virtual void CalculateEffect(Unit target) 
       {
         // Do Stuffs here like damage and poison etc etc
         this.Event.DispatchMyEvent();
       }
    }
    
  • the Event Dispatcher :

    public class EventDispatcher
    {
      private object mySender;
      private EffectEventArgs myArgument;
    
      public delegate void EventHandler(object sender, EffectEventArgs argument);
      public event EventHandler OnMyEvent;
    
      public EventDispatcher(object sender, EffectEventArgs argument)
      {
        this.mySender = sender;
        this.myArgument = argument;
      }
    
      public void DispatchMyEvent() 
      {
        if (OnMyEvent != null)
        {
            OnMyEvent(this.mySender, this.myArgument);
            Debug.WriteLine("event has been raised");
        }
      }
    }
    
  • The Effect Event Arguments :

     public class EffectEventArgs : EventArgs
     {
       private Unit target; // target affected by effect
    
       // not sure if we even need this EffectEventArgs ?!
       public EffectEventArgs(Unit unit) 
       {
        this.target = unit;
       }
     }
    

Now i'm gonna create 2 effects and 2 abilities and 2 units for the simulation :

  • Fire Effect :

      public class FireEffect : BaseEffect
      {
        public FireEffect(BaseAbility effectOwner)
        {
         this.Owner = effectOwner;
         this.Name = "Fire";
        }
    
        public override void CalculateEffect(Unit target)
        {
          // set the event here (to get the target as argument for the event)
          this.Event = new EventDispatcher(this.Owner, new EffectEventArgs(target));
          base.CalculateEffect(target);
        } 
      }
    
  • Wind Effect : same as fire effect but with a different name and event and apply also a different Effect.

  • Fire Ball ability :

     public class FireBall : BaseAbility
     {
       public FireBall(Unit caster)
       {
        this.Name = "FireBall";
        this.Caster = caster;
        this.EffectList = new List<BaseEffect>();
        this.EffectList.Add(new FireEffect(this)); // fire ball ability has "FireEffect" as effect
       }
    
       public override void DoEffect(Unit target)
       {
        base.DoEffect(target);
       }
     }
    
  • Two Units , let´s say : "Dragon" as Unit => has FireBall (ability) and gonna hit => "shaolin master of the wind " as Unit has a passiveAbility called "WindFury"

  • WindFury :

      public class PassiveAbility : BaseAbility
      {
        public PassiveAbility(Unit caster)  
        {
         this.Name = "WindFury";
         this.Caster = caster;
         this.EffectList = new List<BaseEffect>();
         this.EffectList.Add(new WindEffect(this));
         this.initListeners(); // subscribe to events (aka add listeners)
        }
    
        public override void DoEffect(Unit target)
        {
          base.DoEffect(target);
        }
    
        // THE MAIN PROBLEM : 
        public override void initListeners() 
        {
    
         // here i need to subscribe to an event fired from any Instance/Object of type FireEffect so that the targeted Unit 
         // can react to the Unit caster (kind of counter attack)
         // to resume this , it should follows this logic :
         // if any Ability has The effect(FireEffect => FireBall for example) was casted 
         // on this Unit thats possess this passive, react to it and counter with (WindEffect)
         // otherwise put : when our dragon or Ryu or even Sasuke throw an ability with
         // a FireEffect on our friend "Shaolin" ,he should react to it
         // and send the attacker flying with a powerfull WindEffect 
        }
    
        public void CallBack(object sender, EffectEventArgs e) 
        {
         BaseAbility ab = (BaseAbility)sender;
         this.DoEffect(ab.UnitCaster); // hit the unit caster back (revenge)
        }
     }
    

Notice please that we can have so many dragons and Shaolins in this game or simulation and any passive holder (unit) should only react to the attacker (unit) etc.

Edit : (Recap of the main problem)

How to subscribe via PassiveAbility.initListeners() to an event fired from any instance of type FireEffect (an ability that use fireEffect) ???

Many thanks in advance for your support and contribution.

Youness

Bakkoto
  • 43
  • 4
  • 1
    Perhaps you can narrow down the code to the specific problem/question? – Magnus Jun 25 '14 at 10:58
  • My Bad sorry .Here is a recap for you : How to subscribe in PassiveAbility.initListeners() to an event fired from any Instance of type FireEffect ?? – Bakkoto Jun 25 '14 at 11:38
  • Why do you have a custom event dispatcher? What functionality does it offer you that normal events do not? – Nick Udell Jun 26 '14 at 11:09

1 Answers1

0

Add a static EventDispatcher to FireEffect and subscribe to that.

public class FireEffect : BaseEffect
{
    public static EventDispatcher FireEffectEventDispatcher = new EventDispatcher(null,null);

    public FireEffect(BaseAbility effectOwner)
    {
        this.Owner = effectOwner;
        this.Name = "Fire";
    }

    public override void CalculateEffect(Unit target)
    {
        // set the event here (to get the target as argument for the event)
        FireEffectEventDispatcher.mySender = Owner;
        FireEffectEventDispatcher.myArgument = new EffectEventArgs(target);
        // Fire the event
        FireEffectEventDispatcher.DispatchMyEvent();
        //If you still want the base effect firing.
        base.CalculateEffect(target);
    } 
}

To make this work, you'll also need to change your EventDispatcher to let you set the sender / argument after construction (not being able to doesn't make any sense anyway - it's a useless restriction).

I would recommend redoing (or removing) your EventDispatcher implementation, however. It makes no sense to set your event parameters in the constructor when they can more reasonably be set during event triggering.

Nick Udell
  • 2,420
  • 5
  • 44
  • 83
  • Additionally, I would recommend revisiting your OOP design. This reeks of over-engineering a problem. A custom event dispatcher that does *nothing* more than make it harder to dispatch events without any good reason to do so is only wasted code and time. – Nick Udell Jun 26 '14 at 11:17
  • Thank you Nick for your suggestion.The EventDispatcher is intended to organize the code but i guess you're right. It would be handy to get rid of it. As for the rest, i still worry about the public static approach!! as you know everything in this logic is running asynchronously with multiple Units distpatching events via Effects and in some cases simultaneously. Is it wise to go with such an approach?? And what would you suggest to improve the current design.Some code snippets are more than welcome. Thank you again – Bakkoto Jun 26 '14 at 13:31
  • Why do you worry about public static approaches? In an asynchronous case events will prove more complicated. Try here for more info: http://stackoverflow.com/questions/2403972/c-sharp-events-between-threads-executed-in-their-own-thread-how-to – Nick Udell Jun 26 '14 at 13:44
  • Ok i will give it a try tanks. – Bakkoto Jun 26 '14 at 18:19
  • Well I did everything to avoid static events for no reason ! that was stupid my bad but hey , thanks for all your support I appreciate it. Answer marked and up-voted. – Bakkoto Jun 27 '14 at 08:36