Hinzufügen realistischer Kurven
Der nächste Schritt ist das Hinzufügen realistischer Kurven für unsere Einheiten, damit sie nicht jedes Mal, wenn sie sich drehen müssen, abrupt ihre Richtung ändern. Eine einfache Lösung besteht darin, die abrupten Ecken mit einem Spline in Kurven zu glätten. Dies löst zwar einige der ästhetischen Probleme, führt jedoch bei den meisten Einheiten zu physisch sehr unrealistischen Bewegungen. Beispielsweise könnte eine abrupte Kurvenfahrt eines Panzers in eine enge Kurve umgewandelt werden, aber die Kurve wäre immer noch viel enger, als der Panzer tatsächlich ausführen könnte.
Für eine bessere Lösung müssen wir zunächst den Wenderadius unserer Einheit kennen. Der Wenderadius ist ein ziemlich einfaches Konzept: Wenn Sie sich auf einem großen Parkplatz in Ihrem Auto befinden und das Rad so weit wie möglich nach links drehen, um in einem Kreis zu fahren, ist der Radius dieses Kreises Ihr Wenderadius Radius. Der Wenderadius eines Volkswagen Käfers ist wesentlich kleiner als der eines großen SUV, und der Wenderadius einer Person ist wesentlich kleiner als der eines großen, schwerfälligen Bären.
Nehmen wir an, Sie befinden sich an einem bestimmten Punkt (Ursprung) und weisen in eine bestimmte Richtung, und Sie müssen zu einem anderen Punkt (Ziel) gelangen, wie in Abbildung 5 dargestellt. Der kürzeste Weg wird gefunden, indem Sie nach links bis zu Ihnen abbiegen Gehen Sie im Kreis, bis Sie direkt auf das Ziel gerichtet sind, und gehen Sie dann vorwärts oder indem Sie nach rechts abbiegen und das Gleiche tun.
In Abbildung 5 ist der kürzeste Weg eindeutig die grüne Linie unten. Dieser Pfad ist aufgrund einiger geometrischer Beziehungen recht einfach zu berechnen (siehe Abbildung 6).
Zuerst berechnen wir den Ort des Punktes P, der der Mittelpunkt unseres Wendekreises ist und immer einen Radius r vom Startpunkt entfernt ist. Wenn wir von unserer anfänglichen Richtung nach rechts abbiegen, bedeutet dies, dass P in einem Winkel von (initial_direction - 90) vom Ursprung steht.
angleToP = initial_direction - 90
P.x = Origin.x + r * cos(angleToP)
P.y = Origin.y + r * sin(angleToP)
Nachdem wir die Position des Mittelpunkts P kennen, können wir die Entfernung von P zum Ziel berechnen, die im Diagramm als h angezeigt wird:
dx = Destination.x - P.x
dy = Destination.y - P.y
h = sqrt(dx*dx + dy*dy)
An dieser Stelle möchten wir auch überprüfen, ob das Ziel nicht innerhalb des Kreises liegt, da wir es sonst niemals erreichen könnten:
if (h < r)
return false
Jetzt können wir die Länge des Segments d berechnen, da wir bereits die Längen der beiden anderen Seiten des rechten Dreiecks kennen, nämlich h und r. Wir können den Winkel auch aus der Dreiecksbeziehung bestimmen:
d = sqrt(h*h - r*r)
theta = arccos(r / h)
Um schließlich den Punkt Q zu bestimmen, an dem der Kreis verlassen und auf der Geraden begonnen werden soll, müssen wir den Gesamtwinkel + kennen, der leicht als Winkel von P zum Ziel bestimmt werden kann:
phi = arctan(dy / dx) [offset to the correct quadrant]
Q.x = P.x + r * cos(phi + theta)
Q.y = P.y + r * sin(phi + theta)
Die obigen Berechnungen stellen den Rechtskurvenpfad dar. Der Pfad auf der linken Seite kann genauso berechnet werden, außer dass wir zur Berechnung von angleToP 90 zu initial_direction addieren und später - anstelle von + verwenden. Nachdem wir beide berechnet haben, sehen wir einfach, welcher Pfad kürzer ist und verwenden diesen.
Bei der Implementierung dieses und der folgenden Algorithmen verwenden wir eine Datenstruktur, in der bis zu vier verschiedene "Liniensegmente" gespeichert sind, von denen jedes entweder gerade oder gekrümmt ist. Für die hier beschriebenen Kurvenpfade werden nur zwei Segmente verwendet: ein Bogen, gefolgt von einer geraden Linie. Die Datenstruktur enthält Elemente, die angeben, ob das Segment ein Bogen oder eine gerade Linie ist, die Länge des Segments und seine Startposition. Wenn das Segment eine gerade Linie ist, gibt die Datenstruktur auch den Winkel an. Bei Bögen werden der Mittelpunkt des Kreises, der Startwinkel auf dem Kreis und die vom Bogen abgedeckten Bogenmaßzahlen angegeben.
Nachdem wir den für die Verbindung zwischen zwei Punkten erforderlichen gekrümmten Pfad berechnet haben, können wir unsere Position und Richtung zu jedem beliebigen Zeitpunkt leicht berechnen, wie in Listing 2 gezeigt.
Listing 2. Berechnung der Position und Orientierung zu einem bestimmten Zeitpunkt.
distance = unit_speed * elapsed_time
loop i = 0 to 3:
if (distance < LineSegment[i].length)
// Unit is somewhere on this line segment
if LineSegment[i] is an arc
//determine current angle on arc (theta) by adding or
//subtracting (distance / r) to the starting angle
//depending on whether turning to the left or right
position.x = LineSegment[i].center.x + r*cos(theta)
position.y = LineSegment[i].center.y + r*sin(theta)
//determine current direction (direction) by adding or
//subtracting 90 to theta, depending on left/right
else
position.x = LineSegment[i].start.x
+ distance * cos(LineSegment[i].line_angle)
position.y = LineSegment[i].start.y
+ distance * sin(LineSegment[i].line_angle)
direction = theta
break out of loop
else
distance = distance - LineSegment[i].length