Unity - 使用枚举属性来检测碰撞的对象

Posted

技术标签:

【中文标题】Unity - 使用枚举属性来检测碰撞的对象【英文标题】:Unity - using enum properties to detect objects colliding 【发布时间】:2018-05-01 11:22:51 【问题描述】:

昨晚我在做一个 C-Sharp 项目,试图围绕相互碰撞的游戏对象编写代码。我想要不同的门类型(例如木头、石头、金属),它们可以被不同的武器(例如棍棒、剑、斧头)分解。

为了检测 GateManager 上的碰撞,我为每个门使用了标签。比如:

    void OnTriggerEnter(Collider collider) 
       switch (gameObject.tag) 
         case "WoodenGate":
             ...
         case "StoneGate":
             ...

上面的代码并不准确,但应该给出一个想法。将每种浇口类型设置为不同的标签感觉是错误的(如果每种浇口类型都有不同的标签,每种材料类型都有不同的标签等,那么我最终会得到数百个标签)。

所以我想出了一个替代方案。我设置了 GateType 的枚举并创建了 3 个值(WoodenGate、StoneGate、MetalGate)。然后,我将公共 GateType 属性附加到 GateManager 类。这使我可以在统一的“检查器”窗口中选择与每个预制件相关的枚举。它非常整洁,我真的很高兴。

然后出现了一个问题:我在列表的中间添加了第四个枚举(例如 GlassGate)。因为枚举只是 int 值,所以第三项不再是 MetalGate,而是现在的 StoneGate。这意味着金属门预制件突然有了一个 GateType 石门。这打破了我的游戏。

抱歉,对于这个冗长的问题,但我的问题是我应该如何最好地标记和识别许多不同类型的项目?我不想使用标签(因为我需要太多标签)并且我不想使用枚举(因为它们在与统一检查器结合使用时会形成脆弱的问题。

我认为这一定是许多游戏的共同要求(例如,在游戏中,您可以在许多不同的游戏对象上使用镐来收集不同的资源)所以只是想知道最佳实践吗?

【问题讨论】:

您尝试对每种门类型进行什么样的交互?与其在 GateManager 脚本中包含所有逻辑,不如编写一组 MonoBehaviour 类,每个类都指示一个反应,根据需要将它们附加到每个门,并在与门碰撞时盲目调用它们? (只需让它们都继承自同一个类/实现相同的接口即可轻松检索和调用它们。) 逻辑很简单,如果与门碰撞的武器级别足够高,则将门设置为不活动(即摧毁它)。所以例如一把剑可以摧毁木门,但不能摧毁金属门。如此非常简单的逻辑确实如此拥有多个类可能会过大? 在这种情况下,为什么不给每个物体(或组成它的材料)分配一个强度值,并为每个武器分配一个相应的强度?然后比较碰撞时的两个值。如果你必须为每一种门、每一种路障/家具物品/块/等等都做一个枚举,这将是很多枚举值,随着项目的增长,这些值将变得越来越难以维护。 Serlite - 谢谢。不敢相信我错过了它作为一种编码方式。很棒的东西 【参考方案1】:

1。您可以声明并使用许多接口来完成此操作,但缺点是您需要声明许多接口并在附加到每个对象的许多脚本中实现它们:

public interface IDestroyable  

public interface IOpenable  

然后你在你的脚本中继承它:

public class MyScript : MonoBehaviour, IDestroyable

public class MyOtherScript : MonoBehaviour, IOpenable

在碰撞过程中检查是哪一个:

void OnTriggerEnter(Collider collider)

    if (collider.GetComponent<IOpenable>() != null)
    

    

    else if (collider.GetComponent<IDestroyable>() != null)
    

    


2。您也可以使用您提到的枚举。

public enum GateType

    WoodenGate,
    StoneGate,
    MetalGate

将描述此对象是什么类型的门的单个脚本附加到所有门对象预制件,然后从编辑器或脚本中为每个门选择枚举

public class GateDescription : MonoBehaviour

    public GateType gateType;

在碰撞过程中检查是哪一个:

void OnTriggerEnter(Collider collider)

    GateDescription gateType = collider.GetComponent<GateDescription>();

    if (gateType != null)
    
        switch (gateType.gateType)
        
            case GateType.StoneGate:
                break;

            case GateType.WoodenGate:
                break;

            case GateType.MetalGate:
                break;
        
    

【讨论】:

我认为接口是要走的路。 @AdamB 使用接口的唯一缺点是您必须为从不同接口继承的每个门创建许多脚本。除此之外,应该没问题。 是的,但我认为从长远来看,代码的可读性会更高。需要做更多的设置工作,但最终会更加易于理解和使用。 是的,可读性是为此使用接口的优势之一。【参考方案2】:

枚举是最方便的方法。为枚举值添加索引并手动递增。

public GateType gateType;

public enum GateType

    Wood = 0,
    Stone = 1,
    Brick = 2

现在,如果您想在“列表”中间添加另一个,请这样做:

public GateType gateType;

public enum GateType

    Wood = 0,
    Metall = 3,
    Stone = 1,
    Brick = 2

Unity 应该在您的对象上保留正确的值,因为您添加了索引。

【讨论】:

【参考方案3】:

您可以根据 spawn/init 事件进行设置。如果您要使用 enum 方法,您可以在生成对象时定义它。这显然取决于您的游戏机制。但是,我可能会将其外包给专门针对您想要的物质行为的单一行为。这样,如果您想更改木拱门的行为方式,您只需更新一个脚本并且它是独立的。这将有助于您的代码库变得更大,并且如果您使用 2017.3 的功能(允许您定义哪些文件进入哪些程序集)将改善编译和加载时间

【讨论】:

以上是关于Unity - 使用枚举属性来检测碰撞的对象的主要内容,如果未能解决你的问题,请参考以下文章

Unity 2d 中的碰撞检测

使两个物理对象不碰撞,但在 Unity 中检测碰撞

unity 用角色控制器怎么检测碰撞

unity3d 碰撞检测

unity3d 怎么检测碰撞?比如主角碰撞到物体之后销毁被撞到的物体

unity_小功能实现(碰撞检测)