- Home /
The question is answered, right answer was accepted
Why won’t GetComponent ().rotation.SetLookRotation actually change the object’s rotation?
I have some code to modify an object’s rotation transform in the update statement, but I’m not getting the results I expected … This code snipped, run in Update(), works fine and rotates the object as expected:
Transform t = GetComponent<Transform> ();
Quaternion q = new Quaternion ();
q.SetLookRotation(lookat,new Vector3 (0, 1, 0));
t.rotation = q;
This code does NOT rotate the object. Why the heck not?
GetComponent<Transform> ().rotation.SetLookRotation(lookat,new Vector3 (0, 1, 0));
Note: lookat is a Vector3 variable setup earlier in the code: setup not relevant, I think, because I pass the same values to both versions of the code. (Debug.Log tests confirmed this)
I suspect I’m missing something simple and obvious here, but I’m still stumped.
Just transform is a shortcut for GetComponent transform(). Other common components have similar shortcuts. LookAt is also a shortcut. transform.LookAt(lookat); does the same as both examples.
But, even though most people would never write it that way, your 2nd example should work. Does it fail in a script by itself?
I'm not sure I understand your first paragraph..
Yes, it does fail in a script by itself. this fails to rotate the object
void Update () {
GetComponent<Transform> ().rotation.SetLookRotation(new Vector3 (1, 0, 1),new Vector3 (0, 1, 0));
}
this DOES rotate the object
void Update () {
Quaternion q = new Quaternion ();
q.SetLookRotation(new Vector3 (1, 0, 1),new Vector3 (0, 1, 0));
GetComponent<Transform> ().rotation = q;
}
He means that there is an in-built reference to transform, so you do not have to call it manually, i.e.
gameObject.transform.rotation.SetLookRotation(new Vector3(1,0, 1), new Vector3 (0, 1, 0));
Having this by itself and with gameObject, ins$$anonymous$$d of GameObject (case sensitive), will access the transform component of the object the script is attached to. Likewise, if you wanted to get the transform of another object, you would put your reference to that object in place of gameObject.
oh my, that's very useful! Alas: these also fails to rotate the object
gameObject.transform.rotation.SetLookRotation(new Vector3 (1, 0, 1),new Vector3 (0, 1, 0));
and
transform.rotation.SetLookRotation(new Vector3 (1, 0, 1),new Vector3 (0, 1, 0));
this DOES (notice: I'm not even creating a new instance of a quaternion here, just using a local variable for no reason I can see)!
Quaternion q = transform.rotation;
q.SetLookRotation(new Vector3 (1, 0, 1),new Vector3 (0, 1, 0));
transform.rotation = q;
There's also no reason to use SetLookRotation. Using transform.LookAt will run it for you, using your rotation (see the docs.)
SetLookRotation is for those rare cases when you are doing math on just naked quaterions.
Also don't need to use new Vector3(0,1,0) as the 2nd input. Vector3.up is a shortcut. But, Up is the default anyway, so don't even need a 2nd input (you rarely need a rotation vector which isn't "head up.")
Answer by Owen-Reynolds · Jan 02, 2015 at 01:43 AM
I think your not-working examples are really compile errors, which the compiler should be flagging, but isn't. The same sort of error as transform.position.x=5;. What compiler are you using?
rotation is a struct and transform.rotation is probably a set/get. That means you can change the entire thing using set, or play with a copy through get. I assume the compiler didn't notice that SetLookRotation is changing itself, so didn't flag anything. It just (incorrectly) said "here's your rotation copy, have fun."
Why doesn't C# allow references to structs, like C++? I assume it would break garbage collection. Likewise, C# doesn't have a const for member funcs, which might allow it to catch this easier.
Oh, so the object.transform.rotation is only returning a copy to the transform, not a reference to the transform? I didn't expect that, in c# I though everything, except base types, is supposed to be a reference. Is that the case with all "get" accessors?
I'm a bit confused though: How would the compiler know if the SetLookRotation() function is going to modify itself?
How am I as a programmer supposed to know if a variable I'm trying to use comes from a get accessor, and I only have a copy? Check the docs each time? This makes me think your right, the compiler SHOULD be at least warning me here.
I'm using monoDevelop that came with Unity.
Structs in C# are never references. Classes always are. Just because. Some C# programmers say they avoid structs, just to avoid non-referenced non-primatives. I assume Unity uses structs for speed.
The issue is only when "reaching through" a getter to a modify a struct. Again, same problem as transform.position.x=5;.
But, most people use the Unity shortcuts and never have to worry about this. You may be the only person to ever use SetLookRotation through a transform. Come to think of it, I only use LookRotation, which is the value-returning version.
The issue is only when "reaching through" a getter to a modify a struct
Since the get is transparent to a caller, how do I know if what I'm using IS or IS-NOT safe to modify? $$anonymous$$anually check the definition, in code, or library, to see if the variable I'm using is indeed a getter (though auto fill DOES help with this part), and further deter$$anonymous$$e if the return value is a Sruct or class? Fix my compiler?
Thanks for the terrific explanations and help Owen!
Edit: Ran tests using visual studio- while directly modifying a "gotten" struct value with an "=" WILL generate an error, calling a member function on the "gotten" value will not. It seems to me, like the compiler would need some kind of keyword to $$anonymous$$NOW weather or not a struct's particular member function actually modifies it's values, or not, in order to be able to generate a compiler error here. They obviously thought about this when designing c#, so why no modifier/keyword?
struct someStruct {
public float f;
/*keyword $$anonymous$$ODIFIER*/ public void SetF(float param){f=param;}
public void OutputDebugInfo(float another_number) {Debug.output(f+another_number);}
}
class hasAccessor$$anonymous$$ember {
private someStruct a;
public someStruct A {
get
{return a;}
set
{a=value;}
}
}
class test{
void main(){
hasAccessor$$anonymous$$ember has= new hasAccessor$$anonymous$$ember();
has.A.f = 6.0f; //compiler error on this line Cannot modify the return value of 'hasAccessor$$anonymous$$ember.A' because it is no a variable
has.A.SetF(6.0f); // no error generated- but there should be because modification is done
has.A.OutputDebugInfo(12.0f); // no error generated- nor SHOULD there be
}
}
I think this is just a defect in C#, and kind of a bad one. This is the same problem: http://blogs.msdn.com/b/colinth/archive/2007/05/14/c-for-c-users-structs-vs-classes.aspx not being caught by the compiler.
But, in practice, I think this is rare in Unity. I've never seen it before this. Your very 1st example "pull out, modify, put back" is often more natural, since $$anonymous$$odify may be several steps.
Follow this Question
Related Questions
I can't update my speed after reaching certain score 1 Answer
Accessing a GameObject from another script 1 Answer
How to get all children gameobjects 5 Answers
Raycast to Disable Script 0 Answers