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. 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:
using UnityEngine;
using System.Collections;
public class PlayerControl : MonoBehaviour {
[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.
but maybe it’s just the fact that you move player1 with transform.Translate, that moves the object outside of Physics updates, and it happens in Update, so FPS and Update might be in simple scene happening more often than fixed step update (set in Physics settings).
When you move object with rigidBody.MovePosition, object will be moved on next tick of FixedUpdate. I’m quite noob with Unity Physics stuff, so those who know better correct if I’m wrong, but that’s how I think it works.
I’ve reduced it to 0.166667 (to achieve 60 Hz refresh rate) and moved the rigidbody manipulation to Update, since it’s linear movement and doesn’t involve acceleration. It’s better now but I’m still having a little bit of lag compared to the movement of the GO using translate.
[Range(1, 2)]
public int PlayerId = 1;
public float speed = 5;
private Rigidbody rigidBody;
private Vector2 input;
private Vector3 movement;
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; }
movement = Vector3.right * input.x * speed * Time.deltaTime;
movement += Vector3.forward * input.y * speed * Time.deltaTime;
if (PlayerId == 1)
transform.Translate(movement);
if (PlayerId == 2)
rigidBody.position = rigidBody.position + movement; //instead of rigidBody.MovePosition(rigidBody.position + movement);
}
I’m quite surprised that nobody finds this disturbing. I know that rigidbody are usually moved using forces, etc, but moving one changing it’s coordinates seems like an usual scenario…
Kinematic rigidbodies should always be moved via MovePosition / MoveRotation so the physic interactions would be properly applied. Otherwise, using Translate you’ll surely encounter issues when the moving object has to interact with other non-kinematic physic objects. Typical cases are collisions and carrying other objects (i.e. a character walking over a kinematic moving platform).
The discrepancies you’re observing might have to do with the accumulated error of the different delta times between Update and FixedUpdate. They are different tasks running at different rates. I wouldn’t expect delta times at Update to be exact at all and every frame.
If enabled, the object will not be driven by the physics engine, and can only be manipulated by its Transform. This is useful for moving platforms or if you want to animate a Rigidbody that has a HingeJoint attached.
That sounds more like Translate than MovePosition to me…
I’m actually quite baffled by this whole issue. I understand how different timings affect the smoothness of the final movement, but I’m surprised that there isn’t an integrated solution in such a simple scenario…
To my understanding, moveposition and rigidbody.position will run in fixedupdate even if you use it in update.
If you are going to use physics, and your fixed timestep is less than your framerate, you will have a delay compared to just update. Interpolation will increase that delay by like 1 frame more.
Also, again to my understanding, the difference between moveposition and translating is that moveposition will push other rigidbodies as if you were moving it with addforce, while setting the transform will just teleport and then slide any collisions away so they dont collide.
Nothing prevents you to do so, but then your object won’t collide or push/move other non-kinematic objects.
That’s it.
The correct solution is using MovePosition/MoveRotation in FixedUpdate for moving kinematic objects in a physically precise way. Having Interpolate enabled ensures visually smooth movement.
Comparing the results to using Translate in Update is rather pointless and subject to errors and discrepancies (frame timing, numerical accumulations…). Moreover, if you verify the actual results of each case you’ll encounter that the FixedUpdate/MovePosition solution actually brings the exact result.
Example: distance traveled by the object when moving at 1 m/s during 60 seconds. The FixedUpdate/MovePosition method will yield 60 meters exactly. The Update/Translate method will yield varying results depending on frame rate during execution, frame timing inaccuracies, numerical accumulations, etc.
So if you need precision gameplay, the FixedUpdate/MovePosition is definitely the way to go. You can reduce the fixed time step if you need to increase the precision.
Of course, but if I chose to set it to kinematic, that’s probably what I had in mind. And it will collide/push non-kinematic… not sure why you suggest it wont.
I just wrote a runner with kinematic cubes for the level and a non kin for the player.
But as you can see in the sample scene I attached, using FixedUpdate + MovePosition results in stuttering while moving, even with interpolation and a fixed timestep of 0.166667 (for 60fps refresh)
Is there anything obvious I’m missing?
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; }
}
void FixedUpdate()
{
Vector3 movement = Vector3.right * input.x * speed * Time.deltaTime;
movement += Vector3.forward * input.y * speed * Time.deltaTime;
rigidBody.MovePosition(rigidBody.position + movement);
}
Weird, I just did a quick test and it seems moveposition, rigidbody.position, translate, and transform.position will act the same in fixedupdate. It seems they are all moving the colliding rigidbody, but not pushing it.
I could have sworn in 5.0 or so moveposition was pushing rigidbodies. I am now in 5.2.1f1
The obvious failings will become apparent when you put colliders in front of the moving object.
Here is what I would expect in a few different scenarios…
Kinematic - Moving via Translate/MovePosition - forces don’t work.
pushing into kinematic. Colliders pass through each other without resistance
pushing into non-kinematic. Non-kinematic gets pushed away
Non-Kinematic - Moving via Translate
pushing into kinematic. Collider will move clip other collider with some resistance (bad - the non kinematic should not pass/move through the blocking collider)
pushing into non-kinematic. They will push each other. Some clipping will occur. Again bad form. They should not clip.
Non-Kinematic - Moving via MovePosition/Forces/Velocity
pushing into kinematic - Colliders will not clip, kinematic will prevent non-kinematic pushing through
pushing into non-kinematic - Colliders will push each other away without clipping. RB with largest mass will have biggest effect on which collider gets pushed.
I’ve just updated to 5.2.1f1 and now it seems that moving the kinematic rigidbody using MovePosition is smoother than using translate using the same script as post #1… wait, WHAT?
There’s still some lag between the button press and the actual movement of the rigidbody that doesn’t occur using translate. My head is spinning…
I know this is old but here my 5 cents. You’re using Time.deltaTime inside the fixed update and this is incorrect. Your should use Time.fixedDeltaTime. That is probably why you got so much difference.