C# 在不修改对象的情况下设计可修改的对象间交互';密码
假设我们在Unity的环境中 假设我们有PlayerA对象和PlayerB对象。PlayerA想要造成伤害(即降低PlayerB的健康变量) 我希望设计一个交互系统,允许修改如果PlayerA发出对PlayerB造成X伤害的信号会发生什么,并且允许在不修改PlayerA或PlayerB代码的情况下进行修改C# 在不修改对象的情况下设计可修改的对象间交互';密码,c#,oop,unity3d,C#,Oop,Unity3d,假设我们在Unity的环境中 假设我们有PlayerA对象和PlayerB对象。PlayerA想要造成伤害(即降低PlayerB的健康变量) 我希望设计一个交互系统,允许修改如果PlayerA发出对PlayerB造成X伤害的信号会发生什么,并且允许在不修改PlayerA或PlayerB代码的情况下进行修改 简言之,一旦玩家效果累积起来,我不希望DealDamage函数有几十个if(hasArmorEffect)、if(isImmuneEffect)、if(HasDamagerReflection
简言之,一旦玩家效果累积起来,我不希望DealDamage函数有几十个if(hasArmorEffect)、if(isImmuneEffect)、if(HasDamagerReflectionEffect)检查来检查所有这些东西。理想情况下,该系统的工作方式是,程序员可以编写装甲组件,将其挂接到某个地方,表示他对计算伤害感兴趣,并将其附加到游戏对象上,而无需修改a和B代码。我会用修改器列表解决这个问题。假设您有以下接口:
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
}
}
不过,这种方法容易受到修改器顺序的影响。例如,如果先放置“反射”修改器,则其反射的伤害将比最后放置的伤害更多。例如,您可能需要使用优先级/排序系统来扩展系统
如果攻击者和目标都有反射修饰符,则此反射修饰符也容易受到stackoverflow异常的攻击,因此请小心
希望这有帮助。埃里克·利珀特阅读。这是一篇由五部分组成的博客文章,详细描述了你最有可能处理的一个相关问题以及如何解决它。具体来说,上述系列文章中的一部分涉及的内容与你在问题中描述的内容非常相似。
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;
}
}