【问题标题】:What is better: link to a GameObject or to a Class in Unity?哪个更好:链接到游戏对象或 Unity 中的类?
【发布时间】:2018-11-02 00:45:29
【问题描述】:

示例:游戏对象 A 附加了一个名为 MakeItRain 的脚本。该脚本内部是一个 public void Drizzle();

GameObject B 也有一个脚本,想告诉 MakeItRain 做 Drizzle();

在 GameObject B 的脚本中,我可以这样做:

public GameObject makeitrain;

然后我必须使用 GetComponent 来到达 Drizzle();在我的代码中。 在检查器中,我将 GameObject A 放入 makeitrain 的插槽中,然后就完成了。

但是,我也可以在 GameObject B 的脚本中执行此操作:

public MakeItRain makeitrain;

然后在我的 GameObject B 脚本代码中调用 makeitrain.Drizzle();,不使用 GetComponent。

在这两种情况下,在 Inspector 中,我都必须将 GameObject A 拖放到 GameObject B 的插槽中。

我绝对不应该选择最后一个选项有什么不同或原因吗?我知道第一种方法给了我更大的灵活性,因为我也可以调用 GameObject A 的其他组件,而不仅仅是脚本的东西。只是想知道不使用第二种方法是否还有其他理由。

【问题讨论】:

  • 这完全取决于您的客户端代码(我想是脚本 A)是要直接使用游戏对象还是游戏对象的附加脚本组件。第二种方法没有提供第一种方法提供的一件事是强类型。我个人尽量避免在原版游戏对象之间出现过多的“意大利面条式”跨对象/脚本/组件引用;强类型在这里可以提供帮助。

标签: c# unity3d


【解决方案1】:

答案取决于您是否需要调用 MakeItRain 脚本中的任何函数或使用变量。

如果您不需要调用MakeItRain 脚本中的任何函数或从中访问任何变量,那么最好使用 GameObject 作为参考。另外,如果您需要做的是激活、停用、旋转游戏对象,然后使用游戏对象作为参考。

另一方面,如果您需要能够从多个地方调用Drizzle等函数或从MakeItRain脚本访问变量,那么您需要使用MakeItRain 参考。此时,使用 GameObject 引用没有意义,因为使用它时,每次需要调用函数或从附加的MakeItRain 脚​​本访问变量时都需要使用GetComponent

最后,当使用MakeItRain 脚本引用您的对象时,您可以直接轻松地访问它所附加的游戏对象,而无需使用makeitrain.gameObject。这不需要使用GetComponent 函数。

只是想知道是否还有其他理由不这样做 第二种方法。

由于需要使用GetComponent 函数导致的性能问题是原因。在StartAwake 函数中使用一次并初始化MakeItRain 变量会更好。

例如,这样更好:

public MakeItRain makeitrain;

void Start()
{
    makeitrain = GetComponent<MakeItRain>();
}

void Update()
{
    makeitrain.Drizzle();
}

比这个:

public GameObject makeitrain;

void Update()
{
    makeitrain.GetComponent<MakeItRain>().Drizzle();
}

并且应该用于避免必须在原生端搜索组件每一帧

【讨论】:

    【解决方案2】:

    使用MakeItRain 并显式定义类型比使用GameObject 更好。

    正如@hacksalot 评论的那样,使用 MakeItRain 可以提供强类型。这样做的好处之一与您的评论有关:

    在这两种情况下,在 Inspector 中,我都必须拖放 GameObject A 进入 GameObject B 的插槽。

    如果您将公共变量类型显式设置为MakeItRain 而不是GameObject,则无法将游戏对象 A 拖放到游戏对象 B 的插槽中除非游戏对象 A 有正确类型的脚本。这为您提供了编译时/编辑器时检查,您正在 Unity 编辑器检查器中链接到正确的游戏对象

    此外,虽然不一定如此,使用GameObject 引用通常会导致代码混乱,无论是因为没有指定类型而将方法不必要地链接在一起(例如GetComponent),或者因为它在编写和使用辅助方法时增加了一些摩擦。甚至在一个简单的例子中考虑哪个读起来更好:

    makeitrain.Drizzle()

    makeitrain.GetComponent&lt;MakeItRain&gt;().Drizzle()


    我知道第一种方法给了我更多的灵活性,因为我 也可以调用 GameObject A 的其他组件,而不仅仅是 脚本的东西。

    请注意,您仍然可以灵活地访问GameObject,只是有点冗长(这是这种方法的一个缺点):

    public MakeItRain makeitrain;
    
    void Start()
    {
        makeitrain.gameObject.SetActive(false)
    }
    

    但是,无论如何,您很可能会使用辅助方法(除了基本调用之外),甚至是包装器方法(编写起来不方便,但有时有助于提高可读性)。

    在大多数情况下,链接到类而不是 GameObject 的好处大于坏处。

    【讨论】:

      【解决方案3】:

      如果你不想使用GetComponent(),你可以直接使用SendMeassage(),像这样

      public Gameobject makeItRain;
      void Start(){
          makeitrain.SendMeassage("Drizzle");
      }
      

      另一种链接脚本的方法是使用FindObjectOfType(),不需要将GameObject拖放到插槽中,这里是示例

      void Start(){
          MakeItRain makeitrain = FindObjectOfType("MakeItRain");
      }
      

      您也可以使用Gameobject.Find() 链接GameObject 而不是拖到插槽中,但我不推荐这种方式,因为您需要找到场景中的每一个游戏对象,因此会消耗很多性能。

      【讨论】:

      • SendMeassage 不是因为反射变慢了吗?当您有一个组件的多个实例时,如何区分使用 FindObjectOfType 获取哪个组件?
      • 顺便说一句,您要么必须进行类型转换 (MakeItRain)FindObjectOfType("MakeItRain"); 或更好地使用通用版本 FindObjectOfType&lt;MakeItRain&gt;(); 仍然 PassetCronUs 是正确的,如果您的场景中有多个类型的组件,这将不起作用 - OP的问题就是这种情况
      • 除了 SendMessage 很慢之外,当您决定将 Drizzle() 方法重命名为其他名称时,它会静默停止工作。我在 Unity 论坛上看到的关于 SendMessage 的最佳类比:SendMessage 是当魔鬼敲鼓让所有最丑陋的野兽出来时。
      猜你喜欢
      • 2020-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多