Search Unity

Transform an object like a child of another object (in root)

Discussion in 'Scripting' started by Di_o, Jun 3, 2019.

  1. Di_o

    Di_o

    Joined:
    May 10, 2016
    Posts:
    62
    I'm trying to move some objects like they are a child of the main camera. Some of these objects must be root objects due to their functionality. Is there a method for that? I found that this:

    Code (CSharp):
    1.  transform.position = transform.InverseTransformPoint(camera.position);
    ... is sort of what I'm looking for, but using this in Update() makes the objects go cazy.
     
  2. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    You don't need to put that code in your update method. You need a method like

    Code (CSharp):
    1. void SetCameraRelativePosition(Camera cam, Vector3 position) {
    2. // your code goes here
    3. }
    Call this method only if you need to change the object's position. In Update() you continiously applying the transformation to previously transformed position, wich effectively creates random-looking motion.
     
  3. kritoa

    kritoa

    Joined:
    Apr 21, 2017
    Posts:
    60
    I think you just want
    Code (CSharp):
    1. transform.position = camera.transform.position
    2. transform.rotation = camera.transform.rotation
     
  4. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    This way the object won't follow camera rotation but if it's ok then this will work.
     
  5. Di_o

    Di_o

    Joined:
    May 10, 2016
    Posts:
    62
    This will set my object to the direct position of the camera. My goal is to set it to its own relativ transform of the camera. Just like a child would with its localPosition.
     
  6. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    If I'm understanding correctly, then there's no way to do what you want without storing your own Vector3 and Quaternion for the offset. You can't use localPosition and localRotation because in the root they just use the world position, and you can't just use the world positions of both objects because then your offset gets lost. Making private members for the offset is one way (to be your own personal version of localPosition and localRotation values), then when you need to change your "relative to" information, you change those private members, and your actual position and rotation are those values added to the position/rotation of the object you're following.

    If you want to be cute about it, you can create a dummy child object just to abuse its Transform component for its localPosition and localRotation values- some operations require a Transform component and can't be used directly on a Vector3 or Quaternion, so that helps.

    In other words, the parent (your root object) has a position always equal to (objectToFollow.transform.position + dummyChild.transform.localPosition), and its rotation is always equal to (objectToFollow.transform.rotation + dummyChild.transform.localRotation). You're essentially inverting the Transform control. When you need to move the root object relative to the object you're following, you actually apply the change to the dummy child instead, and then automatically update the root object too since it's still adding the child + object being followed.
     
    Last edited: Jun 3, 2019
  7. Di_o

    Di_o

    Joined:
    May 10, 2016
    Posts:
    62
    Alright, I will try that. It's still weird to me that this method "can't stay still".

    thx!
     
  8. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    It's easy to explain. Update is called every frame. In every frame you call the code which transforms object position, the object is moved every frame to new position.
     
  9. Di_o

    Di_o

    Joined:
    May 10, 2016
    Posts:
    62
    But why isn't it in the same relative position every frame?
     
  10. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    Because you modify that position every frame. It's like doing x = x + 1 every frame. Obviously it won't stay the same through every next frame.
     
  11. kritoa

    kritoa

    Joined:
    Apr 21, 2017
    Posts:
    60
    What your original code is doing is very weird. You’re finding the cameras’s position in the object’s localspace, and then setting the object’s worldspace position to that.

    Basically, pretend there’s no rotation of everything to make things easier: if your object is sitting at 10,0,0 and your camera is sitting at 10,10,-1 (so, the camera is only 1 unit away), calling the object’s inversetransformpoint method on the camera will return only the camera’s offset from the object. So that returns (0,0,-1). Then you set the object’s position to (0,0,-1), which is not anything like where you actually want it.

    It’s actually just dumb luck that it happens to work correctly the first time (on the very first frame, your object starts at the origin so the camera’s position in the object’s local space just happens to be the same as the camera’s world space position). But after that it’ll go crazy.

    One solution is either to do what Lysander suggested: make an empty gameobject that is a child of your camera and put it where you’d like your object to stick to, and then
    Code (CSharp):
    1. transform.position=emptygameobject.transform.position
    2. transform.rotation=emptygameobject.transform.rotation.
    The other solution would be to do a little vector math. So you store the “offsets” that you want your object to be offset from the camera to be - so like if you wanted the object to always be 3 units forward and 1 unit down from the camera and rotated 45 degrees left, you’d have

    Code (CSharp):
    1. Vector3 offsetPosition = new Vector3(0,-1,3);
    2. Quaternion offsetRotation = Quaternion.Euler(0,-45,0);
    And then every update you’d call:

    Code (CSharp):
    1. transform.position = camera.transform.rotation * offsetPosition + camera.transform.position;
    2. transform.rotation = camera.transform.rotation * offsetRotation;
     
    Last edited: Jun 4, 2019