unity 實現物體沿指定的平滑曲線移動(通過貝塞爾曲線實現)
阿新 • • 發佈:2018-12-10
在實際專案開發中,為了實現某種動畫或者特效,策劃都會要求讓物體實現沿編輯的軌跡進行移動,今天這裡就講一下如何讓物體沿可編輯的路線進行移動,這裡主要是通過貝塞爾曲線實現。
首先要了解貝塞爾曲線的基礎知識及原理,具體可參考改連結:
這裡的思路就是首先就是把關鍵節點儲存起來,然後在通過貝塞爾的計算公式計算出兩個節點之間的擬合點的集合,最後可以控制小球在運動的過程中通過走過的路徑的長度作為下標,取出該長度下對應的座標資訊,從而實現小球沿規定路徑移動。
下面是具體的程式碼實現:
首先是計算出指定軌跡的擬合點,儲存到list中,就是隻在初始化的時候計算出來,然後儲存,後面可以一直沿用,如果是在執行邊計算邊使用計算量會偏大:
#region 計算貝塞爾曲線的擬合點 //初始化算出所有的點的資訊 void InitPoint() { //獲取指定的點的資訊 Vector3[] pointPos = new Vector3[basePoint.Length]; for (int i = 0; i < pointPos.Length; i++) { pointPos[i] = basePoint[i].transform.position; } GetTrackPoint(pointPos); } /// <summary> /// 根據設定節點 繪製指定的曲線 /// </summary> /// <param name="track">所有指定節點的資訊</param> public void GetTrackPoint(Vector3[] track) { Vector3[] vector3s = PathControlPointGenerator(track); int SmoothAmount = track.Length * baseCount; lineRender.positionCount = SmoothAmount; for (int i = 1; i < SmoothAmount; i++) { float pm = (float)i / SmoothAmount; Vector3 currPt = Interp(vector3s, pm); lineRender.SetPosition(i, currPt); lsPoint.Add(currPt); } } /// <summary> /// 計算所有節點以及控制點座標 /// </summary> /// <param name="path">所有節點的儲存陣列</param> /// <returns></returns> public Vector3[] PathControlPointGenerator(Vector3[] path) { Vector3[] suppliedPath; Vector3[] vector3s; suppliedPath = path; int offset = 2; vector3s = new Vector3[suppliedPath.Length + offset]; Array.Copy(suppliedPath, 0, vector3s, 1, suppliedPath.Length); vector3s[0] = vector3s[1] + (vector3s[1] - vector3s[2]); vector3s[vector3s.Length - 1] = vector3s[vector3s.Length - 2] + (vector3s[vector3s.Length - 2] - vector3s[vector3s.Length - 3]); if (vector3s[1] == vector3s[vector3s.Length - 2]) { Vector3[] tmpLoopSpline = new Vector3[vector3s.Length]; Array.Copy(vector3s, tmpLoopSpline, vector3s.Length); tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3]; tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2]; vector3s = new Vector3[tmpLoopSpline.Length]; Array.Copy(tmpLoopSpline, vector3s, tmpLoopSpline.Length); } return (vector3s); } /// <summary> /// 計算曲線的任意點的位置 /// </summary> /// <param name="pos"></param> /// <param name="t"></param> /// <returns></returns> public Vector3 Interp(Vector3[] pos, float t) { int length = pos.Length - 3; int currPt = Mathf.Min(Mathf.FloorToInt(t * length), length - 1); float u = t * (float)length - (float)currPt; Vector3 a = pos[currPt]; Vector3 b = pos[currPt + 1]; Vector3 c = pos[currPt + 2]; Vector3 d = pos[currPt + 3]; return .5f * ( (-a + 3f * b - 3f * c + d) * (u * u * u) + (2f * a - 5f * b + 4f * c - d) * (u * u) + (-a + c) * u + 2f * b ); } #endregion
然後就是通過在update中移動小球,根據小球軌跡長度取出對應長度下的座標資訊賦值:
void Start() { lineRender = gameObject.GetComponent<LineRenderer>(); InitPoint(); } void Update() { length += Time.deltaTime * speed; if (length >= lsPoint.Count - 1) { length = lsPoint.Count - 1; } sphere.transform.localPosition = lsPoint[(int)(length)]; }
上述就是小球沿指定軌跡的具體思路。
工程連結:連結:https://pan.baidu.com/s/1h4FQNI1A9992k7T29J2GqQ 密碼:mql1
想了解更多unity開發相關資訊,可以關注下方公眾號或者新增QQ交流群879354767,來分享學習遊戲中的開發心得: