
给定 起点、中间高度点、终点、运动时间实现抛物线运动自由抛物线路径可不对称using UnityEngine; /// summary /// 自由抛物线 /// 路径自由可不对称 /// /summary public class ParabolaMoveActionScript : MonoBehaviour { public Transform MoveObj; public Transform FromPoint; public Transform PeekPoint; public Transform ToPoint; public float MoveTime 2.0f; [SerializeField, Header(Timer)] private float m_Timer 0.0f; private bool m_Run; private Vector3 m_StartPos; private Vector3 m_PeekPos; private Vector3 m_EndPos; private void Start() { m_StartPos FromPoint.position; m_PeekPos PeekPoint.position; m_EndPos ToPoint.position; } private void Update() { if (Input.GetKeyDown(KeyCode.Tab)) { m_Run true; m_Timer 0; } if (m_Run) { m_Timer Time.deltaTime; float t m_Timer / MoveTime; t Mathf.Clamp(t, 0.0f, 1.0f); Vector3 currPos GetCurvePoint(m_StartPos, m_PeekPos, m_EndPos, t); MoveObj.position currPos; if (t 1.0f) { m_Run false; } } } public static Vector3 GetCurvePoint(Vector3 _p0, Vector3 _p1, Vector3 _p2, float t) { t Mathf.Clamp(t, 0.0f, 1.0f); float x ((1 - t) * (1 - t)) * _p0.x 2 * t * (1 - t) * _p1.x t * t * _p2.x; float y ((1 - t) * (1 - t)) * _p0.y 2 * t * (1 - t) * _p1.y t * t * _p2.y; float z ((1 - t) * (1 - t)) * _p0.z 2 * t * (1 - t) * _p1.z t * t * _p2.z; Vector3 pos new Vector3(x, y, z); return pos; } private void OnDrawGizmos() { if (FromPoint null || PeekPoint null || ToPoint null) { return; } m_StartPos FromPoint.position; m_PeekPos PeekPoint.position; m_EndPos ToPoint.position; for (float t 0; t 1; t 0.005f) { var point GetCurvePoint(m_StartPos, m_PeekPos, m_EndPos, t); Gizmos.color Color.yellow; Gizmos.DrawSphere(point, 0.01f); Gizmos.color Color.white; } } }标准抛物线路径对称using System.Collections.Generic; using System; using UnityEngine; /// summary /// 标准抛物线 /// 路径对称 /// /summary public class ParabolicMover : MonoBehaviour { public Transform FromPoint; public Transform PeakPoint; public Transform ToPoint; public float Duration 2.0f; private Vector2 m_Start; private Vector2 m_Peak; private Vector2 m_End; private float m_ElapsedTime; private (float a, float b, float c) m_Coefficients; private bool m_Run; void Start() { SetPath(FromPoint.position, PeakPoint.position, ToPoint.position); transform.position m_Start; } void Update() { if (Input.GetKeyDown(KeyCode.Tab)) { m_Run true; m_ElapsedTime 0; } m_ElapsedTime Time.deltaTime; float t Mathf.Clamp01(m_ElapsedTime / Duration); // 在x轴上线性移动 float x Mathf.Lerp(m_Start.x, m_End.x, t); // 根据抛物线方程计算y值 float y m_Coefficients.a * x * x m_Coefficients.b * x m_Coefficients.c; transform.position new Vector2(x, y); // 到达终点 if (t 1.0f) { m_Run false; } } private void OnDrawGizmos() { if (FromPoint null || PeakPoint null || ToPoint null) { return; } SetPath(FromPoint.position, PeakPoint.position, ToPoint.position); for (float t 0; t 1; t 0.005f) { float x Mathf.Lerp(m_Start.x, m_End.x, t); float y m_Coefficients.a * x * x m_Coefficients.b * x m_Coefficients.c; Gizmos.color Color.yellow; Gizmos.DrawSphere(new Vector3(x, y, 0), 0.01f); Gizmos.color Color.white; } } public void SetPath(Vector2 newStart, Vector2 newPeak, Vector2 newEnd) { m_Start newStart; m_Peak newPeak; m_End newEnd; m_Coefficients ParabolicPathCalculator.CalculateParabolaCoefficients(m_Start, m_Peak, m_End); m_ElapsedTime 0; } } public class ParabolicPathCalculator { /// summary /// 计算抛物线路径点 /// /summary /// param namestart起点坐标/param /// param namepeak最高点坐标/param /// param nameend终点坐标/param /// param namepointCount生成的点数/param /// returns抛物线路径点列表/returns public static ListVector2 CalculateParabolaPoints(Vector2 start, Vector2 peak, Vector2 end, int pointCount 50) { // 验证输入 if (pointCount 2) { throw new ArgumentException(点数必须至少为2, nameof(pointCount)); } // 计算抛物线系数 (float a, float b, float c) CalculateParabolaCoefficients(start, peak, end); // 确定x范围 float minX Mathf.Min(start.x, end.x); float maxX Mathf.Max(start.x, end.x); // 生成路径点 ListVector2 points new ListVector2(); for (int i 0; i pointCount; i) { // 在x范围内均匀分布点 float t i / (float)(pointCount - 1); float x Mathf.Lerp(minX, maxX, t); // 使用抛物线方程计算y值 float y a * x * x b * x c; points.Add(new Vector2(x, y)); } return points; } /// summary /// 计算抛物线系数 (y ax² bx c) /// 顶峰peek的x坐标去首位点的中点 /// /summary public static (float a, float b, float c) CalculateParabolaCoefficients(Vector2 start, Vector2 peak, Vector2 end) { // 使用三个点建立方程组 // y1 a*x1² b*x1 c // y2 a*x2² b*x2 c // y3 a*x3² b*x3 c // 矩阵形式 // | x1² x1 1 | | a | | y1 | // | x2² x2 1 | * | b | | y2 | // | x3² x3 1 | | c | | y3 | peak.x (start.x end.x) / 2; float x1 start.x, y1 start.y; float x2 peak.x, y2 peak.y; float x3 end.x, y3 end.y; // 计算行列式 float det (x1 * x1) * (x2 - x3) - x1 * (x2 * x2 - x3 * x3) (x2 * x2 * x3 - x2 * x3 * x3); float detA y1 * (x2 - x3) - x1 * (y2 - y3) (y2 * x3 - y3 * x2); float detB (x1 * x1) * (y2 - y3) - y1 * (x2 * x2 - x3 * x3) (x2 * x2 * y3 - x3 * x3 * y2); float detC (x1 * x1) * (x2 * y3 - x3 * y2) - x1 * (x2 * x2 * y3 - x3 * x3 * y2) y1 * (x2 * x2 * x3 - x2 * x3 * x3); // 检查行列式是否接近零 if (Mathf.Abs(det) 0.0001f) { // 三点共线,自动改为使用线性插值 return CalculateLinearCoefficients(start, end); } float a detA / det; float b detB / det; float c detC / det; return (a, b, c); } /// summary /// 当三点共线时计算线性系数 /// /summary private static (float a, float b, float c) CalculateLinearCoefficients(Vector2 start, Vector2 end) { // 线性方程y mx k float m (end.y - start.y) / (end.x - start.x); float k start.y - m * start.x; // 返回形式y 0*x² mx k return (0, m, k); } }