Search Unity

How to rotate an object around the same global axe even when parent rotation is changed

Discussion in 'Scripting' started by Aladine, Mar 21, 2015.

  1. Aladine

    Aladine

    Joined:
    Jul 31, 2013
    Posts:
    195
    Hello,

    I want to have a cube that rotate like the one in this game, and am kinda lost here...

    so the way i tried to solve the problem is like this :
    Make the cube a child of an empty game object,

    then the left key will rotate the cube 90 degrees around its x axes :



    And the right key will rotate the parent 90 degrees around its Z axes :



    Now the problem start to happen, because after rotating the parent, the child axes get rotated too, so if rotate it again along the X axes it will give me the wrong result like this :


    And the weird part is that even when i try to rotate it around the Y axes it doesn't give me the result am looking for :



    So i really hope someone could put me in the right direction here.

    finally here is the class am using to do all this and a web build to better understand the problem :

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class RotateCube : MonoBehaviour
    5. {
    6.     public  float speed;
    7.     public Vector3  targetEul, parentTargetEul;
    8.     private Transform myTrans;
    9.     public bool canRotate, doLeft, doRight;
    10.  
    11.    
    12.     void Start ()
    13.     {
    14.        
    15.         myTrans = transform;
    16.         targetEul = myTrans.rotation.eulerAngles;
    17.        
    18.         //get parent angle
    19.         parentTargetEul = myTrans.parent.rotation.eulerAngles;
    20.  
    21.         print (Vector3.right);
    22.         print (transform.right);
    23.  
    24.     }
    25.    
    26.     void Update ()
    27.     {
    28.  
    29.         //check input when possible
    30.         if (canRotate) {
    31.             checkInput ();
    32.         }
    33.  
    34.         //rotate child
    35.         if (doLeft) {
    36.             checkQuat ();
    37.         }
    38.  
    39.         //rotate parent
    40.         if (doRight) {
    41.             checkQuatParent ();
    42.         }
    43.     }
    44.  
    45.     //rotate child
    46.     float chrono;
    47.     void checkQuat ()
    48.     {
    49.        
    50.         if (chrono > 0) {
    51.             chrono -= speed * Time.deltaTime;
    52.             myTrans.localRotation *= Quaternion.Euler (Vector3.right * speed * Time.deltaTime);
    53.         } else {
    54.             myTrans.localRotation = Quaternion.Euler (targetEul);
    55.             canRotate = true;
    56.             doLeft = false;
    57.         }
    58.        
    59.     }
    60.  
    61.     //rotate parent
    62.     float chronoP;
    63.     void checkQuatParent ()
    64.     {
    65.         if (chronoP > 0) {
    66.             chronoP -= speed * Time.deltaTime;
    67.             myTrans.parent.rotation *= Quaternion.Euler (Vector3.forward * speed * Time.deltaTime);
    68.         } else {
    69.             myTrans.parent.rotation = Quaternion.Euler (parentTargetEul);
    70.             canRotate = true;
    71.             doRight = false;
    72.            
    73.         }
    74.  
    75.     }
    76.  
    77.     //check input
    78.     void checkInput ()
    79.     {
    80.         if (Input.GetKeyDown (KeyCode.LeftArrow)) {
    81.             targetEul = myTrans.localEulerAngles;
    82.             targetEul.x += 90;
    83.             chrono = 90;
    84.             canRotate = false;
    85.             doLeft = true;
    86.  
    87.         }
    88.        
    89.         if (Input.GetKeyDown (KeyCode.RightArrow)) {
    90.             parentTargetEul = myTrans.parent.rotation.eulerAngles;
    91.             parentTargetEul.z += 90;
    92.             chronoP = 90;
    93.             canRotate = false;
    94.             doRight = true;
    95.         }
    96.     }
    97.    
    98. }
    99.  

    Thank you very much and have a great day
     
  2. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,089
    Aladine likes this.
  3. Aladine

    Aladine

    Joined:
    Jul 31, 2013
    Posts:
    195
    Thanks for the help :)

    So if i use the Transform.Rotate() i won't need to setup my object like this (parent/child) ?
    because at the moment i replace the old line (commented) with the new one using transform.rotate() :
    Code (CSharp):
    1. //myTrans.localRotation *= Quaternion.Euler (Vector3.right * speed * Time.deltaTime);
    2.             myTrans.Rotate (transform.up, speed * Time.deltaTime, Space.World);
    but it still give me the same result when i rotate the parent.


    EDIT:
    okay so this seems to get it working :
    Code (CSharp):
    1. //rotate around X
    2. transform.Rotate (speed * Time.deltaTime, 0, 0, Space.World);
    3.  
    4. //rotate around Z
    5. transform.Rotate (0, 0, speed * Time.deltaTime, Space.World);
    One last problem though, in this section i save the target euler angle:
    Code (CSharp):
    1.  
    2. if (Input.GetKeyDown (KeyCode.LeftArrow)) {
    3.             targetEul = transform.eulerAngles;
    4.             targetEul.x += 90;
    5.    }
    6. //when the interpolation is done, apply it to the object to avoid any "rotation noise"
    7. transform.rotation = Quaternion.Euler (targetEul);
    8.        
    Thank you

    for some reason it gave me a wrong result. any idea why ?
     
    Last edited: Mar 21, 2015
  4. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,089
    I'm not too sure really, I'd probably need to try it myself to see. Once you've rotated it in world space the euler results probably won't make much sense anymore though so I would avoid using them if possible. Might be better to just keep your own value that goes from 0 to 90 each time you do a rotation. If you're rotating from it's current angle it shouldn't really matter if you know what the last rotation was.

    I suppose over a period of time the rotation could get a bit out of sync though!
     
  5. Aladine

    Aladine

    Joined:
    Jul 31, 2013
    Posts:
    195
    Exactly! that's why i want to keep track of the target rotation to set the object rotation back to it once the cycle is done.
    do you have any suggestion to do that please ?

    For example, say you want to rotate an object a 90 degrees around the x axes.
    what will its rotation would be equal to after you apply the 90 degree ?

    in other word, if x = 5; and i want to add 90 to it, the the final x will be 95, and the general form of this will always be "FinalX =x+90"
    Can i do that with Quaternion to know exactly what's my rotation will equal too after executing this line an x-time ?
    Code (CSharp):
    1. transform.Rotate (speed * Time.deltaTime, 0, 0, Space.World);
     
  6. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,089
    There's a lot of chat here (http://away3d.com/forum/viewthread/4248/) about a similar issue but it seems quite complicated.

    A quick and dirty solution would be to just record all the player's actions in a list. Each time they wanted a rotation (x or z) you can just store that. When you want to get the current rotation just start off with an unrotated object and apply each rotation in the list again in order.

    e.g.

    Unrotated object
    Rotate x -90 in world
    Rotate z +90 in world
    Rotate z +90 in world
     
  7. Aladine

    Aladine

    Joined:
    Jul 31, 2013
    Posts:
    195
    Really :p ?

    So for example say am working with just a float that i want to increase in time to reach 10.00, if i do this :

    Code (CSharp):
    1. if  (x<10){
    2.     x+=Time.deltaTime;
    3. }
    Then the final result of x won't be exactly 10.00, it would be something a little bit more. and so i need to make it like this :
    Code (CSharp):
    1. if(x<10){
    2.    x+=Time.deltaTime;
    3. } else{
    4.    x=10;
    5. }
    That is exactly what i am trying to make but instead of X i want the object rotation, and instead of 10 i want the previous object rotation+90 on X or Z

    Is it really "impossible" to do in that simple way?
     
  8. tonemcbride

    tonemcbride

    Joined:
    Sep 7, 2010
    Posts:
    1,089
    Ah, ok - sorry, I got confused by what you meant.

    The easiest solution would be to grab the rotation matrix before you start rotating - that way you can just rotate it by a value that you hold yourself.

    e.g.
    Before rotating:

    Quaternion currentQuat = myObject.transform.rotation;
    float CurrentXRot = 0.0f;

    each update you can do:

    CurrentXRot += Time.deltaTime;
    if( CurrentXRot > 90.0f )
    {
    CurrentXRot = 90.0f;
    // Finished rotating here
    }

    // Copy start rotation into transform
    myObject.transform.rotation = currentQuat;

    // Rotate by the current amount
    myObject.transform.Rotate ( CurrentXRot, 0, 0, Space.World);