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

时间:2014-06-25 10:32:20

标签: c# events game-engine

我目前正在开发一款小型游戏引擎,而且我有点想找到合适的模式。 首先是一些代码片段,以了解我想要实现的目标:

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

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

    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();
    
    }
    
  • 效果:

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

     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);
       }
     }
    
  • 两个单位,让我们说: “龙”作为单位=&gt;有FireBall(能力)并且会击中=&gt; “少林风之师”作为单位有一个被称为“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)
        }
     }
    

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

编辑:(回顾主要问题)

如何订阅通过 PassiveAbility.initListeners()事件从任何类型的FireEffect 触发事件 (使用fireEffect的能力)???

非常感谢您的支持和贡献。

Youness

1 个答案:

答案 0 :(得分:0)

将静态EventDispatcher添加到FireEffect并订阅。

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,以便在构建后设置发件人/参数(无论如何都无法理解 - 它&# 39;无用的限制)。

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