为什么在使用游戏内对象而非游戏对象时通常会传递变换?

时间:2019-06-13 01:00:54

标签: c# unity3d

我一直在学习Unity基础知识,但是想加深我对组件和拥有它们的对象之间的关系的理解。在我观看的教程中,当处理拉入代码的对象时,通常使用或传递Transform组件。例如:

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

在找到的对撞机上进行变换后调用“损坏”:

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

很明显,这是在拉取所有游戏对象上找到的Component,然后使用“ GetComponent”按名称拉取另一个组件实例,因为“ Enemy”组件不会有自己的方法。为什么不通过collider.gameObject呢?我尝试了此操作(在更改了损害以期望使用GameObject之后),并且工作正常。

对我来说,这似乎更直观,但是我看过的所有教程都使用了transform组件。有人对此有何见解?这将有助于我加深对Unity如何构造其代码的理解。

2 个答案:

答案 0 :(得分:1)

我不确定您要遵循哪些教程,但是当我第一次使用Unity时所遵循的教程是使用GameObject而不是Transform。

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

最终,由于您可以在两个Transform上调用许多与GameObject相同的方法,因此示例之间的区别不大。

TLDR:

使用您认为最有意义的方式。

答案 1 :(得分:0)

简短答案

您所说的GameObject更直观。

好答案

我认为(我认为)最好通过最具体,最相关的组成部分。

例如,假设您有一个角色可以捡起板条箱:

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

在我看来,传递Transform是有道理的,因为它是最需要的特定组件。通过在此处传递GameObject只会延迟不可避免的GetComponent<Transform>go.transform。 / p>

另一方面,如果您具有隐藏创建的功能,则传递游戏对象将是您实现这一目标的最低要求:

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,您将始终需要担心目标组件真正收到的是什么。您还将对无法确定对GameObjects进行某些更改的情况敞开心situations,因为它可能是系统中进行更改的任何内容。您的ColorChangerComponent实际上也可能在移动对象,破坏了其他一些组件,等等。通过为组件提供渲染器,它更自然地将组件限制为仅在渲染器上进行更改(尽管您显然会违反此限制,除非您可以针对适当的界面执行操作。

唯一有意义的事情是传递通用组件,是当您将“事件”广播给一堆可能的接收者时,每个接收者将对该对象进行不同的处理。即您不能在编译时确定游戏对象将用于什么,或者您知道它将用于许多不同的事情。

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