Bewegung und Abprallen
Partikel per Mausklick auf dem Bildschirm zu positionieren ist schon recht nett, aber nicht abendfüllend. Partikel02 fügt dem Programm eine selbstständige Bewegung der Partikel und deren Abprallen an den Fenstergrenzen hinzu.
Als wesentliche Neuerung in der Klasse Particle (Listing 5 zeigt einen Auszug) kommt ein zweiter Vektor vel hinzu (Zeile 5), der zur Beschreibung der Geschwindigkeit in X- und Y-Richtung dient. Diese setzt der Konstruktor mittels random() auf einen zufälligen Wert zwischen -3 und 3 (Zeile 9).
Listing 5
// Partikel02/Particle.pde
class Particle {
[...]
PVector vel;
[...]
Particle() {
[...]
vel = new PVector(random(-3,3), random(-3,3));
[...]
}
void update() {
pos.add(vel);
if (pos.x + radius > width || pos.x - radius < 0 ) {
vel.x *= -1;
pos.x = constrain(pos.x, radius, width-radius);
}
[...]
}
[...]
}
Neu ist auch die Funktion update(): Sie addiert jeweils den Geschwindigkeitsvektor zur Position (Zeile 14) und sorgt so für Bewegung. Anschließend kontrolliert sie, ob das Partikel die Bande des Programmfensters überschritten hat (Zeile 15), und kehrt in dem Fall die Bewegungsrichtung um (Zeile 16): Das Partikel prallt ab (Abbildung 2). Das Listing realisiert das nur für die X-Richtung, also die seitlichen Fenstergrenzen.

Abbildung 2: In der zweiten Ausbaustufe bewegen sich die Partikel selbstständig und prallen von den Fenstergrenzen ab – hier in einer kolorierten Version.
In den Dateien ParticleSystem.pde und Partikel02.pde ruft draw() nun für alle Partikel nicht nur display() auf, sondern auch update(). Das erledigt wie gehabt eine For-each-Schleife.
Anziehung, Abstoßung, Reibung
Die letzte Ausbaustufe des Programms führt ein weiteres Element ein: Wann immer ein neues Partikel in der Nähe eines bereits vorhandenen Partikels entsteht, spannt sich ein virtuelles Gummiband zwischen beiden und sorgt für Anziehung zwischen den Verbindungspartnern. Andererseits verhindert eine Abstoßungskraft zwischen allen Partikeln, dass sich diese zu nahe kommen. Diese beiden einfachen Regeln bewirken überraschend komplexe Bewegungsmuster.
Das Programm Partikel03 umfasst insgesamt rund 130 Codezeilen und ist ausführlich kommentiert. Um das gewünschte Verhalten zu erreichen, kommen in der Klasse Particle zwei neue Variablen hinzu: fraction beschreibt die Reibung, eine ArrayList namens connectedParticles speichert die Verbindungspartner.
In der update()-Funktion gibt es zwei neue, wesentliche Abschnitte (Listing 6). Der eine berechnet die Anziehung zwischen den Verbindungspartnern, der andere modelliert die Abstoßungskraft zwischen allen Partikeln. Letztlich geht es darum, für jede anziehende (attraction) und abstoßende (repulsion) Paarung einen Vektor zur Partikelgeschwindigkeit zu addieren. Die Geschwindigkeitsänderung resultiert als Summe aus all diesen Einwirkungen. Beide Abschnitte arbeiten mit einer For-each-Schleife. Die erste (Zeile 6) iteriert nur über die Verbindungspartner connectedParticles, die zweite (Zeile 13) über sämtliche Partikel.
Listing 6
// Partikel03/Particle.pde
[...]
void update() {
[...]
// Anziehung zwischen Verbindungspartnern
for (Particle p : connectedParticles) {
PVector distanceVector = pos.copy().sub(p.pos);
PVector attractionVector = distanceVector.mult(-0.005);
vel.add(attractionVector);
}
// Abstoßung zwischen allen Partikeln
for (Particle p : system.particles) {
PVector distanceVector = pos.copy().sub(p.pos);
if (distanceVector.mag() < 4*radius) {
PVector repulsionVector = distanceVector.normalize();
vel.add(repulsionVector);
}
}
[...]
// Reibung
vel.mult(1.0 - fraction);
}
[...]
Im Fall der Anziehung speichert distanceVector die Entfernung zum jeweiligen Partikel als Vektor (Zeile 7), den das Programm dann mit der Konstante -0.005 multipliziert (Zeile 8). Das Ergebnis beschreibt die Geschwindigkeitsänderung in Richtung des Verbindungspartners, den das Programm dem Geschwindigkeitsvektor vel hinzufügt (Zeile 9). Die anziehende Kraft des Gummibandes fällt dabei umso größer aus, je weiter die Verbindungspartner voneinander entfernt sind.
Ähnlich läuft es bei der Abstoßung zwischen sämtlichen Partikeln (Zeile 13). Sie kommt jedoch erst zum Tragen, sobald die Entfernung zum jeweiligen Partikel (distanceVector.mag()) weniger als ein Vierfaches des Partikelradius beträgt (Zeile 15). Zudem sorgt normalize() für eine konstante Abstoßung (Zeile 16).
Da in dieser simulierten Physik die Energieerhaltung nicht gilt, dämpft vel.mult(1.0 - fraction) die Bewegung im System (Zeile 22): Sonst würden uns die Partikel schnell um die Ohren fliegen.
Gummibänder spannen
Die Datei Partikel03.pde bleibt in Version 3 unverändert, da Particle und ParticleSystem alles Notwendige unter sich ausmachen. Es fehlt noch der Code, der Verbindungen zwischen neuen und vorhandenen Partikeln herstellt. Das erledigt ParticleSystem (Listing 7).





