[Solved] GameObject aaGameObj = bbGameObj doesn't copy, but refer/point?

I want to copy a GameObject into a separate GameObject in order to keep track of it’s transform/position.
Basically

  • GameObject oldObj = GameObject currentObj;

and then compare

  • if (oldObj.transform.position == currentObj.transform.position) { //do sth }

and see whether it moved (you can move currentObj around).

However it appears as though oldObj isn’t a copy, but merely a pointer/reference, hence they are always the same position and you never detect any change.

My current workaround is to pull out the transform into separate variables:

  • Vector3 oldPos = currentObj.transform.position;

  • Quaternion oldRota = currentObj.transform.rotation;

  • Vector3 oldScale = currentObj.transform.localScale;

So my question is basically whether there is a specific reason that “=” doesn’t copy GameObjects, but points instead? I assume there must be some sort of GameObject.clone/copy, but is it very inefficient to do compared to my current workaround? (Speed/Performance is very important due to device limitations)

That’s how C# works.

For reference types (all objects - eg. things defined as a class), variables are pointers. If you do a = b for a pointer, you copy the pointer, so now b is pointing at the same object.

For value types (numbers like int, float, structs like Vector3, Quaternion), you get a copy of the value.

To illustrate, call this with a Transform and Vector3:

using UnityEngine;
using UnityEngine.Assertions;

public static class Test
{

    public static void Foo(Transform t, Vector3 v)
    {
        /*
         * copies the value of the variable v into vCopy. Since Vector3 is a struct, the variable is just the struct,
         * so changing vCopy will not change v.
         */
        var vCopy = v;  
        /*
         * Copies the value of the variable t into tRef. Since Transform is a class, the variable is a pointer to the
         * object, so tCopy points to the same object as t.
         */
        var tCopy = t;
        
        t.position = Vector3.zero;
        tCopy.position = Vector3.right;
        
        //They have the same position!
        Assert.AreEqual(Vector3.right, t.position);
        //ReferenceEquals means that they reference the same object!
        Assert.IsTrue(object.ReferenceEquals(t, tCopy));

        v.x = 5;
        vCopy.x = 10;
        
        //They are different values!
        Assert.AreEqual(5, v.x);
        
        
        //Note that all of this is why you can't do this:
        //t.position.x = 15; //WONT COMPILE!
        
        /* 
         * t.position returns a copy of t's position, so changing the x-value of that would do nothing. The compiler's guarding you against writing a line of
         * code that doesn't do anything.
         * If you do it over 2 lines, it's more obvious that it won't work: 
         */
        t.position = Vector3.zero;
        var pos = t.position;
        pos.x = 15;
        
        //t's position didn't change from changing the pos variable 
        Assert.AreEqual(t.position.x, 0);
        
        //For objects, though, you can do this:
        var rigidbody = t.GetComponent<Rigidbody>();
        rigidbody.velocity = Vector3.right;

        //Works since Rigidbody is an object, not a struct
        Assert.AreEqual(Vector3.right, t.GetComponent<Rigidbody>().velocity);
    }
}
1 Like

Thanks, that explains a lot!

I take it that therefore merely maintaining a copy of the positions must be way more efficient than keeping a separate copy of the entire class.