游戏事件、效果模式设计

概念


扳机(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);
        }
    }
}

优势

  • 能很好地将效果与事件独立开,可以做到一些隐藏事件;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值