For my mobile game I needed enemy space ships that would fly to random points in space within a specific area. When they reached the designated point, they would choose a new point and the process would repeat. First I tried the easiest solution: transform.LookAt(), which worked, but the space ships had a specific turn radius and under some circumstances would circle the destination point indefinitely. I could increase the distance that was required for the ship to “reach” the checkpoint but I wanted to guarantee consistency.
Bezier curves would allow me to have consistent flight patterns without having to fine tune parameters in order to avoid unintended behaviors.
using UnityEngine; using System.Collections; public class Test : MonoBehaviour { [SerializeField] private float dist; //the distance of the current curve on a scale of 0 to 1 [SerializeField] private Vector3[] points; // an array of Vector3 points to calculate the curve. You can adjust the formula to use your desired amount of points. [SerializeField] private float min; //the minimum distance at which to place a points[] [SerializeField] private float max; //the maximum distance at which to place a points[] [SerializeField] private float speed; //the speed modifier for moving the ship along the curve void Awake() { CalcInitPoints(); } Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) // returns the vector3 of the desired point along the curve. this vector3 will be the transform.position of the ship { float u = 1f - t; float tt = t * t; float uu = u * u; float uuu = uu * u; float ttt = tt * t; Vector3 p = uu * p0; p += 2 * u * t * p1; p += tt * p2; return p; } void Update () { MoveBezier(); //for the purpose of demonstration, the flight is continuously calculated on Update(). } private void CalcInitPoints() //create the initial points for the curve { for (int i = 0; i <= 4; i++) { points[i] = new Vector3(Random.Range(min, max), Random.Range(min, max), Random.Range(min, max)); } } private void NewPoints() //NewPoints is used only after there are points already existing { points[0] = points[2]; //re-use the third point points[1] = (points[2] + (-0.5f * (points[1] - points[2]))); //the second point becomes the new tangent calculated using the third and second point points[2] = new Vector3(Random.Range(min, max), Random.Range(min, max), Random.Range(min, max));//the third point is the new random Vector3 } private void MoveBezier() //updates every frame to move the ship along the curve using Time.deltaTime { Vector3 nextPoint = CalculateBezierPoint(dist, points[0], points[1], points[2], points[3]); //injects dist (0-1 which increases by deltaTime) into the bezier formula transform.position = nextPoint; //translate the position of the ship if (dist <= 1f) //check every frame to see if the end of the curve has been reached { dist += Time.deltaTime * speed; transform.LookAt(CalculateBezierPoint(dist, points[0], points[1], points[2], points[3])); //keeps the ship facing in the direction that it is flying } else { NewPoints(); //when the end of the curve has been reached, create a new curve and then reset the dist to zero dist = 0; } } }
The length and point on the curve is measured between 0 and 1. The position of the ship is set equal to a specific point on the curve which is being increased by Time.deltaTime. Once the distance has reached 1, a new point is made, a new curve is calculated, and the distance along the curve is set back to 0. Now we have random flight paths using bezier curves.
Some caveats; the curves would sometimes be very acute, which resulted in a space ship that turned very quickly, which I found undesirable. A solution to this would be use a 3rd point between the previous and the next point. An extra point would create a softer curve, as long as it is placed between the first and last points a shape close to an equilateral triangle.
Special thanks and credits to Herman Tulleken for being my source: http://devmag.org.za/2011/04/05/bzier-curves-a-tutorial/ His function CalculateBezierPoint does a great job of breaking down the cubic bezier formula: