Search Unity

Using Transform.Rotate()

Discussion in 'Scripting' started by tsphillips, Jan 17, 2006.

  1. tsphillips

    tsphillips

    Joined:
    Jan 9, 2006
    Posts:
    359
    Transform.Rotate() seems to be doing "extra" rotations, and I'm not sure why.

    Consider the following code, which is attached to a flattened cube (like a plane, though I will call it a board). It allows the user to tilt the board using the arrow keys. The tilt is constrained, though, so flipping the board is impossible.

    Code (csharp):
    1.  
    2. var tilt_rate = 100.0;
    3.  
    4. function FixedUpdate () {
    5.  
    6.     if (Input.GetKey("left")
    7.             (transform.localEulerAngles.x > 350 || transform.localEulerAngles.x < 15) ) {
    8.         transform.Rotate(Vector3.left * Time.deltaTime * tilt_rate);
    9.     } // if right
    10.  
    11.     if (Input.GetKey("right")
    12.             (transform.localEulerAngles.x > 345 || transform.localEulerAngles.x < 10) ) {
    13.         transform.Rotate(Vector3.right * Time.deltaTime * tilt_rate);
    14.     } // if right
    15.  
    16.     if (Input.GetKey("down")
    17.             (transform.localEulerAngles.z > 350 || transform.localEulerAngles.z < 15) ) {
    18.         transform.Rotate(Vector3.back * Time.deltaTime * tilt_rate);
    19.     } // if right
    20.  
    21.     if (Input.GetKey("up")
    22.             (transform.localEulerAngles.z > 345 || transform.localEulerAngles.z < 10) ) {
    23.         transform.Rotate(Vector3.forward * Time.deltaTime * tilt_rate);
    24.     } // if right
    25.  
    26.     if (Input.GetKey("space")) {
    27.         transform.localRotation = Quaternion.identity;
    28.     } // if space
    29.  
    30. } // FixedUpdate()
    31.  
    If the direction keys are continuously pressed in rotational order (up, right, down, left, up, right, etc.) then the board will rotate through the Y axis. Visually this looks like the board rotating around on a lazy Susan, or having the camera rotate around the board.

    Does anyone know why this Y axis drift is occuring, and what I can do to prevent it?

    Tom
     
  2. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    Be very careful about using euler angles. Changing one can easily change the other.

    I recommend using a transform's forward vector to determine stuff about where it's facing rather than euler angles.
     
  3. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Can't see exactly where your rotations go wrong, but some suggestions to make the whole script a lot simpler

    1. store x and y rotation as a float
    Code (csharp):
    1.  
    2. var x = 0.0;
    3. var y = 0.0;
    4.  
    2. Every frame, add x and y by Input.GetAxis("Horizontal") / Input.GetAxis("Vertical").
    Code (csharp):
    1.  
    2. x += Input.GetAxis("Horizontal") * Time.deltaTime * speed;
    3.  
    3. Then clamp x and y using Mathf.Clamp
    4. Apply the rotation using
    Code (csharp):
    1.  
    2. transform.rotation = Quaternion.identity;
    3. transform.Rotate(x, 0, y);
    4.  
     
  4. tsphillips

    tsphillips

    Joined:
    Jan 9, 2006
    Posts:
    359
    I'm careful not to modify the Euler angles (here) -- just wanted to know the rotation relative to the parent. I did see the forward vector code in the physics demo (making the car untopple itself), but didn't quite follow how that was working. (I didn't know how to interpret "transform.rotation * Vector3.fwd". A 1x4 vector times a 1x3 vector? But then, my matrix algebra is almost 20 years old...)

    To solve the Y axis rotation problem I ended up fixing the Y rotation at the end of the script.
    Code (csharp):
    1.  
    2. transform.localEulerAngles.y = 0;
    3.  
    (Okay, it's fixing an Euler angle, but it looks safe. :wink: )

    The GetAxis() example certainly looks more straightfoward. Are scripts atomic? That is, is there any chance a script could be interrupted between these two lines?

    Code (csharp):
    1.  
    2. transform.rotation = Quaternion.identity;
    3. transform.Rotate(x, 0, y);
    4.  
    Tom
     
  5. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Unity will never interrupt a script function execution on it's own.

    But you can tell unity to pause execution using coroutines. Coroutines are a great concept. They can simplify code a lot when you have to deal with behaviours/events over time. Which games happen to do a lot.

    http://www.otee.dk/Documentation/ScriptReference/index.html#The Yield Statement
     
  6. NCarter

    NCarter

    Joined:
    Sep 3, 2005
    Posts:
    686
    That's a quaternion 'multiplied' by a vector, which is the usual notation for "rotate this vector by this quaternion". So, for example:

    Code (csharp):
    1. localForwardVector = transform.rotation * Vector3.forward;
    Quaternions are essentially 4D vectors, but you may as well ignore that detail, and just concentrate on thinking of them as rotations which can be used to rotate vectors and objects.
     
  7. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    I've just been informed by Joe that our Lerps all clamp between 0 and 1. Hence you don't need to worry about the last step.
     
  8. tsphillips

    tsphillips

    Joined:
    Jan 9, 2006
    Posts:
    359