Zuerst müssen Sie die Winkeldifferenz zwischen der Richtung des Turms und der Richtung zum Ziel bestimmen.
Vector2 turretToTarget = target.position - turret.position;
float desiredAngle = atan2(turretToTarget.y, turretToTarget.x);
float angleDiff = desiredAngle - turret.angle;
// Normalize angle to [-PI,PI] range. This ensures that the turret
// turns the shortest way.
while (angleDiff < -PI) angleDiff += 2*PI;
while (angleDiff >= PI) angleDiff -= 2*PI;
Sobald Sie diese Größen haben, können Sie einen Ausdruck zweiten Grades für den Revolverwinkel einrichten. Sie müssen dies bei jeder Aktualisierung berechnen, um sicherzustellen, dass Sie immer die neuesten Positions- und Geschwindigkeitsdaten verwenden.
// Compute angular acceleration.
const float C0 = // Must be determined.
const float C1 = // Must be determined.
float angularAcc = C0 * angleDiff - C1 * turret.angularVelocity;
Hier bewirkt der erste Term (null Grad) im Beschleunigungsausdruck, dass sich der Turm in Richtung des Ziels dreht. Es wird jedoch nicht rechtzeitig aufhören, sondern darüber hin- und herschwingen. Damit es stoppt, benötigen wir den zweiten Dämpfungsterm (erster Grad), der bewirkt, dass einer hohen Drehgeschwindigkeit eine hohe Beschleunigung gegenübersteht.
Nun müssen die positiven Konstanten (nicht unbedingt Programmkonstanten) bestimmt und ausgeglichen werden, damit sich das System gut verhält. C0
ist die Hauptsteuerung für die Geschwindigkeit des Systems. Ein hoher Wert für C0
ergibt eine schnelle Drehgeschwindigkeit und ein niedriger Wert ergibt eine niedrige Drehgeschwindigkeit. Der tatsächliche Wert hängt von vielen Faktoren ab, daher sollten Sie hier "trial and error" verwenden. C1
regelt die Stärke der Dämpfung. Die Diskriminante der quadratischen Gleichung sagt uns, dass C1*C1 - 4*C0 >= 0
wir ein nicht oszillierendes System haben.
// New definition.
const float C1 = 2*sqrt(C0); // Stabilizes the system.
Sie sollten wahrscheinlich C1
aus numerischen Gründen ein wenig größer wählen , aber nicht zu groß, da es stattdessen sehr überlastet und langsam reagieren kann. Auch hier müssen Sie optimieren.
Es ist auch wichtig zu beachten, dass dieser Code nur die Winkelbeschleunigung berechnet. Der Winkel und die Winkelgeschwindigkeit müssen unter Verwendung einer Art Integrator von dieser Stelle aus aktualisiert werden. Aus der Frage gehe ich davon aus, dass dies abgedeckt wurde.
Zum Schluss gibt es noch einiges zum Thema Verzögerung zu sagen, da der Turm bei der Verfolgung eines schnellen Ziels wahrscheinlich immer zurückbleibt. Eine einfache Möglichkeit, dies zu beheben, besteht darin, der Position des Ziels eine lineare Vorhersage hinzuzufügen, dh immer leicht nach vorne in die Vorwärtsrichtung des Ziels zu zielen.
// Improvement of the first lines above.
const float predictionTime = 1; // One second prediction, you need to experiment.
Vector2 turretToTarget = target.position + predictionTime * target.velocity - turret.position;
/// ...
Um den Turm für einige Zeit im Radius des Ziels zu halten, kann dies eine schwierige Anforderung sein, die direkt an ein solches System gestellt werden muss. Sie können sicher sein, dass dieser Controller stets bestrebt ist, den Turm auf das Ziel (bzw. die vorhergesagte Position) auszurichten. Wenn das Ergebnis nicht zufriedenstellend erweist , müssen Sie die Parameter ändern predictionTime
, C0
und C1
(innerhalb stabiler Grenzen).