这个RPG游戏效果系统的设计有什么问题,或者我如何从不同的派生效果列表中删除所有特定效果?

时间:2018-05-29 13:30:33

标签: c# oop inheritance interface

我想我遇到了一个设计问题......我不确定如何解决自己。很抱歉,但我必须提供一些基本的设计信息...

一场比赛。玩家,怪物,物体,不同的东西可能会受到不同的影响:

public interface IEffect {}

可能有不同的特效:

public interface IResistanceBuff : IEffect
{
    void modifyIncomingDamage(Damage damage);
}

public interface IDamageBuff : IEffect
{
    void modifyOutgoingDamage(Damage damage);
}

为什么这样?好吧,它避免重复代码的概念。例如,通过这种方式,我可以统一类型阻力减少伤害,例如穿着盔甲。简单地说,我创建了Type类和Armor类实现IResistanceBuff。 (类似地,Weapon类将实现IDamageBuff)。

但有些影响是暂时的,不是永久性的。为此,我们将:

public interface ITemporaryEffect : IEffect
{
    long TimeRemaining {get; set;}
}

同样,这里的目的是避免重复代码。例如,PotionOfMight类将实现IDamageBuff接口,并从Potion抽象类派生,而抽象类又将实现ITemporaryEffect接口。或者,我们将使用IStun接口,该接口将实现ITemporaryEffect

现在,每个可以处于特定效果下的对象都会存储它所有效果的集合(可能是HashSet?)。这是为了能够更轻松地调用这些效果。例如,一个角色将拥有一个属性public HashSet<IResistanceBuff> ResistanceBuffs {get; private set;},因此我们可以使角色的TakeDamage方法看起来像这样:

void TakeDamage(Damage damage)
{
    this.ResistanceBuffs.ForEach(resistanceBuff =>
        resistanceBuff.modifyIncomingDamage(damage)
    );

    this.HP -= damage.Amount;

    if(this.HP <= 0) {
        this.Faint();
    }
}

但问题出现了。我希望有一段代码来更新临时效果的剩余持续时间,并删除那些持续时间已过期的代码。

我的(not working, by design of C#)想法是使Character类(以及代表任何类型的Effect对象的任何其他类 - 这意味着甚至{ {1}},因为我认为我将天气状况存储为[{1}}应用于世界的情况)实施WorldMap界面:

Effects

现在处理临时效果到期将是IEffectStorage静态类的责任:

public interface IEffectStorage
{
    List<HashSet<IEffect>> AllEffects {get;}
}

public class Character : IEffectStorage
{
    // ...
    public HashSet<IResistanceBuff> ResistanceBuffs {get; private set;}
    public HashSet<IDamageBuff> DamageBuffs {get; private set;}
    // ...
    public List<HashSet<IEffect>> AllEffects =>
        new List<HashSet<IEffect>> {ResistanceBuffs, DamageBuffs, /* ... */};
}

但是,当然,正如我所说,我不能这样做。

现在我可能会开始寻找一些使用这种设计的hackish和/或丑陋的方法。另外,我可能会因为我未能很好地理解这个范例而尝试对C#编程语言和/或OO编程范式的设计做某些事情......特别是因为这是第一个项目这个规模我自己做的,我选择做后者......所以我问这个问题:)我的设计是否都错了,如果是,那么如何解决?

很抱歉这篇文章的篇幅很长,但我觉得上面的所有信息都是必要的。

1 个答案:

答案 0 :(得分:0)

我不是游戏开发者或者有游戏引擎的经验,但我认为大多数游戏或引擎都会使用类似框架的东西作为时间的安慰(也许我完全错了)。我的想法是将你的ITemporaryEffect改为

public interface ITemporaryEffect : IEffect
{
    bool IsActive(long currentFrame)
}

按如下方式实施:

public class SilencedEffect : ITemporaryEffect 
{
    private long duration = 1000;
    private long endFrame;

    public SilencedEffect(int currentFrame)
    {
        endFrame = currentFrame + duration;
    }

    public bool IsActive(long currentFrame)
    {
        return endFrame > currentFrame;
    }
}

通过这种方式,您可以在角色或世界地图类中对其进行迭代,如果不再处于活动状态,则将其删除。

public class Character
{
    private IList<ITemporaryEffect> temporaryEffect;         

    public void UpdateEffects(long currentFrame)
    {
        var outdatedTempEffects = temporaryEffect.Where(p => !p.IsActive(currentFrame));
        temporaryEffects.RemoveRange(outdatedTempEffects);
    }
}