Zielen für Fortgeschrittene

Aus Spieleprogrammierer-Wiki
(Unterschied zwischen Versionen)
Wechseln zu: Navigation, Suche
[gesichtete Version][gesichtete Version]
K (Bezeichnungen)
K (Anpassung für MathJax)
 
(10 dazwischenliegende Versionen von einem Benutzer werden nicht angezeigt)
Zeile 66: Zeile 66:
 
: <math>\left((\vec p_T + t_H \cdot \vec v_T) - \tfrac{1}{2} \vec g \cdot {t_H}^2\right)^2 = (t_H \cdot v_0)^2</math>
 
: <math>\left((\vec p_T + t_H \cdot \vec v_T) - \tfrac{1}{2} \vec g \cdot {t_H}^2\right)^2 = (t_H \cdot v_0)^2</math>
  
Jetzt muss diese Gleichung nach <math>t_H</math> aufgelöst werden. Die Arbeit besteht im Wesentlichen im Ausmultiplizieren der Quadrate. Wenn man anschließend die verschiedenen Potenzen von <math>t_H</math> ausklammert, ergibt sich folgende biquadratische Gleichung:
+
Jetzt muss diese Gleichung nach <math>t_H</math> aufgelöst werden. Die Arbeit besteht im Wesentlichen im Ausmultiplizieren der Quadrate. Wenn man anschließend die verschiedenen Potenzen von <math>t_H</math> ausklammert, ergibt sich folgende quartische Gleichung:
  
 
: <math>{t_H}^4 \cdot (\tfrac{1}{4} \vec g^2) + {t_H}^3 \cdot (-\vec v_T \cdot \vec g) + {t_H}^2 \cdot (\vec {v_T}^2 - {v_0}^2 - \vec p_T \cdot \vec g) + t_H \cdot (2 \vec p_T \cdot \vec v_T) + \vec {p_T}^2 = 0</math>
 
: <math>{t_H}^4 \cdot (\tfrac{1}{4} \vec g^2) + {t_H}^3 \cdot (-\vec v_T \cdot \vec g) + {t_H}^2 \cdot (\vec {v_T}^2 - {v_0}^2 - \vec p_T \cdot \vec g) + t_H \cdot (2 \vec p_T \cdot \vec v_T) + \vec {p_T}^2 = 0</math>
  
So wie es die "pq-Formel" zum Lösen quadratischer Gleichungen gibt, existieren auch für biquadratische Gleichungen direkte Lösungsverfahren, allerdings sind diese bei weitem nicht so einfach. Wir nehmen für den Moment einmal an, dass wir die Gleichung bereits lösen können. Dann können folgende Fälle auftreten:
+
So wie es die "pq-Formel" zum Lösen quadratischer Gleichungen gibt, existieren auch für quartische Gleichungen direkte Lösungsverfahren, allerdings sind diese bei weitem nicht so einfach. Wir nehmen für den Moment einmal an, dass wir die Gleichung bereits lösen können. Dann können folgende Fälle auftreten:
  
 
# Die Gleichung besitzt keine positive reelle Lösung. Für unseren Fall bedeutet das, dass das Ziel schlichtweg nicht getroffen werden kann, sofern es seinen momentanen Kurs beibehält (und auf dieser Annahme beruht das Verfahren).
 
# Die Gleichung besitzt keine positive reelle Lösung. Für unseren Fall bedeutet das, dass das Ziel schlichtweg nicht getroffen werden kann, sofern es seinen momentanen Kurs beibehält (und auf dieser Annahme beruht das Verfahren).
# Es gibt mindestens eine positive reelle Lösung. Das heißt, dass es eine oder mehrere Möglichkeiten gibt, wie das Projektil abgefeuert werden könnte, so dass es das Ziel irgendwann trifft. Manche dieser Möglichkeiten könnten etwas ungewöhnlich erscheinen, würde man sie in die Tat umsetzen. Der Schütze würde das Geschoss beispielsweise im hohen Bogen auf das Ziel befördern, obwohl es sich direkt vor ihm befindet. Negative Lösungen sind deswegen uninteressant, da die Lösungen schließlich für den voraussichtlichen Trefferzeitpunkt stehen, und ein negativer Wert würde bedeuten, dass das Ziel in der Vergangenheit getroffen wurde.
+
# Es gibt mindestens eine positive reelle Lösung. Das heißt, dass es eine oder mehrere Möglichkeiten gibt, wie das Projektil abgefeuert werden könnte, so dass es das Ziel irgendwann trifft. Manche dieser Möglichkeiten könnten etwas ungewöhnlich erscheinen, würde man sie in die Tat umsetzen. Der Schütze würde das Geschoss beispielsweise im hohen Bogen auf das Ziel befördern, obwohl es sich direkt vor ihm befindet (eine solche Lösung wäre dann interessant, wenn der direkte Weg zum Ziel durch ein Hindernis versperrt ist). Negative Lösungen sind deswegen uninteressant, da die Lösungen schließlich für den voraussichtlichen Trefferzeitpunkt stehen, und ein negativer Wert würde bedeuten, dass das Ziel in der Vergangenheit getroffen wurde.
  
 
Für unsere Zwecke sind wir daher an der ''kleinsten positiven Lösung'' dieser Gleichung interessiert, denn mit dieser Lösung bleibt dem Ziel die kürzeste Zeit zum Ausweichen.
 
