Search Unity

having trouble with rotations

Discussion in 'Scripting' started by tone, Sep 12, 2005.

  1. tone

    tone

    Joined:
    Aug 26, 2005
    Posts:
    26
    I find that when I try to remove a GameObject from a parent object, its world transform is altered, and its localTransform relative to its lost parent is immediately applied to its relationship to the new (world) parent.

    For instance, I have a first person controller I've adapted so it adds itself as a child to anything it lands on, and I place it on a rolling ship on the water. The result, of course, is that he then walks upright on the ship (but is not necessarily upright in the world, which would induce nausea in players). However, when he hops down a flight of stairs on the ship, in between each step as he flies through the air, he flits upright in the world and this is really weird looking!

    How can I remove an object from a parent, and have its world position and rotation remain unaltered?

    thanks in advance.

    tone
     
  2. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    The world position of a transform should always be maintained when you change the parent.

    Can you outline the exact steps you take and where the world transform position is not mainted anymore?
     
  3. tone

    tone

    Joined:
    Aug 26, 2005
    Posts:
    26
    Here is my "DeckWalker" script, adapted from the stock FPS control script to cause the person to be added to the deck of his rolling ship when he collides with it:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5.  
    6. public class DeckWalker : MonoBehaviour {
    7.     public float runSpeed = 7f;
    8.     public float walkSpeed = 2f;
    9.  
    10.     public float groundDrag = 30;
    11.     public float groundDragNoMovement = 50;
    12.  
    13.     public float jumpVelocity = 3F;
    14.  
    15.     const float  airDrag = 0F;
    16.  
    17.     bool grounded = false;  /// Does the avatar have ground contact?
    18.  
    19.  
    20.     void FixedUpdate () {
    21.         if (grounded) {
    22.  
    23.             // Jump
    24.             if (Input.GetButton ("Jump")) {
    25.                 Vector3 newVelocity = rigidbody.velocity;
    26.                 newVelocity.y = jumpVelocity;
    27.                 rigidbody.velocity = newVelocity;
    28.                 rigidbody.drag = airDrag;
    29.                 transform.parent = null;
    30.             } else {       
    31.        
    32.                 float lateral  = Input.GetAxis ("Horizontal");
    33.                 float forward = Input.GetAxis ("Vertical");
    34.                 bool userMoved = Mathf.Abs (lateral) > 0.1F || Mathf.Abs (forward) > 0.1F;
    35.  
    36.                 float groundSpeed = Input.GetButton("Run") ? runSpeed : walkSpeed;
    37.  
    38.                 // Walking laterally (half the forward limit)
    39.                 float x = lateral * (groundSpeed * 0.5f);          
    40.                 float z = forward * groundSpeed;
    41.                 rigidbody.AddRelativeForce (new Vector3 (x, 0, z), ForceMode.VelocityChange);
    42.            
    43.                 if (userMoved)
    44.                     rigidbody.drag = groundDrag;
    45.                 else
    46.                     rigidbody.drag = groundDragNoMovement;
    47.             }
    48.  
    49.         } else {
    50.             rigidbody.drag = airDrag;
    51.         }
    52.     }
    53.  
    54.    
    55.     int timesOff = 0; // count times we fall off a boat
    56.     int timesOn = 0; // and times we fall ONTO a boat
    57.     void OnCollisionExit () {
    58.  
    59.         transform.parent = null;
    60.         grounded = false;      
    61.         print("left my ship, presumably " + (++timesOff)); 
    62.         }
    63.  
    64.     void OnCollisionEnter (Collision c) {
    65.         grounded = true;
    66.         transform.parent = c.transform;
    67.  
    68.         print("onboard a ship, presumably: " + c.other.gameObject.name + " " + (++timesOn));
    69.     }
    70.    
    71.     void OnCollisionStay () {
    72.     }
    73.    
    74.     void Start () {
    75.         if (rigidbody==null)
    76.             gameObject.AddComponent ("Rigidbody");
    77.  
    78.         // Don't let the physics engine rotate the character
    79.         rigidbody.freezeRotation = true;
    80.     }
    81. }
    82.  
    My scene has a simple ship with a mesh collider with an elevated foredeck and stairs to permit the player to ascend/descend between the lower deck and the upper one. A script causes the ship to roll 20 degrees with a 16 second period. When my sailor is on either deck, the effect I am trying for is achieved -- the sailor translates and orients to follow the ship's motion, and his "up" follows the ship's.

    However, when my walker jogs down the steps, I will see as many as 20 rapid alternations of being on board and being offboard (not unexpected) but as he does so, the view flickers rapidly as my player appears to be jerked upright (in world space) every time he leaves the ship, and then back so his "up" again matches the ship's canted deck every time he touches down again.

    tone

    If it helps, I could package up my project directory. Let me see how big that winds up being.
     
  4. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    When looking at your deckwalter in the sceneview.

    Does the deckwalker himself turn/move correctly?
    You can also select the camera which is a child of the fps capsule, maybe that has weird behaviour and not the capsule itself?
     
  5. tone

    tone

    Joined:
    Aug 26, 2005
    Posts:
    26
    Let me look into this -- I'd have to set a breakpoint I think as the bumping down the steps goes so blessedly fast. I'd be surprised, actually, if it were the camera, as the camera's place in the scenegraph is not being altered at all (but perhaps there is a "rotation" referenced in the MouseLook script when "localRotation" should be used)

    tone
     
  6. tone

    tone

    Joined:
    Aug 26, 2005
    Posts:
    26
    I did some print()s around the issue, but don't know how to digest the results.

    How is the best way to debug this? I truly wish you had some simpler interfaces to your transform and/or quaternion classes. I do not know know to ask an object "what is your roll angle in world space" or "what is your up vector in world space".

    tone
     
  7. tone

    tone

    Joined:
    Aug 26, 2005
    Posts:
    26
    Ok ... I found that by disabling the MouseLook script on both the body (yaw) and the camera (pitch), the right thing happens.

    However... I do not see anything wrong with the script as it is written. It only employs the localRotation

    Unsure what might be going wrong here.

    edit: No. I think I do see what's going on here.

    The transform, which was previously applicable in relation to the old parent ship, is now being applied relative to the new parent, the world. I believe that were my ship not presently at the world's origin, that I'd also see a translation when changing my parent.

    I feel this would all be more clear if I were calling methods (e.g.: setParent(), setLocalRotation()) rather than directly altering the datamembers. Since the local rotation and world rotation are related, it is not clear what happens when you directly alter one or the other data member. Will the inconsistency between the two cause your change to be discarded? Or will the change you just made cause the other rotation to change to the proper, related value?

    edit:

    a further test with the ship displaced from the world origin showed that position is managed properly when changing parents. I'll test what happens if I copy the world rotation into the localRotation value at the point where I set parent = null . Dang... still does it.


    tone
     
  8. David-Helgason

    David-Helgason

    Moderator

    Joined:
    Mar 29, 2005
    Posts:
    1,104
  9. tone

    tone

    Joined:
    Aug 26, 2005
    Posts:
    26
    Ok .. I think I have it.

    If I disable mouselook on the body, the right thing happens (I can leave mouselook on on the camera).

    The issue, I think is that Mouselook.cs's Start() contains some code that records an originalRotation and all rotations in Update() are calculated not incrementally based on how far the mouse moved since the last Update(), but always by setting a localRotation based on current mouse position.

    This means that when we change our parent from the ship to the world, our "originalRotation" is now expressed in relation to the wrong coordinate space.

    MouseLook would be more robust if it did not achieve its function in terms of rotations relative to a starting rotation, but as rotations relative to the objects current rotation. I will look into how I might do this.

    tone