Search Unity

Question rigidbody.MovePosition() vs transform.position

Discussion in 'Getting Started' started by Opaiushart, Feb 23, 2022.

  1. Opaiushart

    Opaiushart

    Joined:
    Nov 14, 2015
    Posts:
    5
    As per the title, I have 3 gameobjects with slightly different movement code.

    The first sets its position with Transform.position.
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class Tr_Position : MonoBehaviour
    5. {
    6.     [SerializeField] private float movementSpeed = 5f;
    7.  
    8.     private void Update()
    9.     {
    10.         Vector3 nextPos = transform.position + transform.forward * movementSpeed * Time.deltaTime;
    11.         transform.position = nextPos;
    12.     }
    13. }
    14.  
    The 2nd uses rigidbody.MovePosition() in Update().
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class RB_Movement_Update : MonoBehaviour
    5. {
    6.     [SerializeField] private float movementSpeed = 5f;
    7.     private Rigidbody rigid;
    8.  
    9.     private void Start()
    10.     {
    11.         rigid = GetComponent<Rigidbody>();
    12.     }
    13.  
    14.     private void Update()
    15.     {
    16.         Vector3 nextPos = transform.position + transform.forward * movementSpeed * Time.deltaTime;
    17.         rigid.MovePosition(nextPos);
    18.     }
    19. }
    20.  
    The 3rd also uses a rigidbody but this time it calls MovePosition() in FixedUpdate().
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class RB_Movement_FixedUpdate : MonoBehaviour
    5. {
    6.     [SerializeField] private float movementSpeed = 5f;
    7.     private Rigidbody rigid;
    8.  
    9.     private void Start()
    10.     {
    11.         rigid = GetComponent<Rigidbody>();
    12.     }
    13.  
    14.     private void FixedUpdate()
    15.     {
    16.         Vector3 nextPos = transform.position + transform.forward * movementSpeed * Time.fixedDeltaTime;
    17.         rigid.MovePosition(nextPos);
    18.     }
    19. }
    20.  
    To calculate its next position, I am using the below formula:
    nextPosition = currentPosition + direction * movementSpeed * deltaTime.

    Upon having all 3 gameobjects move off at the same time, the 1st and 3rd objects appear to move at the same rate while the 2nd lags severely behind. Why is that?
     
    profitdefiant likes this.
  2. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    The physics simulation runs on a fixed update time, hence why
    FixedUpdate
    should be used for physics tasks like moving a Rigidbody.

    On the other hand,
    Update
    is tied to frame-rate; your frame-rate is how many times
    Update
    executes per second.
    Since the physics simulation isn't tied to frame-rate, it's possible for nothing to happen on a frame where you try to execute some physics task, because the next fixed time step hasn't been updated yet on that frame.
     
    Last edited: Feb 23, 2022
    profitdefiant and Opaiushart like this.
  3. Opaiushart

    Opaiushart

    Joined:
    Nov 14, 2015
    Posts:
    5
    Thank you for the reply. In that case, could you confirm that the logic in the below code is flawed for gameobjects with rigidbodies? (Assuming FinalizePosition is called in Update() and the supplied parameter "nextPosition" is calculated in Update() with Time.deltaTime)

    Code (CSharp):
    1.  
    2. private void FinalizePosition(Vector3 nextPosition)
    3. {
    4.     if (rigid != null) rigid.MovePosition(nextPosition)
    5.     else tr.position = nextPosition;
    6. }
    7.  
    If it is true that the above code is flawed, would it be appropriate for one to add checks in the calculation of "nextPosition" to have different calculations for gameobjects with rigidbodies? Below is an example to illustrate what I am thinking of:

    Code (CSharp):
    1.  
    2. void Update()
    3. {
    4.     Vector3 nextPosition = CalculateNextPosition();
    5.     FinalizePosition(nextPosition);
    6. }
    7.  
    8. private Vector3 CalculateNextPosition()
    9. {
    10.     if (rigid != null) return rigid.position + direction * movementSpeed * Time.fixedDeltaTime;
    11.         else return transform.position + direction * movementSpeed * Time.deltaTime;
    12. }
    13.  
     
  4. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    The typical way to share data between
    Update
    and
    FixedUpdate
    is to just use a global variable.
    I may be wrong here, but in your
    CalculateNextPosition
    method, I believe
    transform.position + direction * movementSpeed * Time.deltaTime;
    should work fine regardless if you're using a Transform or Rigidbody for movement; you just need to make sure the next position is calculated from
    Update
    , and used in
    FixedUpdate
    when applicable:
    Code (CSharp):
    1. Rigidbody2D rigid;
    2. Vector3 nextPosition;
    3.  
    4. bool ShouldUsePhysics => rigid != null;
    5.  
    6. void Update()
    7. {
    8.   nextPosition = CalculateNextPosition();
    9.  
    10.   if(!ShouldUsePhysics)
    11.   {
    12.     FinalizeTransformPosition(nextPosition);
    13.   }
    14. }
    15.  
    16. void FixedUpdate()
    17. {
    18.   if(ShouldUsePhysics)
    19.   {
    20.     FinalizeRigidbodyPosition(nextPosition);
    21.   }
    22. }
    23.  
    24. void FinalizeTransformPosition(Vector3 position) =>  tr.position = position;
    25.  
    26. void FinalizeRigidbodyPosition(Vector3 position) => rigid.MovePosition(position);
    27.  
    28. Vector3 CalculateNextPosition() => transform.position + direction * movementSpeed * Time.deltaTime;
     
  5. Opaiushart

    Opaiushart

    Joined:
    Nov 14, 2015
    Posts:
    5
    Thanks for getting back, that indeed sounds like a good way to share data between Update() and FixedUpdate(). I have already incorporated it into my project and its working well so far.

    I also went ahead to test out your script. However, it seems that gameobjects with a rigidbody still moves slower compared to the ones without. I think this is because when a position is calculated in
    Update
    , as you said, some frames are rendered without the physics simulation have run its update cycle, thus making it possible for
    CalculateNextPosition 
    to calculate the same position over a few frames, hence leading to the object moving slower than intended.

    Thanks again for the replies :)
     
    profitdefiant likes this.