Für unsere Zwecke sind wir daher an der ''kleinsten positiven Lösung'' dieser Gleichung interessiert, denn mit dieser Lösung bleibt dem Ziel die kürzeste Zeit zum Ausweichen.
Zeile 91: Zeile 91:
 
Da wir vorhin bereits den Zeitpunkt des Treffers <math>t_H</math> und auch den Ort <math>\vec p_H</math> berechnet haben, können wir beides in die Gleichung einsetzen und nach <math>\vec d</math> auflösen:
 
Da wir vorhin bereits den Zeitpunkt des Treffers <math>t_H</math> und auch den Ort <math>\vec p_H</math> berechnet haben, können wir beides in die Gleichung einsetzen und nach <math>\vec d</math> auflösen:
  
: <math>\begin{align}
+
: <math>\begin{align} \vec x(t_H) &= \vec p_H \\ \vec d \cdot v_0 \cdot t_H + \tfrac{1}{2} \vec g \cdot {t_H}^2 &= \vec p_H \\ \vec d &= \frac{\vec p_H - \tfrac{1}{2} \vec g \cdot {t_H}^2}{v_0 \cdot t_H} \end{align}</math>
\vec x(t_H) &= \vec p_H \\
+
\vec d \cdot v_0 \cdot t_H + \tfrac{1}{2} \vec g \cdot {t_H}^2 &= \vec p_H \\
+
\vec d &= \frac{\vec p_H - \tfrac{1}{2} \vec g \cdot {t_H}^2}{v_0 \cdot t_H}
+
\end{align}</math>
+
  
 
Mit dem Vektor <math>\vec d</math> kennen wir jetzt die Richtung, in die der Schütze von sich aus gesehen das Geschoss abfeuern muss, um das Ziel (wahrscheinlich) zu treffen. Dieser Vektor ist automatisch normiert, hat also die Länge 1. Da wir bei allen Überlegungen die Position und die Bewegung des Schützen nicht benötigt haben, weil wir mit relativen Positionen und Geschwindigkeiten gearbeitet haben, müssen wir, um den endgültigen ''absoluten'' Bewegungsvektor <math>\vec v_P</math> des Projektils zu erhalten, den Bewegungsvektor <math>\vec v_S</math> des Schützen wieder hinzuaddieren:
 
Mit dem Vektor <math>\vec d</math> kennen wir jetzt die Richtung, in die der Schütze von sich aus gesehen das Geschoss abfeuern muss, um das Ziel (wahrscheinlich) zu treffen. Dieser Vektor ist automatisch normiert, hat also die Länge 1. Da wir bei allen Überlegungen die Position und die Bewegung des Schützen nicht benötigt haben, weil wir mit relativen Positionen und Geschwindigkeiten gearbeitet haben, müssen wir, um den endgültigen ''absoluten'' Bewegungsvektor <math>\vec v_P</math> des Projektils zu erhalten, den Bewegungsvektor <math>\vec v_S</math> des Schützen wieder hinzuaddieren:
Zeile 103: Zeile 99:
 
== Implementierung in C++ ==
 
== Implementierung in C++ ==
  
