2

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

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

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

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

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

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

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

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

4

3 回答 3

4

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;
        }
    }
}
于 2017-11-17T16:36:03.713 回答
1

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

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 应该在您的对象上保留正确的值,因为您添加了索引。

于 2017-11-17T16:27:45.117 回答
0

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

于 2017-11-17T16:38:28.320 回答