如何订阅从任何类型X的实例/对象触发的事件

本文关键字:对象 事件 实例 任何 类型 何订阅 | 更新日期: 2023-09-27 18:10:16

我目前正在制作一个小型游戏引擎,我有点困在寻找正确的模式。首先,这里有一些代码片段来理解我想要实现的目标:

  • 单位:技能施法者/目标(投掷或接收技能)

    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();
       }
    }
    
  • 事件调度器:

    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");
        }
      }
    }
    
  • Effect事件参数:

     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;
       }
     }
    

现在我要为模拟创建2个效果,2个技能和2个单位:

  • 火焰效果:

      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);
        } 
      }
    
  • 风效果:与火效果相同,但名称和事件不同,应用的效果也不同。

  • 火球技能:

     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);
       }
     }
    
  • 两个单位,假设:"龙"作为单位=>有火球(技能)并且会命中=>"少林风之师"作为单位拥有被动技能"风之怒"

  • 风怒:

      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)
        }
     }
    

请注意,我们可以在这个游戏或模拟中有这么多龙和少林,任何被动的持有者(单位)应该只对攻击者(单位)做出反应。

编辑:(重述主要问题)

如何订阅通过PassiveAbility.initListeners()到一个事件从任何实例类型的FireEffect(使用FireEffect的能力)?

提前感谢您的支持和贡献。

尤尼斯

如何订阅从任何类型X的实例/对象触发的事件

FireEffect添加一个静态EventDispatcher并订阅。

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);
    } 
}

要做到这一点,你还需要改变你的EventDispatcher,让你在构造后设置发送者/参数(不能够无论如何没有任何意义-这是一个无用的限制)。

但是,我建议重做(或删除)您的EventDispatcher实现。如果可以在事件触发期间更合理地设置事件参数,那么在构造函数中设置事件参数是没有意义的。