0
\$\begingroup\$

Apparently gameObject.transform.eulerAngles is accessing a copy, so changing it shouldn't do anything, and in fact using .Set doesn't work. But why does =new Vector3 (..) work?

EDIT: Given the answers - I think I should update the question. What seems inconsistent to me, is the fact that "new Vector3" works as a setter the way I would want it to, but not using "new" and .Set doesn't. It doesn't seem very intuitive that "new" is understood as "ah, he's trying to set this property of a property" that way want - the choice of word doesn't seem very intuitive at least.

I suppose it makes sense in the ".Set" case - you might want to intentionally use the .Set of the Vector3 returned. Essentially, it might be useful to interpret A.B.Set as (A.B).Set, as this is the "natural" way to interpret it, as opposed to some other "ordering" (which could symbolically be expressed as A.(SetB) or something like that).

But in the other case - I don't know why omitting "new" doesn't work. It would seem like a natural choice to interpret (A.B.C)= as "he wants to set the property" - what else could be intended by this? I can't think of a reason why someone would want it to do something else than what happens when you add "new" - i.e. assuming that A.B gives you the copy of the property B of A, and assuming it's not some sort of simple object like a Vector3, why would you want to set this copy of the property to something? In what scenario could that be a useful, efficient way of doing something?

But thinking about it again, I suppose the reason might be the same as with .Set -the code A.B.C= is simply understood as ((A.B).C)=, because that's the most natural, basic way to interpret it, is that right?

\$\endgroup\$
1
  • \$\begingroup\$ Remember the adage, "Whenever you think you are facing a contradiction, check your premises. You will find that one of them is wrong." Here, your assumption is that because reading transdorm.eulerAngles returns a copy, therefore writing to it must also write to a copy. But that's not required by how C# properties work; in fact it would be unusual API design to expose a setter method that can never change the underlying state (in most such cases it would be clearer to not expose a setter) \$\endgroup\$
    – DMGregory
    Commented Mar 26, 2019 at 11:04

4 Answers 4

2
\$\begingroup\$

'All of what I write here is an assumption, based on the API. Take it with a grain of salt.

I assume that eulerAngles is a property that encapsulates more than basic setter logic. Essentially, assume that

foo.eulerAngles = new Vector3(x, y, z);

is translated by the compiler into a method

foo.setEulerAngles(new Vector3(x, y, z));

now, assuming there's some internal state of the transform from which the eulerAngles' property is derived - I assume it's the 'rotation' quaternion. Then the setEulerAngles method rotates 'rotation' using quaternion mathematics, by converting the given vector to a quaternion.

By the same logic, the getter 'eulerAngles' is compiled to

public Vector3 getEulerAngles() {
  return rotation.eulerAngles;
}
\$\endgroup\$
2
\$\begingroup\$

As @DMGregory points out in a comment, you seem to assume a premise that if getting from gameObject.transform.eulerAngles accesses and returns a copy, then writting to it must write to a copy, in which case there would be no meaningful changes being done to the root data.

Both parts of that premise are wrong. Despite breaking the naming convention most people use in C#, eulerAngles is a property, not a variable. And in C#, properties, including ones made to act as getters and setters, can implement completely independent logic.


Specifically, in this case, the property returns a copy in reading/getting inherently, as it is just a proxy to the underlying Transform.rotation, which is a Quaternion, not a Vector3. Therefore a new Vector3 is returned simply as part of the process of conversion.

And for writing, the same proxy happens in reverse. The property converts the given Vector3 representing euler angles to a Quaternion, using Quaternion.Euler(Vector3), and then writes the result to Transform.rotation:

public Vector3 eulerAngles { get { return rotation.eulerAngles; } set { rotation = Quaternion.Euler(value); } }

From the official Unity source-code reference

\$\endgroup\$
1
\$\begingroup\$

The other answers are correct, it's a property that returns a copy when you get it, but when you set it, converts the value to a quaternion.

I believe this is the right part of the reference source:

        public Vector3 eulerAngles { get { return rotation.eulerAngles; } set { rotation = Quaternion.Euler(value); } }
\$\endgroup\$
0
\$\begingroup\$

Good question! I would guess youre accessing not a copy, but a prop with its setter routing to the real value stored inside a database withing unity.

Vector3.Set would indeed just set the value of the local prop this way, while

= new Vec3(..) would make use of the setter of the prop (wich implementation details i couldnt find)

Edit:

I think so because ive heard that unity's implementation relies on an entityComponentSystem and inside the metaData of unity's Transform comopnent we can see that eulerAngles is an undefined prop and Set(x, y, z) a delegate/action or something, maybe to obscure the implementation

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .