正如您所注意到的,樣條線會生成不同長度的線段。曲線越緊密,分段越短。這對於顯示而言很不錯,對於移動設備的路徑生成不太有用。
爲了獲得樣條路徑的恆速遍歷的合理近似值,您需要沿着曲線段進行一些插值。由於您已經有一組線段(在由Vector2.CatmullRom()
返回的點對之間),您需要一種以恆定速度行走這些段的方法。
給定一組點和一條沿着定義爲那些點之間的線的路徑移動的總距離,下面的(或多或少的僞代碼)會找到一個沿着路徑的特定距離的點:
Point2D WalkPath(Point2D[] path, double distance)
{
Point curr = path[0];
for (int i = 1; i < path.Length; ++i)
{
double dist = Distance(curr, path[i]);
if (dist < distance)
return Interpolate(curr, path[i], distance/dist;
distance -= dist;
curr = path[i];
}
return curr;
}
有各種優化可以做,以加快這,如存儲與路徑中的每個點的路徑距離,使其更易於步行操作過程中查找。隨着你的路徑變得越來越複雜,這變得越來越重要,但是對於只有幾個分段的路徑來說可能是過度的。
編輯:Here's an example我在JavaScript中使用了這種方法。這是一個驗證的概念,所以在代碼不要太嚴格:P
編輯:花鍵上一代
給定一組的「結」的更多信息分 - 是點一個曲線必然順序傳遞 - 對於曲線算法最明顯的適合是Catmull-Rom。缺點是C-R需要兩個額外的控制點,這些控制點可能很難自動生成。
一段時間後,我在網上發現了一篇相當有用的文章(我無法找到正確的歸因),根據路徑中的點集計算了一組控制點。這裏是我的C#代碼爲計算控制點方法:
// Calculate control points for Point 'p1' using neighbour points
public static Point2D[] GetControlsPoints(Point2D p0, Point2D p1, Point2D p2, double tension = 0.5)
{
// get length of lines [p0-p1] and [p1-p2]
double d01 = Distance(p0, p1);
double d12 = Distance(p1, p2);
// calculate scaling factors as fractions of total
double sa = tension * d01/(d01 + d12);
double sb = tension * d12/(d01 + d12);
// left control point
double c1x = p1.X - sa * (p2.X - p0.X);
double c1y = p1.Y - sa * (p2.Y - p0.Y);
// right control point
double c2x = p1.X + sb * (p2.X - p0.X);
double c2y = p1.Y + sb * (p2.Y - p0.Y);
// return control points
return new Point2D[] { new Point2D(c1x, c1y), new Point2D(c2x, c2y) };
}
的tension
參數調整控制點生成改變曲線的密封性。值越高,曲線越寬,曲線越緊密,值越低。玩它,看看什麼價值最適合你。
給定一組「N」節(曲線上的點),我們可以生成一組將被用來生成節之間的曲線控制點:所以現在
// Generate all control points for a set of knots
public static List<Point2D> GenerateControlPoints(List<Point2D> knots)
{
if (knots == null || knots.Count < 3)
return null;
List<Point2D> res = new List<Point2D>();
// First control point is same as first knot
res.Add(knots.First());
// generate control point pairs for each non-end knot
for (int i = 1; i < knots.Count - 1; ++i)
{
Point2D[] cps = GetControlsPoints(knots[i - 1], knots[i], knots[i+1]);
res.AddRange(cps);
}
// Last control points is same as last knot
res.Add(knots.Last());
return res;
}
你有一組2*(n-1)
控制點,然後您可以使用該控制點生成結點之間的實際曲線段。
public static Point2D LinearInterp(Point2D p0, Point2D p1, double fraction)
{
double ix = p0.X + (p1.X - p0.X) * fraction;
double iy = p0.Y + (p1.Y - p0.Y) * fraction;
return new Point2D(ix, iy);
}
public static Point2D BezierInterp(Point2D p0, Point2D p1, Point2D c0, Point2D c1, double fraction)
{
// calculate first-derivative, lines containing end-points for 2nd derivative
var t00 = LinearInterp(p0, c0, fraction);
var t01 = LinearInterp(c0, c1, fraction);
var t02 = LinearInterp(c1, p1, fraction);
// calculate second-derivate, line tangent to curve
var t10 = LinearInterp(t00, t01, fraction);
var t11 = LinearInterp(t01, t02, fraction);
// return third-derivate, point on curve
return LinearInterp(t10, t11, fraction);
}
// generate multiple points per curve segment for entire path
public static List<Point2D> GenerateCurvePoints(List<Point2D> knots, List<Point2D> controls)
{
List<Point2D> res = new List<Point2D>();
// start curve at first knot
res.Add(knots[0]);
// process each curve segment
for (int i = 0; i < knots.Count - 1; ++i)
{
// get knot points for this curve segment
Point2D p0 = knots[i];
Point2D p1 = knots[i + 1];
// get control points for this curve segment
Point2D c0 = controls[i * 2];
Point2D c1 = controls[i * 2 + 1];
// calculate 20 points along curve segment
int steps = 20;
for (int s = 1; s < steps; ++s)
{
double fraction = (double)s/steps;
res.Add(BezierInterp(p0, p1, c0, c1, fraction));
}
}
return res;
}
一旦運行這個在你結你現在有一組相隔距離可變插值點,根據線路的曲率距離。由此,您可以迭代運行原始的WalkPath方法來生成一組相距不變的點,這些點以恆定的速度定義您的手機沿着曲線的進度。
您的手機在路徑任意點的標題(大致)是兩側的點之間的角度。對於路徑中的任意點n
,p[n-1]
和p[n+1]
之間的角度是航向角度。
// get angle (in Radians) from p0 to p1
public static double AngleBetween(Point2D p0, Point2D p1)
{
return Math.Atan2(p1.X - p0.X, p1.Y - p0.Y);
}
我已經適應從我的代碼上面,因爲我用的是Point2D類我很久以前寫的,有很多的功能 - 浮點運算,插值等 - 建於我可能已經增加了一些在翻譯過程中出現錯誤,但希望在玩遊戲時很容易發現它們。
讓我知道如何去。如果遇到任何特殊困難,我會看看我能做些什麼來幫助。
所以你有樣條曲線的產生,但需要以恆定的速度沿着它移動? – Corey 2013-02-16 22:42:44
@Corey我認爲...我會編輯這個問題來粗略地展示我迄今爲止所做的事情 – Bushes 2013-02-16 22:46:04
@Corey問題編輯 – Bushes 2013-02-16 22:48:33