Bällebad mit JavaScript
Eine lustige Sache, die ich noch programmieren wollte, ist ein simuliertes Bällebad. Und das habe ich jetzt einmal gemacht. Es ist ganz lustig geworden, aber die Kollisionserkennung ist nicht perfekt.
Hier ist das Ding:
An sich ist eine Simulation von Bewegung relativ einfach zu programmieren, wenn man sich mit der ersten Ordnung der Differentialgleichungen zufrieden gibt. So braucht man pro Zeitschritt $\delta t$ nur die Geschwindigkeit zu aktualisieren mit $v(t+\delta t) = v(t) + a(t) \cdot \delta t$, und dann noch die zurückgelegte Strecke zu aktualisieren mit $x(t+\delta t) = x(t) + v(t) \cdot \delta t$. Wählt man das $\delta t$ klein genug, dann sieht das hinreichend akzeptabel aus.
Das Problem hierbei sind die Kollisionen. Denn harte Kreisscheiben stehen eigentlich nur in Kontakt, wenn der Abstand der Kreismittelpunkte exakt die Summe der Radien ist. Das ist allerdings in einer Simulation mit endlichen Zeitschritten nie der Fall. Man muss also etwas anderes machen, zum Beispiel einen Schritt zu weit gehen und dann korrigieren. So mache ich das hier, ich bewege alle Kreise und schaue dann, ob irgendwas Überschneidungen hat. Ist das der Fall, simuliere ich eine Kollision.
Man kann die Kollision auf viele Wege parametrisieren. Ich transformiere ins das Schwerpunktsystem und spiegele den Relativimpuls an der Mittelsenkrechten zwischen den Kreismittelpunkten. Das bedeutet im Detail, dass ich zuerst aus den Geschwindigkeiten $v_1$ und $v_2$ Impulse berechne. Die Teilchen bekommen eine Masse nach $m = r^2$ zugewiesen, sodass sie eine alle die gleiche Flächendichte haben. Dann sind die Impulse $p = m v$. Der Gesamtimpuls ist $P = p_1 + p_2$. Der Relativimpuls ist $k = p_1 - p_2$. Den Winkel der Verbindungslinie bekomme ich als $\alpha = \mathrm{atan2}(y_2 - y_1, x_2 - x_1) + \pi/2$. Dann spiegele ich den Vektor $k$ mit einer Spiegelungsmatrix um $\alpha$ und erhalte $k'$. Danach setze ich wieder die neuen Impulse zusammen mit $p_1' = (P + k') / 2$ und $p_2' = (P - k') / 2$. Zuletzt dividiere ich die jeweilige Masse wieder heraus und halte die Geschwindigkeiten.
Problematisch wird es, wenn in einem Zeitschritt drei Kreise überlappen. Dann hängt die Reihenfolge der Auflösung an den Indizes der Kreise, was aber letztlich unphysikalisch ist. Auch habe ich das Problem, dass im nächsten Zeitschritt die Kreise manchmal noch überlappen. Ich erzeuge dann keine weitere Kollision, sondern lasse die Kreise sich erstmal weiter überlappen. Ansonsten führte das zu ganz merkwürdigem Springen.
Mit diesem Ansatz habe ich noch das Problem, dass die Kreise keine statischen Kräfte ausüben können. Somit fallen sie irgendwann alle in sich zusammen, und überlappen am Ende dann doch ständig. Da müsste man also noch deutlich mehr Logik reinstecken, damit das so richtig sinnvoll ist.