概念
扳机(Trigger)
时机。如 “死亡时”,“攻击时”,“使用卡牌时”。
事件(Event)
在某个扳机下的一个动作序列,称为在该扳机下的事件。简单地,可以将事件理解为动作序列。
例如 “抽一张牌” 即为一个事件,它可以是任何扳机下的事件。
例如 “如果伤害来源是卡牌,则获得它” 也是一个事件,但它以 “伤害来源” 作为参数,故只能是某些扳机(如 “受到伤害时” )下的事件。
效果(Buff)
作用到一个单位的整体增益。
例如 “每当一个单位攻击或发动技能,抽一张牌,如果是法术牌,再额外抽一张” 是效果。该效果可以分解为如下事件:
- 每当单位攻击时:“抽一张牌,如果是法术牌,再额外抽一张” ;
- 每当单位发动技能时:“抽一张牌,如果是法术牌,再额外抽一张” ;
例如 “祷告(10):对所有敌方单位造成 10 点伤害。每次受到伤害或抽牌时,祷告 -1,祷告为 0 时触发效果” 是效果。该效果可以分解为如下事件:
- 每次受到伤害时,调用【祷告】;
- 每次抽牌时,调用【祷告】;
同时定义动作【祷告】:
- 祷告值减一,如果为 0,则对所有敌方单位造成 10 点伤害,同时移除该 Buff 并移除上述两个事件。
设计模式一:效果为事件的载体
概念
即效果对象包含了所有扳机下的事件。
示例如下:
namespace DesignMode1
{
public delegate void BattleEvent(Battle battle, Character character);
public delegate void DamageEvent(Battle battle, IDealDamage source, IGetDamage target, int damage);
public class Buff
{
public BattleEvent Summon { get; set; }
public BattleEvent Die { get; set; }
public DamageEvent GetDamage { get; set; }
public DamageEvent DealDamage { get; set; }
}
public class Character : IDealDamage, IGetDamage
{
public Battle Battle { get; }
public List<Buff> buffs { get; }
public void OnGetDamage(IDealDamage source, int damage)
{
foreach (Buff b in buffs) if (b.GetDamage) b.GetDamage.Invoke(Battle, source, this, damage);
}
}
}
上述示例中,Buff
类包含了所有扳机下的事件,但有时候无法提前知道是否触发某事件,例如 “受到来自卡牌的伤害后,获得该卡牌”,实现在 GetDamage
扳机内,但在其实现方法内还存在 “伤害源是否为卡牌” 这样一层判定,无法提前获知是否满足该条件。
于是有另一个更好的方法解决:
namespace DesignMode1_v2
{
public class BattleArgs
{
public Battle Battle { get; set; }
public Character Raiser { ; set; } // Who Raise the Event.
}
public class DamageArgs : BattleArgs
{
public IDealDamage Source { get; set; }
public IGetDamage Target { get; set; }
public int Damage { get; set; }
}
public interface IAction { }
public interface ISummonAction : IAction
{
bool HasSummon(BattleArgs args);
void Summon(BattleArgs args);
}
public interface IDieAction : IAction
{
bool HasDie(BattleArgs args);
void Die(BattleArgs args);
}
public interface IGetDamageAction : IAction
{
bool HasGetDamage(DamageArgs args);
void GetDamage(DamageArgs args);
}
public interface IDealDamageAction : IAction
{
bool HasDealDamage(DamageArgs args);
void DealDamage(DamageArgs args);
}
public class Character : IDealDamage, IGetDamage
{
public Battle Battle { get; }
public List<IAction> buffs { get; }
public void OnGetDamage(IDealDamage source, int damage)
{
DamageArgs args = new DamageArgs()
{
Battle = Battle,
Raiser = this,
Source = source,
Target = this,
Damage = damage,
};
foreach (IAction b in buffs)
if (b is IGetDamageAction ac && ac.HasGetDamage()) ac.GetDamage(args);
}
}
}
这种方法添加的 Buff
,必须在实现一个类后添加。
或者预定义一个 Buff
抽象类,提供所有 Buff
的公共属性或方法,在实现时继承事件接口。
namespace DesignMode1_v3
{
public class BattleArgs
{
public Battle Battle { get; set; }
public Character Raiser { get; set; } // Who Raise the Event.
}
public class DamageArgs : BattleArgs
{
public IDealDamage Source { get; set; }
public IGetDamage Target { get; set; }
public int Damage { get; set; }
}
public interface ISummonAction
{
bool HasSummon(BattleArgs args);
void Summon(BattleArgs args);
}
public interface IDieAction
{
bool HasDie(BattleArgs args);
void Die(BattleArgs args);
}
public interface IGetDamageAction
{
bool HasGetDamage(DamageArgs args);
void GetDamage(DamageArgs args);
}
public interface IDealDamageAction
{
bool HasDealDamage(DamageArgs args);
void DealDamage(DamageArgs args);
}
public abstract class Buff
{
public abstract string Name { get; }
public abstract string Description { get; }
public abstract string Abstract { get; }
}
public class Character : IDealDamage, IGetDamage
{
public Battle Battle { get; }
public List<Buff> Buffs { get; }
public void OnGetDamage(IDealDamage source, int damage)
{
DamageArgs args = new DamageArgs()
{
Battle = Battle,
Raiser = this,
Source = source,
Target = this,
Damage = damage,
};
foreach (Buff b in Buffs)
if (b is IGetDamageAction ac && ac.HasGetDamage()) ac.GetDamage(args);
}
}
}
优势
- 能清楚地知道某个事件是由什么效果给予的。
设计模式二:效果为控制事件的载体
概念
即效果对象控制着添加、移除事件,而本身不包含事件。
示例如下:
namespace DesignMode2
{
public delegate void BattleEvent(Battle battle, Character character);
public delegate void DamageEvent(Battle battle, IDealDamage source, IGetDamage target, int damage);
public class Buff
{
public Action<Character> Apply { get; }
public Action<Character> Remove { get; }
public Buff(Action<Character> apply, Action<Character> remove)
{
Apply = apply;
Remove = remove;
}
}
public class Character : IDealDamage, IGetDamage
{
public BattleEvent OnSummon { get; set; }
public BattleEvent OnDie { get; set; }
public DamageEvent OnGetDamage { get; set; }
public DamageEvent OnDealDamage { get; set; }
public List<Buff> buffs { get; }
public void AddBuff(Buff buff)
{
buffs.Add(buff);
buff.Apply(this);
}
public void RemoveBuff(Buff buff)
{
buffs.Remove(buff);
buff.Remove(this);
}
private class GetDamageBuff : Buff
{
private DamageEvent eventAction;
private void _Apply(Character character) { character.OnGetDamage += eventAction; }
private void _Remove(Character character) { character.OnGetDamage -= eventAction; }
public GetDamageBuff(DamageEvent e) : base(_Apply, _Remove) { eventAction = e; }
}
public void ExampleAddBuff()
{
GetDamageBuff buff = new GetDamageBuff(delegate (Battle battle, IDealDamage source, IGetDamage target, int damage)
{
// Do Somgthing
});
this.AddBuff(buff);
}
}
}
优势
- 能很好地将效果与事件独立开,可以做到一些隐藏事件;