- Home /
Do gameobjects pass reference by default?
Hello, i have a reference and value problem. if i were to have lines of codes like this;
int a;
int b=5;
void Start ()
{
a=b;
a=6;
//what is "b"
}
Value of variable "b" would still be 5. Which as far as i know it means variable "b" passed its value. Now i have lines of code like this;
GameObject[] patroledPoints;
void Start ()
{
patroledPoints = new GameObject[transform.childCount];
for (int i = 0; i <patroledPoints.Length ;i++ )
{
patroledPoints[i] = transform.GetChild(0).gameObject;
patroledPoints[i].transform.SetParent(transform.parent);
}
}
Now when i start the game with these lines, children of the object that this script is attached to simply stops being child of that object. The problem here is i didn't do that operations to the children of that object, i did it to patroledPoints[i]
. Which could only mean the children passed as reference to the patroledPoints[i]
. So is it safe to assume that gameobjects always pass itself as references, or the situation here is completely something else?(I am kind of new to the reference and value subject so if there are mistakes with my terminology, feel free to correct me.)
Yes, GameObject
is a so-called reference type and assignment assigns by reference, not value.
In C# all the basic types (e.g. int
, char
, float
, double
) and all the types defined by struct
(e.g. Vector3
, Color
, RaycastHit
) are value types, that is assigning to them assigns the value. The rest of the types are (e.g. string
, GameObject
, Transform
) are reference type, and assigning to them assigns the reference.
Answer by Bunny83 · Aug 08, 2018 at 11:35 AM
"Passed by Value" vs "Passed by Reference"
All variables are passed by value, always. The only exception are out and ref parameters where the variable is passed by reference. People always confuse the concept of a value type or reference type with the concept of passing a variable. Whenever you assign one variable to another you always copy it's content. Where people are confused the most is what "content" actually means.The content of a value type is just the value itself. So an int variable that contains the value 5 has the content "5" and when you assign it to another variable or pass it as parameter to a method it's value is copied.
The content of a reference type however is not the object which the reference might point to. The content is the reference itself. I know in C# we have managed references but just for the sake of argument you can imagine a reference as a pointer. So the content of a reference type variable is just the address of some memory location where the actual object is located. Now when you assign a reference type variable to another reference type variable you also will copy the content of the variable which is the memory address that is stored in the variable. Of course when you access the object that the reference is pointing to, both variables will point to the same object. However the two variables are not linked in any way.
Think about a reference like an actual address. The white house has the address "1600 Pennsylvania Ave NW, Washington, DC 20500, USA". If you store that in a variable you now have a "reference" to the white house. When you assign this variable to another one the address is copied into the other variable. Changing the address in one of the two variables will not change the address in the other variable. However if you send a rocket to that address which destroys the white house, the referenced object has been "changed". So everybody who uses their reference to the white house will see those changes.
ref and out parameters are actually implemented as pointers onto variables. ref and out only applies to parameters of methods. You can't "store" a pointer to another variable into a variable. At least not in safe managed code. When i said to a variable i mean to the location in memory where the variable content is stored and not the object the reference might be pointing to.
To the actual issue here
edit
So since we basically worked out that our variable content is actually passed by value we will have a look at your code.
GameObjects are objects which live on the heap. Objects are reference types. So a variable of type GameObject actually stores a reference to an actual gameobject somewhere on the heap. The "gameobject" object itself is not stored in the variable. The variable only holds a reference to the actual object. So of course when you store the references to all the child objects in an array and then use those references to manipulate the objects you always manipulate the actual object.
If you actually want a copy of the child gameobjects you have to use Instantiate to create a clone.
Note that your for loop only works because you change the parent of each child object. Otherwise you would always access only the first child of the gameobject. Since you change the parent the object disappears from the child list of our object and therefore the index 0 will now reference the next child
This line of code along with the one below it is supposed get the child out of its parent. And that's what i thought at first, i put "i" there. But notice that each time i get a child out, the "second" child becomes the "first" child. Hence the "0". Code works just as i wanted it to be i don't know why you thought it wouldn't work.
It's a bit difficult to understand what holistic1 wanted to do with that code, and it does smell, but it makes sense once you notice that patroledPoints[i].transform.SetParent()
removes a child of transform
, so child 1 becomes child 0 and so on.
A easier to understand way of writing it would be:
private List<Transform> patroledPoints = new List<Transform>();
private void Start () {
List<Transform> patroledPoints = new List<Transform>();
while (transform.childCount > 0) {
Transform child = transform.GetChild(0);
child.SetParent(transform.parent); // parent child to its grandparent
patroledPoints.Add(child);
}
}
Ahh I just realised that you use "transform.parent" as new parent. I first thought you just set the same parent as it already was ^^. Of course when you run that code you actually change the parent of all your childs to be a child of the parent of the object you have this script attached to. This is what happens:
Though this has nothing to do with passing variables by reference or value. A GameObject or Transform are objects and therefore reference types. When you pass around references to objects you never will create copies or clones of the objects. Clones has be be created explicitly with Instantiate.
Though we don't know what behaviour you want to achieve or what behaviour you would expect. Anyways I'll edit the end of my answer.
I just read your edit. You are right about "Note that your for loop only works because you change the parent of each child object.". But whole point of that "for" loop is just that. To get the childs out of that parent(If there is any).
ps: If you're still not sure about the difference between the type of a variable (value type / reference type) and the concept of passing variables by value / by reference, I've written an even more detailed answer over here
Yes, i actually read that a few times before posting this question. Very helpful.