Schneller Tipp Kollisionsreaktion zwischen einem Kreis und einem Liniensegment

In den vorherigen Schnelltipps haben wir uns die Kollision angesehen Erkennung: im Wesentlichen das Erkennen, dass sich zwei Formen überlappen. Jetzt sind wir bereit, die Kollision zu betrachten Reaktion: etwas wegen einer Kollision passieren lassen. In diesem Quick Tip werden die Reaktionen von Reflexion und Rutschen betrachtet.


Endergebnisvorschau

Schauen wir uns das Endergebnis an, das wir am Ende dieses Tutorials erzielen werden. Jede Flash-Demo verfügt über einen Neustart-Button. Klicken Sie darauf, um die Position der Kreise oben auf der Bühne zurückzusetzen.

Die erste Demo zeigt Reflexion:

Die zweite zeigt gleiten:


Schritt 1: Die Reflexionsformel

Ich habe dieses Thema mehrere Male mit Schülern durchgearbeitet, und die Erfahrung hat mir gezeigt, dass der direkte Ansatz, Vektor-Mathematik für Neulinge zu erklären, zu leeren Gesichtern und verwirrten Köpfen führt. Anstatt hier einen Mathe-Vortrag zu halten, werde ich diejenigen, die an einer Untersuchung dieses Themas interessiert sind, auf Wolframs Seite zum Nachdenken verweisen.

Hier werde ich meine Erklärungen anhand der folgenden Diagramme vereinfachen. Rückrufvektoraddition:

Beachten Sie nun das folgende Diagramm. A ist die Geschwindigkeit des Kreises vor einer Kollision und A 'ist seine Geschwindigkeit nach der Kollision.

Es ist klar, dass A '= A + 2 V (Ap), woher V (Ap) repräsentiert den Vektor mit einer Stärke von Ap, in Richtung der linken Normalen. (Sie können dies anhand der gestrichelten Linien erkennen.)

Um zu erhalten V (Ap), wir projizieren A auf die linke Normalität.


Schritt 2: Implementierung

Hier kommt die ActionScript-Implementierung von Reflection. Ich habe die wichtigen Teile hervorgehoben. Zeile 67 - 69 ist zu berechnen V (Ap) (v_leftNormSeg2) und Zeile 70 implementiert die Formel. Sie können auf das vollständige Actionscript unter verweisen Reaktion1.as.

(Sie sollten den größten Teil des Codes aus dem vorherigen Quick Tip erkennen.)

 private Funktionsaktualisierung (e: Event): void for (var i: int = 0; i < circles.length; i++)  //calculating line's perpendicular distance to ball var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1); var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal); var c1_circle_onLine:Number = c1_circle.projectionOn(line); //if collision happened, undo movement if (Math.abs(c1_circle_onNormal) <= circles[i].radius && line.dotProduct(c1_circle) > 0 && c1_circle_onLine < line.getMagnitude()) //redefine velocity var v_leftNormSeg2:Vector2D = leftNormal.clone(); var leftNormSeg2_mag:Number = Math.abs(velos[i].projectionOn(leftNormal)) v_leftNormSeg2.setMagnitude(leftNormSeg2_mag); velos[i] = velos[i].add(v_leftNormSeg2.multiply(2));  circles[i].x += velos[i].x; circles[i].y += velos[i].y;  

Schritt 3: Eine interaktive Version

Beachten Sie, dass diese Reflexionsformel auf die Linie eines Farbverlaufs anwendbar ist. Tatsächlich können Sie Ihre Leitung so programmieren, dass sie zur Laufzeit einstellbar ist und Kreise wie die unten dargestellte Flash-Präsentation reflektiert. Klicken Sie einfach darauf und ziehen Sie es in die Nähe des unteren Endes, um es neu zu definieren.


Schritt 4: Linie entlang gleiten

Das Konzept des Gleitens entlang der Linie ist fast identisch mit der Reflexion. Beachten Sie das folgende Diagramm.

Der Vektor der Folie ist A '= A + V (Ap) mit V (Ap) Darstellung eines Vektors mit der Größe von EINp. Um wieder A zu erhaltenp wir projizieren A auf die linke Normalität.

