Vector3.MoveTowards move object with different speed on different frame rate

I am using Vector3.MoveTowards to move my object over a set of points. I am getting different completion time based on fps.
On lower fps my object completes the movement quickly and on higher fps it is completing little later.
Can anyone help me solve this issue.


As long as you move it by the same speed quantity each frame and multiply by Time.deltaTime, it will be as close to the same speed as possible given floating point imprecision.

If that’s not what you see then you have a bug, and that means…time to start debugging!

By debugging you can find out exactly what your program is doing so you can fix it.

Use the above techniques to get the information you need in order to reason about what the problem is.

You can also use Debug.Log(...); statements to find out if any of your code is even running. Don’t assume it is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

Remember with Unity the code is only a tiny fraction of the problem space. Everything asset- and scene- wise must also be set up correctly to match the associated code and its assumptions.

If you’re just moving things around, this was solved decades ago by using Tweeners. There are plenty of free ones like iTween and LeanTween and DOTween. Don’t reinvent the wheel unless you like reinventing wheels. :slight_smile:

Floating (float) point imprecision:

Never test floating point (float) quantities for equality / inequality. Here’s why:

“Think of [floating point] as JPEG of numbers.” - orionsyndrome on the Unity3D Forums

Hi i tested this in a new empty project. There is nothing in this project except the code which shared.

Great! Nothing about what I wrote above changes.

As already noted, you WILL NEVER get exactly the same final position. That’s not a thing in floating point land, especially with variable frame rates.

How much is it off? Go read the above floating point number info to reason about if it is “within expectations,” but keep in mind it will NEVER be equal on two different runs, except by chance.

Delta Time isn’t perfect and your computer can’t perfectly fire updates at a consistent time.

Because of this, you will see differences in the delta between one frame and the next. Generally the failure is less if you are asking it to fire more consistently. However, those diffs will still add up over time. Potentially that total can be fairly significant depending on how precise your position requirements are. You can write systems that measure the over/under timing between frames and try to steer toward the ideal ‘perfect’ value, but the fact is that you won’t be able to get fixed/deterministic update timing. FixedUpdate() does better than Update, but you’ll still see artifacts.

There are systems that run at a fixed hz but this is typically industry hardware and not consumer hardware.

Here’s an extended test script for you to play with and understand a little bit more.

using System.Diagnostics;
using UnityEngine;
using Debug = UnityEngine.Debug;

public class test : MonoBehaviour
{
    public enum UpdateType { Update, FixedUpdate, LateUpdate }

    public UpdateType Mode;
    public int FrameRate = 30;
    public float MoveSpeed = 1;
    public Transform[] MovePoints;
    private int m_index;
    private Stopwatch m_timer;
    private float m_lastTime;

    private void Start()
    {
        m_timer = Stopwatch.StartNew();
        m_index++;
        Application.targetFrameRate = FrameRate;
    }

    private void Update()
    {
        if (Mode != UpdateType.Update) return;
        Tick();
    }
    private void FixedUpdate()
    {
        if (Mode != UpdateType.FixedUpdate) return;
        Tick();
    }
    private void LateUpdate()
    {
        if (Mode != UpdateType.LateUpdate) return;
        Tick();
    }

    private void Tick()
    {
        float step = MoveSpeed * Time.deltaTime;
        transform.position = Vector3.MoveTowards(transform.position, MovePoints[m_index].position, step);

        if (Vector3.Distance(transform.position, MovePoints[m_index].position) > step) return;
        
        m_index++;
        if (m_index >= MovePoints.Length)
        {
            m_index = 0;
            Debug.Log($"Loop [{Mode}] : {m_lastTime} ({m_timer.ElapsedMilliseconds - m_lastTime})");
            m_lastTime = m_timer.ElapsedMilliseconds;
            m_timer.Restart();
        }
    }
}

Thanks for the nice explanation. I will try to implement some kind of logic which accounts for the inconsistency in the delta time.
I was testing/experimenting this for my own understanding, i dont have any project requirement.

1 Like