Ich versuche, das Gelenk gleichmäßig um die Mitte der Leinwand in Richtung des Mauszeigers zu drehen. Was ich habe, funktioniert, aber ich möchte, dass es die kürzest mögliche Entfernung animiert, um zum Mauswinkel zu gelangen. Das Problem tritt auf, wenn der Wert an der horizontalen Linie ( 3.14
und -3.14
) eine Schleife durchläuft . Fahren Sie mit der Maus über diesen Bereich, um zu sehen, wie sich die Richtung ändert, und es dauert den langen Weg zurück.
Relevanter Code
// ease the current angle to the target angle
joint.angle += ( joint.targetAngle - joint.angle ) * 0.1;
// get angle from joint to mouse
var dx = e.clientX - joint.x,
dy = e.clientY - joint.y;
joint.targetAngle = Math.atan2( dy, dx );
Wie kann ich ihn auf die kürzeste Distanz drehen lassen, sogar "über die Lücke"?
mathematics
javascript
animation
lerp
easing
Jackrugile
quelle
quelle
Antworten:
Es ist nicht immer die beste Methode und kann rechenintensiver sein (obwohl dies letztendlich davon abhängt, wie Sie Ihre Daten speichern), aber ich werde argumentieren, dass das Lerpen von 2D-Werten in den meisten Fällen recht gut funktioniert. Anstatt einen gewünschten Winkel zu verändern, können Sie den gewünschten normalisierten Richtungsvektor verändern.
Ein Vorteil dieser Methode gegenüber der Methode "Wählen Sie die kürzeste Route zum Winkel" ist, dass sie funktioniert, wenn Sie zwischen mehr als zwei Werten interpolieren müssen.
Wenn Sie Farbtonwerte einlesen, können Sie diese durch
hue
einen[cos(hue), sin(hue)]
Vektor ersetzen .In Ihrem Fall unterbrechen Sie die normalisierte Gelenkrichtung:
Der Code kann kürzer sein, wenn Sie eine 2D-Vektorklasse verwenden können. Zum Beispiel:
quelle
dx /= len
...len ? len : 1.0
Teil vermeidet nur eine Division durch Null, in dem seltenen Fall, dass die Maus genau an der Gelenkposition platziert ist. Es hätte geschrieben:if (len != 0) dx /= len;
.0°
und interpolieren180°
? In vektorieller Form:[1, 0]
und[-1, 0]
. Interpolations - Vektoren werden Sie geben entweder0°
,180°
oder eine Division durch 0 Fehler, beit=0.5
.Der Trick besteht darin, sich daran zu erinnern, dass die Winkel (zumindest im euklidischen Raum) um 2 * pi periodisch sind. Wenn der Unterschied zwischen dem aktuellen Winkel und dem Zielwinkel zu groß ist (dh der Cursor hat die Grenze überschritten), passen Sie den aktuellen Winkel einfach an, indem Sie 2 * pi entsprechend addieren oder subtrahieren.
In diesem Fall können Sie Folgendes versuchen: (Ich habe noch nie in Javascript programmiert. Verzeihen Sie also meinen Codierungsstil.)
BEARBEITEN : In dieser Implementierung ruckelt der Cursor, wenn er zu schnell um die Gelenkmitte bewegt wird. Dies ist das beabsichtigte Verhalten, da die Winkelgeschwindigkeit des Gelenks immer proportional ist
dtheta
. Wenn dieses Verhalten unerwünscht ist, kann das Problem leicht behoben werden, indem eine Kappe auf die Winkelbeschleunigung des Gelenks aufgesetzt wird.Dazu müssen wir die Geschwindigkeit des Gelenks verfolgen und eine maximale Beschleunigung auferlegen:
Aus praktischen Gründen führen wir eine Clipping-Funktion ein:
Unser Bewegungscode sieht nun so aus. Zuerst berechnen wir
dtheta
wie zuvor und passenjoint.angle
nach Bedarf an:Anstatt das Gelenk sofort zu bewegen, berechnen wir eine Zielgeschwindigkeit und
clip
erzwingen sie innerhalb unseres akzeptablen Bereichs.Dies erzeugt eine gleichmäßige Bewegung, selbst wenn die Richtung geändert wird, während Berechnungen in nur einer Dimension ausgeführt werden. Darüber hinaus können Geschwindigkeit und Beschleunigung des Gelenks unabhängig voneinander eingestellt werden. Sehen Sie die Demo hier: http://codepen.io/anon/pen/HGnDF/
quelle
dtheta
. Wollten Sie, dass das Joint etwas Schwung bekommt?Ich liebe die anderen Antworten. Sehr technisch!
Wenn Sie möchten, habe ich eine sehr einfache Methode, um dies zu erreichen. Für diese Beispiele nehmen wir Winkel an. Das Konzept kann auf andere Werttypen, z. B. Farben, extrapoliert werden.
Ich habe dies gerade im Browser erstellt und wurde noch nie getestet. Ich hoffe, ich habe die Logik beim ersten Versuch richtig verstanden.
[Bearbeiten] 02.06.2017 - Die Logik wurde ein wenig geklärt.
Beginnen Sie mit der Berechnung von distanceForward und distanceBackwards und lassen Sie die Ergebnisse über den Bereich (0-360) hinausgehen.
Durch das Normalisieren der Winkel werden diese Werte wieder in den Bereich von (0-360) gebracht. Dazu addieren Sie 360, bis der Wert über Null liegt, und subtrahieren 360, während der Wert über 360 liegt. Die resultierenden Start- / Endwinkel entsprechen dem Äquivalent (-285 entspricht 75).
Als nächstes finden Sie den kleinsten normalisierten Winkel von distanceForward oder distanceBackward. distanceForward im Beispiel wird zu 75, was kleiner als der normalisierte Wert von distanceBackward (300) ist.
Wenn distanceForward das kleinste AND endAngle <startAngle ist, erweitern Sie endAngle über 360 hinaus, indem Sie 360 hinzufügen (im Beispiel wird es 375).
Wenn distanceBackward das kleinste AND endAngle> startAngle ist, erweitern Sie endAngle auf unter 0, indem Sie 360 subtrahieren.
Sie würden jetzt von startAngle (300) zu dem neuen endAngle (375) springen. Der Motor sollte automatisch Werte über 360 anpassen, indem er 360 für Sie subtrahiert. Andernfalls müssten Sie von 300 bis 360 lerpen, DANN von 0 bis 15 lerpen, wenn die Engine die Werte für Sie nicht normalisiert.
quelle
atan2
Idee einfach ist, könnte diese etwas Platz und ein bisschen Leistung sparen (keine Notwendigkeit, x und y zu speichern oder sin, cos und atan2 zu oft zu berechnen). Ich denke, es lohnt sich, ein wenig darüber nachzudenken, warum diese Lösung richtig ist (dh den kürzesten Weg auf einem Kreis oder einer Kugel zu wählen, genau wie es SLERP für Quaterions tut). Diese Frage und die Antworten sollten in das Community-Wiki gestellt werden, da dies ein sehr häufiges Problem ist, mit dem die meisten Gameplay-Programmierer konfrontiert sind.