C# 与物体相互作用的统一性

C# 与物体相互作用的统一性,c#,unity3d,2d,interaction,C#,Unity3d,2d,Interaction,我正在使用unity构建一个简单的自上而下的类似胭脂的游戏。我有开发经验,但我是unity框架和c#的初学者。是否有一种干净优雅的方式来处理玩家对象与场景中其他各种类型对象的交互 例如,场景中将充满墙、敌人和其他阻挡路径的对象,玩家可以通过尝试向它们的方向移动来与之交互。站在胸部附近并向其方向移动不会移动玩家,而是打开胸部。如果移动到墙上,会损坏它,等等 目前,我正在使用raycast2d获取阻塞路径的对象,但在不检查对象类型的情况下,无法找到如何与其交互的解决方案(是墙;是胸部;等等)。我制作

我正在使用unity构建一个简单的自上而下的类似胭脂的游戏。我有开发经验,但我是unity框架和c#的初学者。是否有一种干净优雅的方式来处理玩家对象与场景中其他各种类型对象的交互

例如,场景中将充满墙、敌人和其他阻挡路径的对象,玩家可以通过尝试向它们的方向移动来与之交互。站在胸部附近并向其方向移动不会移动玩家,而是打开胸部。如果移动到墙上,会损坏它,等等

目前,我正在使用raycast2d获取阻塞路径的对象,但在不检查对象类型的情况下,无法找到如何与其交互的解决方案(是墙;是胸部;等等)。我制作了一个接口,所有可交互对象都使用interact()方法实现,但不同类型的对象需要不同的信息。一堵墙需要它所能承受的伤害(取决于玩家等级中的玩家属性),而胸围则不需要。因此,它们很难实现相同的接口。让墙问玩家他的伤害是什么也是糟糕的编程实践

我在不久前发布的文章中发现了一个类似的问题。它建议使用观察者模式,但我无法想象场景中的每个对象都订阅了玩家移动事件,并在每次移动后检查它是否被击中


这种互动有没有标准的解决方案?一个松散耦合、干净且遵循良好编程实践的游戏?

如果我是你的情况,我会在对象(墙、箱子等)中添加一个带有
碰撞R2D
的空游戏对象,并切换
isTrigger
框。(请注意,这将要求对象派生自
monobhavior
,这可能并不总是可取的。)

在此基础上,我将使用一些专门功能的组合
OnTriggerStay
OnTriggerEnter
OnTriggerExit

//in Chest.cs
void OnTriggerEnter() //http://docs.unity3d.com/ScriptReference/Collider.OnTriggerEnter.html
{
    OpenChest();
} 

//in Wall.cs
void OnTriggerStay() //http://docs.unity3d.com/ScriptReference/Collider.OnTriggerStay.html
{
    DamageWall();
}
从这里开始,您有两个选择来确保某些游戏对象不会触发错误的碰撞器。一种方法使用代码:

//in Chest.cs
void OnTriggerEnter(Collider other)
{
    //notice this won't be very efficient
    if(other.gameObject.GetComponent<PlayerScript>() != null) OpenChest();
    //if(other.name == "The Player") OpenChest(); //probably less efficient at runtime
}
edit2:拆卸联轴器:

OnTriggerStay(Collider other)
将为每个实例调用,如果所有怪物和玩家都造成相同的伤害,那么它会很好地工作,但情况显然不是这样。如果每个实例造成的伤害不同,您可以执行以下操作:

void OnCollisionEnter(Collision other)
{
    addSelfDPS(other.gameObject.GetComponent<WallDamager>().getDPS());
}
void OnCollisionExit(Collision other)
{
    addSelfDPS(-1*other.gameObject.GetComponent<WallDamager>().getDPS());
}
void OnCollisionEnter(碰撞其他)
{
addSelfDPS(other.gameObject.GetComponent().getDPS());
}
void OnCollisionExit(碰撞其他)
{
addSelfDPS(-1*other.gameObject.GetComponent().getDPS());
}

但是,如果使用此方法,在触发器内部生成和销毁对象时会出现问题,因此您可能需要在任何构造函数(唤醒/启动)或析构函数(OnDestroy)中解决此问题。

查找层和碰撞器。它们究竟有何帮助?我可能不完全理解层和碰撞器。我知道它们用于指定同一层上的对象可以碰撞。但是胸部和墙壁都和玩家在同一个阻挡层上,我想做的是让他们对交互做出不同的反应,而不必检查它是墙还是其他东西。谢谢你的回复,这非常有用,给了我一些想法。然而,这并不能完全解决问题。例如,一个玩家撞到了一堵墙。触发器将关闭,可以调用DamageWall(),但这意味着DamageWall()必须保留对玩家对象的引用,并检查它需要承受多少伤害。它会导致耦合。此外,如果是怪物而不是玩家撞到墙,DamageWall()必须检查怪物的类型并获得其伤害。。。20个不同的怪物?更多的类型检查和耦合。@mattdnwny我编辑了上面的注释。我该如何避免这个问题?@EimantasŠapoka我认为edit2中的解决方案可能足以解决您的问题。这是否意味着任何能够损坏墙壁的对象都必须有一个脚本/实现接口WallDamager?@EimantasŠapoka是的,但它可以是任何具有名为getDPS()的公共方法的类/脚本(例如,如果你有一个角色脚本,玩家和敌人都是从该脚本派生出来的,它有一个名为getDPS的公共方法,你可以使用该方法)。当然,这假设组件/脚本附加到对象上,如果不是,你应该先检查是否为空。
void OnCollisionEnter(Collision other)
{
    addSelfDPS(other.gameObject.GetComponent<WallDamager>().getDPS());
}
void OnCollisionExit(Collision other)
{
    addSelfDPS(-1*other.gameObject.GetComponent<WallDamager>().getDPS());
}