In der folgenden Beispielimplementierung wird zum Lösen der biquadratischen Gleichung die Funktion <tt>magnet::math::quarticSolve</tt> verwendet, deren Implementierung unter der unten angegebenen Referenz<ref>Marcus Bannerman: [https://www.marcusbannerman.co.uk/index.php/home/42-articles/87-quartic-and-cubic-root-finder-in-c.html ''Quartic and cubic root finder in C++'']<br />Hinweis: Damit der Code in Visual C++ (2010) verwendbar ist, muss an einer Stelle in <tt>cubic.hpp</tt> der Ausdruck <tt>std::sqrt(3)</tt> durch <tt>std::sqrt(3.0)</tt> ersetzt werden. Weiterhin muss in <tt>quartic.hpp</tt> die Datei <tt><nowiki><array></nowiki></tt> anstelle von <tt><nowiki><boost/array.hpp></nowiki></tt> eingebunden werden und dementsprechend <tt>std::array</tt> anstelle von <tt>boost::array</tt> verwendet werden, wenn Boost nicht installiert ist.</ref> zu finden ist. Es wird außerdem davon ausgegangen, dass <tt>Vector</tt> eine Vektorklasse ist, auf der die üblichen Operationen definiert sind. Die statische Methode <tt>dot</tt> muss das Skalarprodukt zweier Vektoren berechnen, die Methode <tt>lengthSq()</tt> das Quadrat der Vektorlänge (das Skalarprodukt mit sich selbst).
+
In der folgenden Beispielimplementierung wird zum Lösen der quartischen Gleichung die Funktion <tt>magnet::math::quarticSolve</tt> verwendet, deren Implementierung unter der unten angegebenen Referenz<ref>[https://github.com/toastedcrumpets/DynamO/blob/master/src/magnet/magnet/math/quartic.hpp ''dynamo - Event driven molecular dynamics simulator'']. Marcus Bannerman. 2011.</ref> zu finden ist. Es wird außerdem davon ausgegangen, dass <tt>Vector</tt> eine Vektorklasse ist, auf der die üblichen Operationen definiert sind. Die statische Methode <tt>dot()</tt> muss das Skalarprodukt zweier Vektoren berechnen, die Methode <tt>lengthSq()</tt> das Quadrat der Vektorlänge (das Skalarprodukt mit sich selbst).
  
 
<sourcecode lang=cpp tab=4>
 
<sourcecode lang=cpp tab=4>
 
/* Parameter:
 
/* Parameter:
 
  * ----------
 
  * ----------
  * shooterPosition: [in] Position des Schützen
+
  * shooterPosition: [in] Position des Schützen
  * shooterVelocity: [in] Bewegungsvektor des Schützen
+
  * shooterVelocity: [in] Bewegungsvektor des Schützen
  * targetPosition:  [in] Position des Ziels
+
  * targetPosition:  [in] Position des Ziels
  * targetVelocity:  [in] Bewegungsvektor des Ziels
+
  * targetVelocity:  [in] Bewegungsvektor des Ziels
  * projectileSpeed: [in] Geschossgeschwindigkeit
+
  * projectileSpeed: [in] Geschossgeschwindigkeit
  * gravity:        [in] Gravitationsvektor
+
  * gravity:        [in] Gravitationsvektor
 
  * outHitPosition:  [out] Position des voraussichtlichen Treffers (absolut)
 
  * outHitPosition:  [out] Position des voraussichtlichen Treffers (absolut)
 
  * outHitTime:      [out] Zeitpunkt des voraussichtlichen Treffers
 
  * outHitTime:      [out] Zeitpunkt des voraussichtlichen Treffers
Zeile 135: Zeile 131:
 
const Vector targetRelVelocity = targetVelocity - shooterVelocity;
 
const Vector targetRelVelocity = targetVelocity - shooterVelocity;
  
// Koeffizienten der biquadratischen Gleichung berechnen.
+
// Koeffizienten der quartischen Gleichung berechnen.
 
const double A = 0.25 * gravity.lengthSq();
 
const double A = 0.25 * gravity.lengthSq();
 
const double B = -Vector::dot(targetRelVelocity, gravity);
 
const double B = -Vector::dot(targetRelVelocity, gravity);
Zeile 197: Zeile 193:
 
Eine Alternative zur direkten Berechnung ist die Verwendung von [http://de.wikipedia.org/wiki/Monte-Carlo-Simulation Monte-Carlo-Simulation]. Dabei könnte man die Bewegung des Ziels probabilistisch modellieren, eventuell sogar "intelligent" auf der Basis vergangener Beobachtungen, und so eine Abschussrichtung mit maximaler Trefferwahrscheinlichkeit finden.
 
Eine Alternative zur direkten Berechnung ist die Verwendung von [http://de.wikipedia.org/wiki/Monte-Carlo-Simulation Monte-Carlo-Simulation]. Dabei könnte man die Bewegung des Ziels probabilistisch modellieren, eventuell sogar "intelligent" auf der Basis vergangener Beobachtungen, und so eine Abschussrichtung mit maximaler Trefferwahrscheinlichkeit finden.
  
== Referenzen ==
+
== Einzelnachweise ==
  
 
<references />
 
<references />

Aktuelle Version vom 28. September 2017, 23:22 Uhr

Klicke hier, um diese Version anzusehen.

Meine Werkzeuge
Namensräume
Varianten
Aktionen
Navigation
Werkzeuge