Es ist möglich, eine Lösung für dieses Problem für die meisten parametrischen Trajektorien zu finden. Die Idee ist die folgende: Wenn Sie eine Kurve stark genug zoomen, können Sie die Kurve selbst nicht an der Tangente an diesem Punkt erkennen.
Wenn Sie diese Annahme treffen, müssen Sie nicht mehr als zwei Vektoren vorberechnen (drei für kubische Bézier-Kurven, usw. ).
Also berechnen wir für eine Kurve ihren Tangentenvektor am Punkt . Die Norm dieses Vektors ist und daher kann die für eine Dauer als . Daraus folgt, dass eine Strecke für eine DauerM(t)dMdtt∥dMdT∥Δt∥ dMdT∥ Δ tLL÷∥dMdT∥ .
Anwendung: quadratische Bezierkurve
Wenn die Kontrollpunkte der Bezier-Kurve , undABC , kann die Flugbahn folgendermaßen ausgedrückt werden:
M(t)=(1−t)2A+2t(1−t)B+t2C=t2(A−2B+C)+t(−2A+2B)+A
Die Ableitung lautet also:
dMdt=t(2A−4B+2C)+(−2A+2B)
Sie müssen nur die Vektoren und irgendwo . Dann, für ein gegebenes , wenn Sie eine Länge vorrücken möchten , tun Sie:v⃗ 1= 2 A - 4 B + 2 Cv⃗ 2= - 2 A + 2 BtL
t = t + Ll e n gt h ( t ⋅ v⃗ 1+ v⃗ 2)
Kubische Bezierkurven
Die gleiche Überlegung gilt für eine Kurve mit vier Kontrollpunkten , , und :EINBCD
M(t)=(1−t)3A+3t(1−t)2B+3t2(1−t)C+t3D=t3(−A+3B−3C+D)+t2(3A−6B+3C)+t(−3A+3B)+A
Die Ableitung ist:
dMdt=t2(−3A+9B−9C+3D)+t(6A−12B+6C)+(−3A+3B)
Wir berechnen die drei Vektoren vor:
v⃗ 1v⃗ 2v⃗ 3=−3A+9B−9C+3D=6A−12B+6C=−3A+3B
und die endgültige Formel lautet:
t=t+Llengt h ( t2⋅ v⃗ 1+ t ⋅ v⃗ 2+ v⃗ 3)
Genauigkeitsprobleme
Wenn Sie mit einer vernünftigen Framerate laufen,L (das entsprechend der Bilddauer berechnet werden sollte) ausreichend klein, damit die Approximation funktioniert.
In extremen Fällen können jedoch Ungenauigkeiten auftreten. Wenn zu groß ist, können Sie die Berechnung stückweise ausführen, beispielsweise mit 10 Teilen:L
for (int i = 0; i < 10; i++)
t = t + (L / 10) / length(t * v1 + v2);
L
ausreichend klein, ist diese Annäherung tatsächlich immer genauer als die Antwort unten, ja. Außerdem wird weniger Speicher verwendet (da die Ableitung verwendet wird, anstatt alle Punktwerte zu speichern). Wenn esL
anfängt zu wachsen, kannst du die Technik verwenden, die ich am Ende vorschlage.Sie müssen die Kurve neu parametrisieren. Der einfachste Weg, dies zu tun, besteht darin, die Bogenlängen mehrerer Kurvensegmente zu berechnen und diese zu verwenden, um herauszufinden, wo Sie abtasten sollten. Zum Beispiel sollten Sie bei t = 0,5 (auf halber Strecke) s = 0,7 an die Kurve übergeben, um die Position "auf halber Strecke" zu erhalten. Dazu müssen Sie eine Liste der Bogenlängen verschiedener Kurvensegmente speichern.
Es gibt wahrscheinlich bessere Möglichkeiten, aber hier ist ein sehr einfacher C # -Code, den ich geschrieben habe, um dies in meinem Spiel zu tun. Es sollte einfach sein, auf Ziel C zu portieren:
Bearbeiten: Es ist erwähnenswert, dass dies nicht die exakte Bogenlänge ergibt, da es unmöglich ist, die Bogenlänge einer kubischen Kurve zu erhalten. Dies ist lediglich eine Schätzung der Länge der verschiedenen Segmente. Abhängig von der Länge der Kurve müssen Sie möglicherweise die Auflösung erhöhen, um zu verhindern, dass sich die Geschwindigkeit ändert, wenn ein neues Segment erreicht wird. Normalerweise benutze ich ~ 100, womit ich noch nie ein Problem hatte.
quelle
Eine sehr leichte Lösung besteht darin, die Geschwindigkeit zu approximieren, anstatt die Kurve zu approximieren. Tatsächlich ist dieser Ansatz unabhängig von der Kurvenfunktion und ermöglicht es Ihnen, eine beliebige exakte Kurve zu verwenden, anstatt Ableitungen oder Näherungen zu verwenden.
Hier ist der Code für C # Unity 3D:
Obwohl die Lösung unabhängig von der Kurvenfunktion ist, wollte ich sie hier notieren, da ich auch nach Möglichkeiten gesucht habe, eine konstante Geschwindigkeit auf einer Bézier-Kurve zu erzielen, und dann habe ich diese Lösung gefunden. In Anbetracht der Popularität der Funktion kann dies hier hilfreich sein.
quelle
Ich weiß nichts über cocos2, aber eine Bezierkurve ist eine Art parametrische Gleichung, sodass Sie in der Lage sein sollten, Ihre x- und y-Werte in Bezug auf die Zeit zu erhalten.
quelle