先看一下曲线的效果
1.在使用NGUI的过程中,发现iTween.cs里面有两个很有用的方法,一个是输入指定路点数组,一个就是曲线的插值算法。今天我们主要就用到这两个方法来实现曲线效果。
1 public static Vector3[] PathControlPointGenerator(Vector3[] path)
2 {
3 Vector3[] suppliedPath;
4 Vector3[] vector3s;
5
6 //create and store path points:
7 suppliedPath = path;
8
9 //populate calculate path;
10 int offset = 2;
11 vector3s = new Vector3[suppliedPath.Length + offset];
12 Array.Copy(suppliedPath, 0, vector3s, 1, suppliedPath.Length);
13
14 //populate start and end control points:
15 //vector3s[0] = vector3s[1] - vector3s[2];
16 vector3s[0] = vector3s[1] + (vector3s[1] - vector3s[2]);
17 vector3s[vector3s.Length - 1] = vector3s[vector3s.Length - 2] + (vector3s[vector3s.Length - 2] - vector3s[vector3s.Length - 3]);
18
19 //is this a closed, continuous loop? yes? well then so let's make a continuous Catmull-Rom spline!
20 if (vector3s[1] == vector3s[vector3s.Length - 2])
21 {
22 Vector3[] tmpLoopSpline = new Vector3[vector3s.Length];
23 Array.Copy(vector3s, tmpLoopSpline, vector3s.Length);
24 tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3];
25 tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2];
26 vector3s = new Vector3[tmpLoopSpline.Length];
27 Array.Copy(tmpLoopSpline, vector3s, tmpLoopSpline.Length);
28 }
29
30 return (vector3s);
31 }
32
33 //andeeee from the Unity forum's steller Catmull-Rom class ( http://forum.unity3d.com/viewtopic.php?p=218400#218400 ):
34 public static Vector3 Interp(Vector3[] pts, float t)
35 {
36 int numSections = pts.Length - 3;
37 int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1);
38 float u = t * (float)numSections - (float)currPt;
39
40 if(currPt == 0)
41 {
42 int dsd = 0;
43 }
44
45 Vector3 a = pts[currPt];
46 Vector3 b = pts[currPt + 1];
47 Vector3 c = pts[currPt + 2];
48 Vector3 d = pts[currPt + 3];
49
50 return .5f * (
51 (-a + 3f * b - 3f * c + d) * (u * u * u)
52 + (2f * a - 5f * b + 4f * c - d) * (u * u)
53 + (-a + c) * u
54 + 2f * b
55 );
56 }
直接上完整代码,把这个脚本放到相机上,然后在场景中拖几个物件作为路点,就可以实现上面的效果
1 using System;
2 using System.Collections.Generic;
3 using UnityEngine;
4
5 namespace Fish.Study.Curve
6 {
7 /// <summary>
8 /// 曲线测试
9 /// </summary>
10 public class CurveTest : MonoBehaviour
11 {
12 //路点
13 public GameObject[] GameObjectList;
14 //各路点的坐标
15 public List<Vector3> TransDataList = new List<Vector3>();
16
17 void Start()
18 {
19 }
20
21 //Gizmos
22 void OnDrawGizmos()
23 {
24 //1个点是不能画出曲线的,2个点实际上是直线
25 if (GameObjectList.Length <= 1) return;
26
27 TransDataList.Clear();
28 for (int i = 0; i < GameObjectList.Length; ++i)
29 {
30 TransDataList.Add(GameObjectList[i].transform.position);
31 }
32
33 if (TransDataList != null && TransDataList.Count > 1)
34 {
35 DrawPathHelper(TransDataList.ToArray(), Color.red);
36 }
37 }
38
39 public Vector3[] GetCurveData()
40 {
41 if (TransDataList != null && TransDataList.Count > 1)
42 {
43 var v3 = (TransDataList.ToArray());
44 Vector3[] vector3s = PathControlPointGenerator(v3);
45 return vector3s;
46 }
47
48 return null;
49 }
50
51 //NGUI iTween.cs中的方法,输入路径点
52 public static Vector3[] PathControlPointGenerator(Vector3[] path)
53 {
54 Vector3[] suppliedPath;
55 Vector3[] vector3s;
56
57 //create and store path points:
58 suppliedPath = path;
59
60 //populate calculate path;
61 int offset = 2;
62 vector3s = new Vector3[suppliedPath.Length + offset];
63 Array.Copy(suppliedPath, 0, vector3s, 1, suppliedPath.Length);
64
65 //populate start and end control points:
66 vector3s[0] = vector3s[1] + (vector3s[1] - vector3s[2]);
67 vector3s[vector3s.Length - 1] = vector3s[vector3s.Length - 2] + (vector3s[vector3s.Length - 2] - vector3s[vector3s.Length - 3]);
68
69 //is this a closed, continuous loop? yes? well then so let's make a continuous Catmull-Rom spline!
70 if (vector3s[1] == vector3s[vector3s.Length - 2])
71 {
72 Vector3[] tmpLoopSpline = new Vector3[vector3s.Length];
73 Array.Copy(vector3s, tmpLoopSpline, vector3s.Length);
74 tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3];
75 tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2];
76 vector3s = new Vector3[tmpLoopSpline.Length];
77 Array.Copy(tmpLoopSpline, vector3s, tmpLoopSpline.Length);
78 }
79
80 return (vector3s);
81 }
82
83 //曲线插值函数
84 public static Vector3 Interp(Vector3[] pts, float t)
85 {
86 int numSections = pts.Length - 3;
87 int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1);
88 float u = t * (float)numSections - (float)currPt;
89
90 Vector3 a = pts[currPt];
91 Vector3 b = pts[currPt + 1];
92 Vector3 c = pts[currPt + 2];
93 Vector3 d = pts[currPt + 3];
94
95 return .5f * (
96 (-a + 3f * b - 3f * c + d) * (u * u * u)
97 + (2f * a - 5f * b + 4f * c - d) * (u * u)
98 + (-a + c) * u
99 + 2f * b
100 );
101 }
102
103 //画曲线
104 private void DrawPathHelper(Vector3[] path, Color color)
105 {
106 Vector3[] vector3s = PathControlPointGenerator(path);
107
108 //Line Draw:
109 Vector3 prevPt = Interp(vector3s, 0);
110 int SmoothAmount = path.Length * 20;
111 for (int i = 1; i <= SmoothAmount; i++)
112 {
113 float pm = (float)i / SmoothAmount;
114 Vector3 currPt = Interp(vector3s, pm);
115
116 Gizmos.color = color;
117 Gizmos.DrawSphere(currPt, 0.2f);
118 prevPt = currPt;
119 }
120 }
121 }
122 }
2.同样的DOTeen插件中也可以利用transform.DoPath()或者transform.DoLocalPath()结合贝塞尔曲线结算路径的坐标点的方式实现我们常用的曲线运动,如:
/// <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;
//Debug.Log(path[i - 1]);
}
return path;
}
/// <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;
}
Vector3[] path = BezierUtils.GetBeizerList(new Vector3(startPositon.x, startPositon.y + 0.5f, startPositon.z), controlPosition, targetPos, 40);
transform.DOPath(path, 1.0f);