MovePosition not as precise as Translate with Kinematic rigidbodies (example unitypackage included)

So I’ve been doing some testing and I’ve come to the conclusion that MovePosition have a lag when moving a rigidbody. The included unitypackage comes with a simple scene with 2 instances of a prefab.

([56224-rigidbodytrouble.zip|56224])

That prefab is a rigidbody with:

  • Interpolate: Set to “Interpolate”
  • Use gravity: Unchecked
  • Is Kinematic: Checked

In Update, the arrow keys are scanned to check if the game objects must be moved around.

One of the instances (Player 1) moves it’s position using transform.Translate in Update. The other (Player 2) uses rigidbody.MovePosition in FixedUpdate, where all physics interactions should be.

The code (very simple) is as follows:

[Range(1, 2)]
public int PlayerId = 1;
public float speed = 5;

private Rigidbody rigidBody;
private Vector2 input;

void Awake()
{
    rigidBody = GetComponent<Rigidbody>();
}


void Update () {
    input = new Vector2();
    if (Input.GetKey(KeyCode.LeftArrow)) { input.x = -1; }
    if (Input.GetKey(KeyCode.RightArrow)) { input.x = 1; }
    if (Input.GetKey(KeyCode.UpArrow)) { input.y = 1; }
    if (Input.GetKey(KeyCode.DownArrow)) { input.y = -1; }

    if (PlayerId == 1)
    {
        Vector3 movement = Vector3.right * input.x * speed * Time.deltaTime;
        movement += Vector3.forward * input.y * speed * Time.deltaTime;                  
        transform.Translate(movement);
    }
}

void FixedUpdate()
{     
    if (PlayerId == 2) {
        Vector3 movement = Vector3.right * input.x * speed * Time.deltaTime;
        movement += Vector3.forward * input.y * speed * Time.deltaTime;
        rigidBody.MovePosition(rigidBody.position + movement);         
    }
}

In theory both game objects should move at the same time, maintaining their relative position between each other. But if you run this sample, you will notice that Player 2 have a noticeable lag between the moment the arrow is pressed and its actual movement on the screen.

While Player 1 (using translate) moves instantly as it should, Player 2 seems to do it at a different time. If you follow Player 2 in the Scene View (using Shift + F) and keep going in one direction, you will notice that eventually it will surpass Player 1.

Is there a solution to this problem? Is there something I’m missing or not understanding? This lag completely ruins precision gameplay, but I want to use the physics system.

Thanks in advance.

I’m not sure if you are familiar with how FixedUpdate works. FixedUpdate is always executed before Update. However it’s “fixed” (not at a fix rate but with a “fixed” time / deltaTime).

Time.deltaTime usually returns the time the last frame took overall. However inside FixedUpdate Time.deltaTime returns “fixedDeltaTime” instead. That’s because FixedUpdate doesn’t run necessarily when Update runs or it might even run multiple times within one frame to keep it’s execution rate “pseudo constant”.

In pseudo code Unity’s main loop looks something like this:

while(true)
{
    ReadInput();
    while(Time.fixedTime < Time.time)
    {
        RunFixedUpdate();
        UpdateInternalPhysics();
        Time.fixedTime += Time.fixedDeltaTime;
    }
    RunUpdate();
    Render();
    Time.time += Time.deltaTime;
}

“Time.fixedDeltaTime” is a constant value it’s what you have set as your fixed timestep. (Usually 0.02 == 50fps)

As you can see if fixedDeltaTime is larger than the actual deltaTime FixedUpdate might skip an execution since the amount Time.time advanced the last frame doesn’t exceed the current “fixedTime”. Both Time.time and Time.fixedTime will advance at the same speed. They never drift apart. However they will almost never be equal since they are advanced at different intervals. FixedUpdate (with a timestep of 0.02) will always be called 50 times in a sec while the Update rate depends on the performance and maybe vsync limitations.

If your framerate drops to 5 fps, FixedUpdate will be called roughly 10 times per frame. If you have a framerate of about 100fps FixedUpdate will be called about every second frame. So every other frame no FixedUpdate call is made.

You get the smoothest movement if you sync the movement with the visual update. FixedUpdate just ensures a constant rate which is important if your movement should be the same at all framerates.

As we all know using Time.deltaTime ensures that a linear change which we apply each frame is time based and frame independent. However that only works for linear changes. Since acceleration (linear change of velocity) results in a quadratic change in position there’s an error which is different depending on the framerate. Using a constant rate for physics calculations ensures that you always get the same result after a certain amount of time.

Using FixedUpdate for movement will always introduce a bit of stutter since sometimes you might get two visual updates but only one actual movement so it looks like it’s stuck for a frame.

As far as i know it should be no problem to use MovePosition inside Update especially since you have just a linear motion (no acceleration). The advice to use FixedUpdate applies to when using forces. Since forces are applied inside the Internal physics step you should apply the force right before Unity’s physics system internally updates the velocity / position.

edit
I once made a Webplayer build to visualize how FixedUpdate works. Of course you need a browser that still supports the Unity webplayer plugin ^^. You can adjust the virtual “FPS rate” and the “FixedRate” at the bottom. The simulaition speed is 100 times slower than realtime(can also be adjusted). Each red section represents “one frame” where each blue rect represents an Update call(once per frame) while the magenta rects represents an FixedUpdate call. You can also see how Time.time and Time.fixedTime will change over time.