If you use the Bezier curve principle to use traces of points on the Bezier curve, you can express a smooth curve.
If you put in a vector list, it’s calculated from the code that solved the formula above traces of dots (dot B) come out.
A curve is drawn according to the change of t = [0,1].
PhysicsUtility.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PhysicsUtility : MonoBehaviour
{ /// <summary>
/// Combination
/// </summary>
/// <param name="n"></param>
/// <param name="i"></param>
/// <returns></returns>
public static float Combination(int n, int i)
{
if (i < 0)
{
return 1;
}
else if (i > n)
{
return 1;
}
float p = 1;
for (int j = 0; j < i; j++)
{
p *= (n - j);
}
float rP = 1;
for (int k = 1; k <= i; k++)
{
rP *= k;
}
return p / rP;
}
/// <summary>
/// Final interpolated position of the bezier curve <br/>
/// </summary>
/// <param name="dataset"></param>
/// <param name="t"></param>
/// <returns></returns>
public static Vector3 BezierCurve(List<Vector3> dataset, float t)
{
if (dataset.Count <= 1)
{
throw new InvalidOperationException("You must include the number of at least two points!!");
}
int n = dataset.Count - 1;
Vector3 B = new Vector3();
for (int i = 0; i <= n; i++)
{
B += Combination(n, i) * Mathf.Pow(t, i) * Mathf.Pow((1 - t), n - i) * dataset[i];
}
return B;
}
}
MovingGround.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovingGround : MonoBehaviour
{
[Range(0, 1)]
public float vTest = 0;
public float speed = 0.01f;
Rigidbody rigid;
public List<Vector3> dataSets = new List<Vector3>();
private void Awake()
{
rigid = GetComponent<Rigidbody>();
}
private void Start()
{
StartCoroutine(Move());
}
private IEnumerator Move()
{
while (true)
{
while (vTest < 1)
{
float sp = speed * Time.fixedDeltaTime;
rigid.position = PhysicsUtility.BezierCurve(dataSets, vTest);
vTest = Mathf.Clamp01(vTest + sp);
yield return new WaitForFixedUpdate();
}
while (vTest > 0)
{
float sp = speed * Time.fixedDeltaTime;
vTest = Mathf.Clamp01(vTest - sp);
rigid.position = PhysicsUtility.BezierCurve(dataSets, vTest);
yield return new WaitForFixedUpdate();
}
}
}
}
MovingEditor.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CanEditMultipleObjects]
[CustomEditor(typeof(MovingGround))]
public class MovingEditor : Editor
{
private MovingGround Generator;
SerializedProperty dataset;
private void OnEnable()
{
Generator = target as MovingGround;
dataset = serializedObject.FindProperty("dataSets");
}
private void OnSceneGUI()
{
if (Generator.dataSets.Count <= 1)
{
return;
}
EditorGUI.BeginChangeCheck();
Queue<Vector3> buffer = new Queue<Vector3>();
for (int i = 0; i < Generator.dataSets.Count; i++)
{
buffer.Enqueue(Handles.PositionHandle(Generator.dataSets[i], Quaternion.identity));
}
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(Generator, $"Change {nameof(Generator.dataSets)}");
for (int i = 0; i < Generator.dataSets.Count; i++)
{
Generator.dataSets[i] = buffer.Dequeue();
}
EditorUtility.SetDirty(Generator);
}
for (int i = 0; i < Generator.dataSets.Count - 1; i++)
{
Handles.DrawLine(Generator.dataSets[i], Generator.dataSets[i + 1]);
}
int detail = 50;
for (float i = 0; i < detail; i++)
{
float value_before = i / detail;
Vector3 before = PhysicsUtility.BezierCurve(Generator.dataSets, value_before);
float value_after = (i + 1) / detail;
Vector3 after = PhysicsUtility.BezierCurve(Generator.dataSets, value_after); ;
Handles.DrawLine(before, after);
}
}
}
Be Careful!
Be careful!
For reference, the Editor script must create and insert an Editor folder within Unity so that there is no error when building.
Result Video
References
Thank you :)