【问题标题】:Why are transforms typically passed when working with in-game objects rather than game objects?为什么在使用游戏内对象而不是游戏对象时通常会传递变换?
【发布时间】:2019-06-13 15:46:34
【问题描述】:

我在学习 Unity 基础知识方面做得很好,但想确定我对组件和拥有它们的对象之间关系的理解。在我一直在观看的教程中,在处理代码中提取的对象时,通常会使用或传递 Transform 组件。例如:

void Explode ()
{
    Collider[] colliders = Physics.OverlapSphere(transform.position, explosionRadius);
    foreach (Collider collider in colliders)
    {
        if (collider.tag == "Enemy")
        {
            Damage(collider.transform);
        }
    }
}

它通过它找到的对撞机上的变换调用“Damage”:

void Damage (Transform enemy)
{
    Enemy e = enemy.GetComponent<Enemy>();
    if (e != null)
    {
        e.TakeDamage(damage);
    }
}

看看这个,很明显它正在拉取一个在所有游戏对象上找到的组件,然后使用“GetComponent”按名称拉取另一个组件实例,因为“Enemy”组件不会有自己的方法。为什么不直接传递 collider.gameObject 呢?我试过这个(在改变伤害以期望一个游戏对象之后),它工作得很好。

这对我来说似乎更直观,但我看到的所有教程都使用转换组件。有谁知道为什么会这样?这将帮助我加深对 Unity 如何构建其代码的理解。

【问题讨论】:

  • 可能你看过的所有教程都是从一个祖先那里复制过来的
  • 就个人而言,我实际上会尝试使用GetComponent&lt;Enemy&gt;() 拳头,而不是调用传递对Enemy 的引用的方法;)
  • 这对我来说很有意义 derHugo。还有 Shingo,我一直在看 Brackeys 的教程和 Unity 本身的一些教程。这似乎是一种正在发展的模式,所以我想问问社区。​​span>

标签: c# unity3d


【解决方案1】:

我不确定您正在学习哪些教程,但我第一次使用 Unity 时遵循的教程使用的是 GameObject 而不是 Transform。

我同意使用 GameObject 更直观。 Transform 是 GameObject 的一部分或 Component,但由于它是强制性的,所以它始终存在,因此公共字段 .transform。但由于从技术上讲,GameObject 是其所有组件的持有者,因此将其作为参数传递是最合乎逻辑的、架构明智的。

归根结底,您的示例几乎没有什么区别,因为您可以在 Transform as GameObject 上调用许多相同的方法。

TLDR:

使用任何你认为最有意义的东西。

【讨论】:

  • 谢谢!这很有帮助。
【解决方案2】:

简答

GameObject 如你所说更直观。

长答案

我认为(我的观点)最好传递最具体和最相关的组件。

例如,假设你有一个让角色捡起箱子的功能:

public void PickUp(Transform crate)
{
    crate.SetParent(this.transform);
    crate.localPosition = Vector3.zero; // or whatever your attachment point is
}

在我看来,Transform 被传递是有道理的,因为它是需要的最具体的组件。通过在此处传递 GameObject,您只会延迟不可避免的 GetComponent&lt;Transform&gt;go.transform

另一方面,如果您有一个隐藏创建的功能,那么传递游戏对象将是实现此目的所需的最低限度:

public void Hide(GameObject crate)
{
    crate.SetActive(false);
}

传递其他任何东西只会延迟不可避免的x.gameObject

在爆炸示例中,老实说,我认为我也不会通过。我可能会这样做:

void Explode ()
{
    Collider[] colliders = Physics.OverlapSphere(transform.position, explosionRadius);

    var enemies = colliders
                 .Select(x => x.GetComponent<Enemy>())
                 .OfType<Enemy>(); // Or IHealth, IDamageable, ITarget, etc if you have other things that can take damage.

    foreach (var enemy in enemies) // If empty, nothing will happen by default
    {
       enemy.TakeDamage(damage);
    }
}

通过这种方法,您可以看到不需要检查标签或空值。可枚举的敌人保证包含敌人或根本不包含任何内容。

通过始终传递 gameObject/transforms,您将始终需要担心您在目标组件中真正收到的是什么。你也会对自己不确定的情况敞开心扉,因为它可能是系统中正在进行这些更改的任何东西。您的ColorChangerComponent 实际上也可能在移动对象,破坏其他一些组件等。通过为组件提供渲染器,它更自然地将组件限制为仅在渲染器上进行更改(尽管您显然可以违反此限制,除非您执行针对适当接口的操作)。

唯一真正有意义的传递通用组件的情况是,当您将此“事件”广播到一堆可能的接收器时,这些接收器将使用对象发送不同的东西。 IE。您在编译时无法确定游戏对象将用于什么,或者您知道它将用于许多不同的事情。

Unity 本身为碰撞检查返回Collider[] 的事实支持了这种思路,否则它只会返回GameObject[]OnTriggerEnter(Collider collider)OnCollisionEnter(Collision collision) 等也是如此。

【讨论】:

  • 你应该在你的脚本顶部有using System.Linq; ;)
  • 感谢您的扩展讨论。这正是我一直在寻找的那种视角!
猜你喜欢
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多