|
Prof.
Urban |
![]() |
![]() |
||
Nun wollen wir unsere Bälle am Rand des Fensters reflektieren. Vorerst soll das Programm nur einen Ball mit Spur anzeigen, um alles genau sehen zu können. Ein flexibles Grundgerüst könnte so aussehen:
// Bunte Bälle bewegen sich // Reflexion an den Wänden int ANZAHL = 1;
Ball[] balls; void setup() { size(200,200); balls = new Ball[ANZAHL]; for (int i=0; i<ANZAHL; i++) balls[i] = new Ball(i); frameRate(10); smooth(); background(0); } void draw() { fill(0,16); rect(0,0,width,height); for (int i=0; i<ANZAHL; i++) balls[i].move(); for (int i=0; i<ANZAHL; i++) balls[i].paint(); } //////////////////////////////////////////////////////////// // class Ball { float x,y; // Ort float vx,vy; // Geschwindigkeit float r; // Radius color col; // Farbe Ball(int number) { x = width/2.0; y = height/2.0; vx = 17; vy = 11; r = 20; colorMode(HSB); col = color(0,255,255); paint(); } // das Ballobjekt zeichnen void paint() { noStroke(); fill(col); ellipseMode(RADIUS); ellipse(x,y,r,r); } // den Ball bewegen void move() { // falls Wand überschritten, Richtung ändern } } // ////////////////////////////////////////////////////////////
Was bedeutet etwa eine Reflexion an der linken Wand? Der Vektor ( vx / vy ) muss in die umgekehrte waagrechte Richtung zeigen, also zu ( -vx / vy ) werden. An der rechten Wand gilt das Gleiche, oben und unten wird ( vx / -vy ) gewählt.
Den neuen Ort des Balls müssen wir noch festlegen. Einfach stehenlassen wollen wir ihn nicht, das wäre vermutlich erkennbar. Lassen wir ihn einfach sofort umkehren. Dadurch ist zwar der Ort der Reflexion nicht korrekt berechnet, doch die Bewegung bleibt flüssig.
Das ist unsere neue Methode move():
// den Ball bewegen
void move() {
// falls Wand überschritten, Richtung ändern
if (x+vx<r || x+vx>=width-r) vx = -vx;
if (y+vy<r || y+vy>=height-r) vy = -vy;
// neue Position
x = x+vx;
y = y+vy;
}
Einen offensichtlichen Nachteil hat unser Algorithmus - durch die zu frühe Reflexion (wir kehren ja bereits vor der tatsächlichen Wandberührung um) erreicht der Ball die Wand meist nicht. Es bleibt eine Lücke frei. Diese ist allerdings nur dann erkennbar, wenn der Ball zwischen zwei Frames seinen Platz deutlich ändert, die Verschiebung also deutlich größer als ein Pixel ist. Abhilfe: mehr fps und kleinerer Vektor.
Liest man Programme aus dem Internet, so wird oft eine andere Technik verwendet. Statt den Ball über die Grenze laufen zu lassen, setzt man seine Koordinate einfach auf den letzten möglichen Wert. Der Geschwindigkeitsvektor wird wie oben gespiegelt. Die Programmierung ist problemlos - wir berechnen den neuen Ort und passen wenn nöttig die richtige Koordinate an.
// den Ball bewegen
void move() {
x = x+vx;
y = y+vy;
// falls Wand überschritten, Richtung ändern
// und Ort anpassen
if (x+vx<r) {
vx = -vx ;
x = r;
}
if (x+vx>=width-r) {
vx = -vx ;
x = width-r-1;
}
if (y+vy<r) {
vy = -vy;
y = r;
}
if (y+vy>=height-r) {
vy = -vy;
y = height-r-1;
}
}
This browser does not have a Java Plug-in.
Get the latest Java Plug-in here.
Der freie Randbereich tritt nun nicht mehr auf. Allerdings ergibt die Verschiebung der Koordinate auf den Randwert ein ungleichmäßiges Bild. Diese eine Position sieht erkennbar falsch aus. Allerdings ist der Fehler bei kleinen Verschiebungen klein und fällt nicht mehr so stark auf, der Sprung fällt nicht mehr auf.
Man könnte aber auch die exakte neue Position berechnen. Aus irgendwelchen Gründen wird dies aber nur selten programmiert. Wie berechnet man den richtigen Punkt für den nächsten Frame?
Erste Möglichkeit: Du fragst Deinen Mathematiklehrer
Er wird Dich an die Vektorrechnung erinnern, und dass die Bahn des Balls auf der Gerade x = (x/y) + t(vx/vy) verläuft. Schneidest Du diese Gerade mit der Geraden, die die Wand darstellt (links etwa x = r ), so erhältst Du ein T, das dem Berührpunkt entspricht. Nun musst Du nur noch dessen Koordinaten finden und den über den Rand reichenden Vektor (Anteil 1-T) gespiegelt dazuzählen. Klingt kompliziert, ist problemlos zu rechnen aber langweilig, liefert ein einfaches Resultat.
Zweite Möglichkeit: Du fragst Deinen Physiklehrer
Er wird als Beispiel die linke Wand nehmen und Dich darauf hinweisen, dass sich der neue Ort ergibt, wenn Du Dir den Ball vom hinter die Wand gespiegelten alten Ort kommend denkst. Wie spiegelt man eine Zahl z an einer Zahl D? Man nimmt den Vektor von der Wand zu z, das ist z-D. Dieser wird umgeklappt (D-z) und bei D angestückelt. Damit ist das Resultat sofort klar mit 2D-z. Fertig. Ein Ausschnitt aus dem neuen move():
if (x<r) {
vx = -vx;
x = 2*r-x; // r - (x-r)
y = y + dy;
if (x>=width-r) {
vx = -vx;
x = 2*(width-r)-x;
y = y + dy;
This browser does not have a Java Plug-in.
Get the latest Java Plug-in here.
Download Source: Reflect_exakt
Hier stimmt nun alles. Kommt der Ball immer bis zur Wand? Nein - weil der Anprall im Allgemeinen ja zwischen zwei Frame-Anzeigen passiert. Aber im Unterschied zum ersten Algorithmus ist der Ort der Reflexion korrekt, im Unterschied zum zweiten die Geschwindigkeit.
Ergänze das Programm um Einstellungen zur Transparenz und wähle geeignete Farben
This browser does not have a Java Plug-in.
Get the latest Java Plug-in here.
Download Source : Reflect_exakt_ART
Um vollflächige Bilder mit Spuren zu erhalten. wählst Du nicht die Reflexion am Rand des Balles, sondern am Mittelpunkt. Das ist zwar physikalisch falsch, gibt aber einen randfreien künstlerisch stimmigen Bildausschnitt.