设计可修改的对象间交互,而无需修改对象的代码

时间:2019-03-08 09:24:45

标签: c# oop unity3d

假设我们在Unity的环境中。

假设我们有PlayerA对象和PlayerB对象。玩家A要造成伤害(即降低玩家B的生命值)。

我正在设计一个交互系统,该系统将允许修改如果PlayerA表示要对PlayerB造成X伤害的意图,并且可以进行修改而无需修改PlayerA或PlayerB的代码。

简而言之,一旦播放器效果叠加,我不希望DealDamage函数具有几十个if(hasArmorEffect),if(isImmuneEffect),if(hasDamageReflectionEffect)检查是否将检查所有这些东西。理想情况下,系统将以程序员可以编写Armor组件的方式工作,将其挂接到某个位置以表示他对DealDamage计算感兴趣并将其附加到GameObject,而无需修改A和B代码。

1 个答案:

答案 0 :(得分:1)

我会用修饰符列表解决这个问题。假设您具有以下接口:

public interface IHealth
{
    float Health {get};
    void TakeDamage(float damage);
}

public interface IDamageModifier
{
   float Apply(float damage);
}

现在让我们进行一些修改器实现:

public class ShieldModifier : ScriptableObject, IDamageModifier
{
    private float shieldAmount = 10;

    public float Apply(float damage)
    {
        var actualDamage = Mathf.Max(0, damage - this.shieldAmount)

        return actualDamage;
    }
}

public class InvulnerabilityModifier: ScriptableObject, IDamageModifier
{
    public float Apply(float damage)
    {
        return 0;
    }
}

最后,您的敌人将拥有一系列修饰语:

public class Enemy : MonoBehaviour, IHealth
{
    public float Health {get; private set;}
    public List<IDamageModifier> modifiers; // Pretend this has both modifiers above.

    public void TakeDamage(float damage)
    {
        var actualDamage = damage;

        foreach(var mod in this.modifiers)
        {
            actualDamage = mod.Apply(actualDamage);
        }

        this.Health -= actualDamage; // 0 because of Invulnerability
    }
}

因此,如果您的敌人的盾牌修改器的盾牌值为10,那么攻击50伤害只会造成40伤害。

如果您希望修饰符可以通过检查器进行配置,则它们可以是可编写脚本的对象。

这种方法很基本。对于ReflectDamageModifier这样的效果,您的修改器界面可能需要以IHealth attacker为例:

public class ReflectDamageModifier: IDamageModifier
{
    private float reflectionFactor = 0.5; // Reflect 50% of damage

    public float Apply(float damage, IHealth attacker)
    {
        attacker.TakeDamage(damage * this.reflectionFactor);

        return damage;
    }
}

尽管如此,该方法容易受到修饰符的影响。例如,如果您将反射修改器放在第一位,则其反射的损害将比放在最后的反射更多。例如,您可能需要使用优先级/订购系统来扩展系统。

如果攻击者和目标都具有反射修饰符,则此反射修饰符也容易受到stackoverflow异常的影响,因此请当心。

希望这会有所帮助。