What is the diff between hit.collider and hit.collider.transform

What is the difference between hit.collider and hit.collider.transform?

                hit.collider.TryGetComponent<CombatTarget>(out var target);
                if(target == null) continue;

                if(Input.GetMouseButtonDown(0)) {
                    GetComponent<Fighter>().Attack(target);
                }
                hit.transform.collider.TryGetComponent<CombatTarget>(out var target);
                if(target == null) continue;

                if(Input.GetMouseButtonDown(0)) {
                    GetComponent<Fighter>().Attack(target);
                }

A lot of redirection and mystical hand waving in this case…
Let’s take a look at the RaycastHit:

using UnityEngine;

public struct RaycastHit
{
    // The impact point in world space where the ray hit the collider.
    public Vector3 point;

    // The normal vector at the impact point of the ray.
    public Vector3 normal;

    // The index of the triangle that was hit.
    public int triangleIndex;

    // The impact distance along the ray.
    public float distance;

    // The Transform of the hit collider.
    public Transform transform;

    // The Rigidbody of the hit collider.
    public Rigidbody rigidbody;

    // The Collider that was hit.
    public Collider collider;

    // The UV texture coordinate at the impact point.
    public Vector2 textureCoord;

    // The UV2 texture coordinate at the impact point.
    public Vector2 textureCoord2;

    // Unity calculates the barycentric coordinates of the triangle we hit.
    public Vector3 barycentricCoordinate;

    // The point where the ray hit the collider.
    public Vector4 lightmapCoord;
}

This struct contains a LOT of juicy information, and we often don’t use most of it. Three items, however, refer to the SAME GameObject, but just in different ways…

public Transform transform;
public Rigidbody rigidbody;
public Collider collider;

So as it turns out, all three of these items are on the same GameObject, and share the same transform, namely the first of the fields, the transform.

So the reference to hit.transform.collider is… usually the collider that was hit (not always, because you can have multiple colliders). It’s very important to note, however, that Transform.collider (and MonoBehaviour.collider) are Deprecated, meaning you shouldn’t use hit.transform.collider anyways.
For the purposes here, however, it doesn’t matter, becase we’re trying to get a CombatTarget out of the hit. This means that hit.collider.TryGetComponent is sufficient.

BTW, using TryGetComponent, we can do a little refactoring that makes this all look a little bit neater:

if(hit.collider.TryGetComponent(out CombatTarget target))
{
    if(Input.GetMouseButtonDown(0))
    {
         GetComponent<Fighter>().Attack(target);
    }
}
1 Like

Beautiful, thank you for the knowledgeable answer. That’s amazing, you reviewed the underpinnings of the library and noticed it was deprecated. Do you have the link for the deprecation. I would like to review it.

Thank you for the refactor. I adjusted the code to follow a shorter way. :sparkles::sparkling_heart:

Actually, in this case, it’s from experience…
Way back in Unity’s earlier days, they thought it would be handy if all MonoBehaviours had access to the animator, the rigidbody, the collider, etc, so they included properties for them. Later, they decided that this was inefficient, and not the best way to manage the code, so they deprecated them.

In fact, I’ve been using Unity since 2014, and they’ve been deprecated since then.

Visual Studio Code should be noting that it is obsolete with a funny squiggle under the reference, and if you hover over it, you should see a message that it is deprecated. Digging into the latest source (using JetBrains Rider to access in my case), this is what you get in the MonoBehaviour class for the declaration of collider:

    /// <summary>
    ///   <para>The Collider attached to this GameObject. (Null if there is none attached).</para>
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete("Property collider has been deprecated. Use GetComponent<Collider>() instead. (UnityUpgradable)", true)]
    public Component collider
    {
      get => throw new NotSupportedException("collider property has been deprecated");
    }

Now this is in the latest version which is 6000.0.12f1, where it’s not longer truly deprecated (deprecated normally means "ok, it will work, but just know we’re gonna change it), and instead will actually throw an exception.

Without direct access to the C# end of the source, looking for these signs in the compiler (or, supposing it actually compiled, running the program) should show you the message…

In Unity 6000, using transform.collider will not even compile, as that [Obsolete] tag prevents the compiler from linking it… If it DID somehow compile, then at runtime, you’ll get the red error message (and of course, the rest of the raytracing code will fail).

You can also always check the public API of any class… for example, here’s a link to the public API of the Transform class:

And one for the MonoBehaviour class:

If a property or method is not listed on these that you might have seen in older code, it’s likely deprecated.

2 Likes

Thank you for the links. Make sense. In VS Code, I see the deprecated message.

  • I’m running 2022.3.48f1

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms