直接上代碼:
BezierUtils類獲得三點之間的所有可移動的位置:
using UnityEngine; public class BezierUtils { /// <summary> /// 根據T值,計算貝塞爾曲線上面相對應的點 /// </summary> /// <param name="t"></param>T值 /// <param name="p0"></param>起始點 /// <param name="p1"></param>控制點 /// <param name="p2"></param>目標點 /// <returns></returns>根據T值計算出來的貝賽爾曲線點 private static Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2) { float u = 1 - t; float tt = t * t; float uu = u * u; Vector3 p = uu * p0; p += 2 * u * t * p1; p += tt * p2; return p; } /// <summary> /// 獲取存儲貝塞爾曲線點的數組 /// </summary> /// <param name="startPoint"></param>起始點 /// <param name="controlPoint"></param>控制點 /// <param name="endPoint"></param>目標點 /// <param name="segmentNum"></param>采樣點的數量 /// <returns></returns>存儲貝塞爾曲線點的數組 public static Vector3[] GetBeizerList(Vector3 startPoint, Vector3 controlPoint, Vector3 endPoint, int segmentNum) { Vector3[] path = new Vector3[segmentNum]; for (int i = 1; i <= segmentNum; i++) { float t = i / (float)segmentNum; Vector3 pixel = CalculateCubicBezierPoint(t, startPoint, controlPoint, endPoint); path[i - 1] = pixel; } return path; } }
BezierMove類讓物體在Bezier曲線上的所有點之間移動:
using UnityEngine; using System.Collections; using UnityEngine.UI; /// <summary> /// 移動完成之后的回調 /// </summary> public delegate void BezierMoveCompleteDel(); public class BezierMove : MonoBehaviour { /// <summary> /// 貝賽爾曲線的路徑點的數量,數量越多獲得的曲線越完美,但是消耗也就越大 /// </summary> private int _segmentNum = 100; /// <summary> /// 獲得貝賽爾曲線所有的路徑點 /// </summary> private Vector3[] _allposArry; /// <summary> /// 移動的速度 /// </summary> private float _speed = 10; /// <summary> /// 所有的路徑點的索引值 /// </summary> private int _index = 0; /// <summary> /// 需要移動的目標 /// </summary> private Transform _moveTargte; /// <summary> /// 是否完成移動 /// </summary> private bool _isMoveComplete = false; /// <summary> /// 初始化貝賽爾曲線所有的路徑點 /// </summary> /// <param name="startPos">開始移動的位置</param> /// <param name="controlPos">中間點的位置,目的是改變物體移動的曲線弧度</param> /// <param name="endPos">最終移動的位置</param> /// <param name="moveTarget">需要移動的目標物體</param> /// <param name="moveSpeed">移動速度</param> /// <param name="segmentNum">三點之間Bezier曲線上所有點的數量</param> public void Init(Vector3 startPos, Vector3 controlPos, Vector3 endPos,Transform moveTarget,float moveSpeed,int segmentNum=100) { _moveTargte = moveTarget; _speed = moveSpeed; _allposArry = new Vector3[segmentNum]; _allposArry = BezierUtils.GetBeizerList(startPos, controlPos, endPos, _segmentNum); _isMoveComplete = false; } /// <summary> /// 移動 /// </summary> /// <param name="moveComplete">移動完成的回調</param> public void Move(BezierMoveCompleteDel moveComplete=null) { if (_allposArry == null|| _allposArry.Length==0) { Debug.LogError("沒有初始化貝賽爾曲線的所有的路徑點"); return; } if(!_isMoveComplete) { if (Vector3.Distance(_moveTargte.position, _allposArry[_index]) <= 0.1f) { _index++; if (_index > _segmentNum - 1) { _index = _segmentNum - 1; if (moveComplete != null) { moveComplete(); } _isMoveComplete = true; } } else { _moveTargte.position = Vector3.Slerp(_moveTargte.position, _allposArry[_index], _speed * Time.deltaTime); } } } }
testBezier測試腳本:
using UnityEngine; using System.Collections; using UnityEngine.UI; using Spine; using Spine.Unity; using System; using Global; using Kernal; namespace Controll { public class testBezier : MonoBehaviour { int _segmentNum = 100; public Transform StartPos; public Transform ControlPos; public Transform EndPos; private Vector3[] posArry; public float Speed = 10; private int _index = 0; public Transform Targte; [SerializeField] private BezierMove _bezierMove; private void Start() { _bezierMove.Init(StartPos.position,ControlPos.position,EndPos.position,Targte, Speed, _segmentNum); } private void Update() { _bezierMove.Move(ONComplete); } private void ONComplete() { Debug.Log("移動完畢"); } } }
unity編輯器下的環境: