1

I want to create a Vector3 type object referring to my player's position so that I can use a shorter name in my script.But I failed to do it. It seems that the new object pointing at other address.

I wrote some code like this:

//PlayerController.cs
vector3 playerPos = transform.position;
Debug.Log(System.Object.ReferenceEquals(playerPos,transform.position)); 

The output was

false

What caused this and how can I refer to my player's position correctly?

Programmer
  • 121,791
  • 22
  • 236
  • 328

1 Answers1

5

What caused this

Below is a simple explanation.

transform.position is Vector3.

Vector3 is a struct.

Struct is a value type.

It's always good look in the Unity's Documentation to see which type Unity API is. This really matter when working in Unity.

enter image description here

When you do:

vector3 playerPos = transform.position;

New struct is created and values from transform.position; is copied to playerPos variable. Since the variable is value type and copied, performing System.Object.ReferenceEquals on it should return false.


I want to create a vector3-type object referring to my player's position so that I can use a shorter

In this case, you have to change the Vector3 to Transform.

Transform myPos = null;
void Start()
{
    myPos = transform;
}

then you can do:

myPos.position = newPos; 

The reason you have to declare the position as Transform instead of Vector3 is because Transform is a class and a class stores the reference of the object.

class is a reference type.

enter image description here

Debug.Log(System.Object.ReferenceEquals(myPos, transform)); should return true because myPos and transform are both classes and the myPos variable is referencing the transform variable.

So, whenever you access your position with myPos.position;, it will give you the newest position of your GameObject which is also (transform.position) since the myPos variable is a class that has a reference of transform which is also a class.

Assuming that myPos is struct or declared as vector3 myPos instead of Transform myPos, then the myPos variable would hold the copy value of transform.position when it was assigned and will never return the latest position of your GameObject since it is a copy.

You can learn more about class vs struct here.

Finally System.Object.ReferenceEquals says "ReferenceEquals" not "ValueEquals" so this is even self-explanatory. You use it on a class/referece types not on structs or value types.

Community
  • 1
  • 1
Programmer
  • 121,791
  • 22
  • 236
  • 328
  • Does this mean that in the case of Vector3 structs and transform class in Unity, the `==` is overridden by `Equals` and not the default `ReferenceEquals`? Since if we use `playerPos == transform.position` Unity returns `true`. – Galandil Mar 04 '17 at 19:06
  • A struct is not a reference type. It's values are accessed directly. Therefore, when you compare a Vector3 with a Vector3, you are comparing value types, (Equals), not their reference types (ReferenceEquals). – Michael Curtiss Mar 04 '17 at 19:20
  • @Galandil `ReferenceEquals` compares the reference. `playerPos == transform.position` compares the value of the `Vector3` such as x, y, and z, values which are all `floats`. – Programmer Mar 04 '17 at 19:35
  • Sorry, I explained myself poorly. My question is this: by default, `==` makes a reference comparison by using `ReferenceEquals`. So, when we compare two objects with `==`, and at least one of them is a value type, we override to `Equals` instead of `ReferenceEquals`, right? – Galandil Mar 04 '17 at 19:35
  • @Galandil *"by default, == makes a reference comparison"* Not really. It depends on the API. For `Vector3`, Unity has an [overload](https://docs.unity3d.com/ScriptReference/Vector3-operator_eq.html) of `==` that compares the `SqrMagnitude` of both Vectors. It does not compare the reference of a `Vector3` with ==. On the other hand, you are right. You can override the `Equals` function but you should't override `ReferenceEquals` for Vector3 since it is a struct. – Programmer Mar 04 '17 at 19:39
  • By default, I meant the C# default: https://msdn.microsoft.com/en-us/library/ms173147(v=vs.90).aspx - apparently, and unless I didn't understand correctly the link, they clearly say that by default `==` checks for reference equality (it's written just after the 3rd code window), so to explain the behaviour described in my first comment I thought that if one of the objects compared is a value type, the `==` is automatically overridden to check for value equality instead of reference. – Galandil Mar 04 '17 at 19:46
  • I really don't know but that's likely what's happening. You can drop this comment under [Jon Skeets](http://stackoverflow.com/a/7345997/3785314)'s answer and see if he replies. He knows a lot about those things. – Programmer Mar 05 '17 at 01:55
  • There is no default == operator for struct, you have to provide one or you cannot use ==. So yes, you have reference comparison for classes instead overriden and you have error for structs unless overriden. Since the compiler cannot compare addresses with struct, it does not know what should be the way to compare struct. So instead of performing something wrong or assuming a proper implementation (like grabbing all public members and performing bitwise comparison which is the basic way), it leaves it to you to explicitly create the method. – Everts Mar 05 '17 at 06:50
  • @Everts That makes sense. Thanks for that. – Programmer Mar 05 '17 at 08:05