SetParent and Rigidbody.position setting Error

I found this weird functionality where you can’t reliably set the position and parent of a Rigidbody GameObject within the same frame.

Here is a minimal script that recreates the complication by setting the position and parent a Rigidbody cube to either trans1’s or trans2’s position. Unfortunately, I’ve tried putting this logic within FixedUpdate, but that had no effect as well.

Here is the script

using UnityEngine;

public class TestRunner : MonoBehaviour
{
    [SerializeField] Transform trans1;
    [SerializeField] Transform trans2;

    private void Update()
    {
        if (!Input.GetKeyDown(KeyCode.Space)) return;

        if (transform.position.x < 0)
        {
            transform.SetParent(trans1);
            transform.GetComponent<Rigidbody>().position = trans1.position;
        }
        else
        {
            transform.SetParent(trans2);
            transform.GetComponent<Rigidbody>().position = trans2.position;
        }
    }
}

Alright well I found that if I moved the teleportation to FixedUpdate or, if called in Update, changed the Rigidbody’s interpolation to None, I got the desired result. I’m still shocked that this is the only way to correctly change the parent and position of a Rigidbody GameObject in a given frame and that I am unable to call transform.GetComponent().position = position. I’ll leave this thread as unresolved for a little longer so that maybe someone can find the flaw in my workflow or a better/more correct solution.

Attached is the updated script.

here is the updated script

using UnityEngine;

public class TestRunner1 : MonoBehaviour
{
    [SerializeField] Transform trans1;
    [SerializeField] Transform trans2;

    private bool hasRequest;

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            hasRequest = true;
        }
    }

    private void FixedUpdate()
    {
        if (!hasRequest) return;
        hasRequest = false;

        if (transform.position.x < 0)
        {
            transform.SetParent(trans1);
            TeleportTo(trans1.position);
        }
        else
        {
            transform.SetParent(trans2);
            TeleportTo(trans2.position);
        }
    }

    private void TeleportTo(Vector3 position)
    {
        // WORKS if called in FixedUpdate or if no interpolation and called in Update
        transform.position = position;

        // FAILS if called in FixedUpdate (also fails in Update(), but this makes sense)
        // transform.GetComponent<Rigidbody>().position = position;
    }
}

Try setting the position of both the rigidbody the transform:

transform.SetParent(trans2);
transform.position = trans2.position;
trasnform.GetComponent<Rigidbody>().position = trans2.position;

The rigidbody is the authoring position and rotation for the transform. However, it’s “physics” position is updated in FixedUpdate. Therefore, the transform may be updated immediately or not depending on when the physics simulation happens and the interpolation mode.

1 Like

Hey Edy, thanks for responding!

I’m aware that the physics position is updated strictly in FixedUpdate, but I don’t understand why the functionality changes when transform.SetParent is called before/after position setting. It seems like I can call either in Update or FixedUpdate and the functionality is as expected, but when SetParent is added to the mix, the behaviour becomes unexpected.

To add context here is a package to minimally recreate this problem where the Rigidbody’s interpolation is set to Interpolate.

9754057–1396312–SetParent_and_Rigidbody_Error.unitypackage (4.53 KB)