Beachten Sie, dass der Kreis entlang der Linie gleitet und mit der Linie kollidiert. Natürlich unterscheiden sich die Kollisionspunkte zwischen Kreisen, die auf einer Linie kollidieren. Daher überlappen manche die Linie, wenn sie sich entlang der Linie bewegen. Das sieht nicht gut aus, also müssen wir sie neu positionieren.


Schritt 5: Standort neu definieren

Lassen Sie uns Kreise auf der Linie neu positionieren, während Sie den Kontakt mit der Linie beibehalten. Siehe das folgende Diagramm.

Eine wichtige zu berechnende Variable ist die Projektion von A entlang der Linie. Der Radius des Kreises ist leicht verfügbar, und wir haben bereits B, sodass wir die Vektoren von B und C bilden können. Wenn Sie die beiden hinzufügen, erhalten Sie A, die genaue Position, um den Kreis neu zu positionieren. Einfach!

Die folgende Flash-Präsentation ist gemäß der genannten Idee codiert. Es gibt jedoch ein Problem: Die Kreise ruckeln entlang der Linie.

Wir haben ein letztes Detail vermisst. Das Diagramm oben zeigt, dass die Größe von C dem Radius des Kreises entsprechen sollte. Dadurch wird der Kreis jedoch wieder oberhalb der Linie positioniert. Da dort keine Kollision erkannt wird, fällt der Kreis wieder auf die Linie, was wiederum die Kollisionserkennung markiert und die Neupositionierung des Kreises bewirkt.

Dieser Zyklus wird so lange wiederholt, bis das Ende des Liniensegments überschritten ist. Das visuelle Ergebnis dieses Zyklus ist der Jitter-Effekt.

Die Lösung für dieses Problem besteht darin, die Größe von C etwas unter dem Kreisradius zu setzen: (Kreisradius - 1), sagen. Beachten Sie die Flash-Demo, die diese Idee verwendet:


Schritt 6: Implementierung

Hier ist also das wichtige ActionScript-Snippet zum Gleiten entlang der Linie. Ich habe die wichtigen Teile hervorgehoben.

 private Funktionsaktualisierung (e: Event): void for (var i: int = 0; i < circles.length; i++)  //calculating line's perpendicular distance to ball var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1); var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal); var c1_circle_onLine:Number = c1_circle.projectionOn(line); //check for collision if (Math.abs(c1_circle_onNormal) <= circles[i].radius) //check if within segment //if within segment, reposition and recalculate velocity if (line.dotProduct(c1_circle) > 0 && c1_circle_onLine < line.getMagnitude())  //repostion circle var v_lineSeg:Vector2D = line.clone(); v_lineSeg.setMagnitude(c1_circle_onLine); var v_leftNormSeg1:Vector2D = leftNormal.clone(); v_leftNormSeg1.setMagnitude(circles[i].radius - 1); //v_leftNormSeg1.setMagnitude(circles[i].radius); //uncomment this to check out the error: jittering effect var reposition:Vector2D = v_lineSeg.add(v_leftNormSeg1) circles[i].x = x1+reposition.x; circles[i].y = y1+reposition.y; //redefine velocity var v_leftNormSeg2:Vector2D = leftNormal.clone(); var leftNormSeg2_mag:Number = Math.abs(velos[i].projectionOn(leftNormal)) v_leftNormSeg2.setMagnitude(leftNormSeg2_mag); var veloAlongLine:Vector2D = velos[i].add(v_leftNormSeg2); circles[i].x += veloAlongLine.x; circles[i].y += veloAlongLine.y;  //if not in segment (e.g. slide out of segment), continue to fall down else  circles[i].x += velos[i].x; circles[i].y += velos[i].y;   //No collision in the first place, fall down else  circles[i].x += velos[i].x; circles[i].y += velos[i].y;   

Fazit

Hoffe das ist hilfreich. Danke fürs Lesen. Fragen Sie mich, wenn Fragen auftauchen, und wir sehen uns als nächster Tipp.