Bezier movement is erratic

Hi, I was studying about bezier curves and how adapt into scripts, so I wanted to make a curve-based movement script with target:

using UnityEngine;
using System.Collections;

public class CurveMov : MonoBehaviour {

	public bool on;

	public float way;
	public float duration;
	public float progress;

	public Vector3 mPoint; //Middle point of the curve

	public Transform target;

	void Start (){

		SetMid();

	}

	Vector3 BezierMov (float t, Vector3 p0, Vector3 p1, Vector3 p2){
		
		float u = 1f-t;
		float uu = u*u;
		float tt = t*t;

		Vector3 p = uu * p0;
		p += 2f * u * t * p1;
		p += tt * p2;
		
		return p;
	}

	public void SetMid (){

		mPoint = (target.position + transform.position)/2;
		mPoint.y += 10f; //Add some height
	}
	
	void Update () {

		if (on){
			progress += Time.deltaTime;
			way = Mathf.Clamp(progress / duration, 0f, 1f);
			transform.position = BezierMov(way, transform.position, mPoint, target.position);
		}
	}
}

When “on” is true, it moves, but works very erratic. At start goes too fast, but when reach middle point, it moves slowly. How can I fix it?

Thanks in advance.

You shouldn’t use the current position as first point as this will deform your curve as you go. The 3 points should be constant. So when you start moving you should save the start position in a variable and use that as the first point.

This should “fix” most of your problems. However keep in mind that a bezier curve isn’t equally distributed and you will have a different speed at different points on the curve depending on the constallation of your control points.

This slight speed variation is a bit tricky to fix as it depends on where the points actually are. However if the points are in a light arc (<90°) the variation should be very small.

edit

To compensate the curve variation you could simply calculate the “speed” of the curve at the current point to approximately adjust the amount you have to move to get a constant speed:

float speed = 2.0f; // desired speed in world units

void Update ()
{
    if (on)
    {
        float dist = (BezierMov(way + 0.01f, start, mPoint, target.position) - transform.position).magnitude;
        float f = 0.01f / dist;
        
        way += speed * f * Time.deltaTime;
        way = Mathf.Clamp01(way);
        transform.position = BezierMov(way, start, mPoint, target.position);
    }
}

This should move your object from “start” to “target.position” at a speed of 2 world units per second.

If you want to move to the target in a specified time you would need to know the overall distance to calculate an appropriate speed. For this you would have to iterate through the whole path once when you start and store the approximate path length in a variable. That length divided by your desired duration would be the linear speed required to reach the target in the given time.