ATAN2 ist eine der unscheinbaren Funktionen, mit der ich auf einmal Probleme gelöst habe, für die ich vorher trickreichen Code geschrieben hatte. Im Kern liefert sie den Winkel zwischen zwei Punkten und kümmert sich dabei um den Quadranten, was ATN(dy/dx) allein nicht tut.
Die Grundformel:
angle = ATAN2(dy, dx)
angle kommt im Bogenmaß raus, also für viele Folgeoperationen direkt brauchbar. Wer Grad will, jagt das Ergebnis durch DEG(). Ein paar Anwendungen, bei denen mir das richtig was gespart hat.
Richtungsvektor zwischen zwei Punkten
Wenn ein Objekt in Richtung eines anderen fliegen soll, ist der Weg fast immer der gleiche: Differenzvektor bilden, daraus den Winkel ableiten, wieder in einen Geschwindigkeitsvektor übersetzen.
dx = target_x - src_x
dy = target_y - src_y
angle = ATAN2(dy, dx)
vx = COS(angle) * speed
vy = SIN(angle) * speed
Klingt nach Umwegen, ist aber nützlich, weil man am Winkel beliebig herumschrauben kann, bevor man wieder in Komponenten zurückrechnet. Genau das brauche ich gleich.
Orthogonal-Vektor durch ±90° drehen
Wenn zwei Objekte zusammenstoßen und etwas seitlich davon abfliegen soll, will ich nicht zwei zufällige Richtungen, sondern Richtungen senkrecht zur Aufprallachse. Mit ATAN2 ist das eine Zeile, plus einmal +90° und einmal -90°:
parent_angle = ATAN2(parent_vy, parent_vx)
angle_a = parent_angle + RAD(90)
angle_b = parent_angle - RAD(90)
Daraus dann wieder die Geschwindigkeitskomponenten. Das ergibt physikalisch glaubwürdige Splittings für Bruchstücke, Reflektionen oder „spawnt rechts/links der Bewegungsrichtung"-Effekte. Ohne ATAN2 müsste man die Drehmatrix selbst aufstellen, was geht, aber unleserlich wird.
Zielen mit randomisierter Streuung
Für eine Gegner-AI, die auf den Spieler zielt, will ich nicht perfektes Tracking. Ein bisschen Streuung pro Schuss macht den Gegner fair und gibt dem Spielgefühl Tiefe. ATAN2 plus eine Zufalls-Abweichung im Winkel ist wieder eine kompakte Lösung:
dx = player_x - enemy_x
dy = player_y - enemy_y
angle = ATAN2(dy, dx) + (RND() - 0.5) * spread
shot_vx = COS(angle) * shot_speed
shot_vy = SIN(angle) * shot_speed
spread ist die Streubreite im Bogenmaß. Wer das pro Spielstand oder pro Gegnertyp variiert, hat sofort eine Schwierigkeitsstellschraube ohne weitere Kosten.
Was bei diesen drei Patterns gleich ist: einmal ATAN2 rechnen, dann am Winkel arbeiten, dann mit COS/SIN zurück in Komponenten. Das ist mathematisch trivial und sieht im Code sofort aus, als hätte man verstanden, was passiert. Genau deshalb mag ich ATAN2 mittlerweile mehr als die meisten anderen Trig-Funktionen.