Snabbtips Kollisionsreaktion mellan en cirkel och ett linjesegment

I de tidigare snabba tipsen har vi tittat på kollision upptäckt: i huvudsak att detektera att två former har överlappat. Nu är vi redo att titta på kollision reaktion: att få något att hända på grund av en kollision. I denna Snabba Tips ser vi på reaktionerna i reflektion och glidning.


Slutresultatförhandsvisning

Låt oss titta på det slutresultat som vi kommer att nå i slutet av denna handledning. Varje Flash-demo har en omstartsknapp; klicka på den för att återställa positionen för cirklarna högst upp på scenen.

Den första demo visas reflexion:

Den andra visar glidning:


Steg 1: Reflektionsformeln

Jag har genomgått detta ämne flera rundor med eleverna, och erfarenheten har lärt mig att huvudet på tillvägagångssättet att förklara vektormatematik till freshers resulterar i tomma ansikten och förvirrade sinnen. Så istället för att lägga upp en matteföreläsning här ska jag hänvisa de som är intresserade av att undersöka detta ämne vidare till Wolframs sida om reflektion.

Här ska jag förenkla mina förklaringar med diagram nedan. Återkall vektortillsats:

Nu observera diagrammet nedan. A är cirkelns hastighet före en kollision och A 'är dess hastighet efter kollisionen.

Det är uppenbart att A '= A + 2 V (Ap), var V (Ap) representerar vektorn med en magnitud av Ap, i riktning mot vänster normal. (Du kan se detta genom att följa streckade linjer.)

För att erhålla V (Ap), vi ska projicera A till vänster normal.


Steg 2: Implementering

Här kommer ActionScript-implementeringen av reflektion. Jag har markerat viktiga delar. Linje 67 - 69 är att beräkna V (Ap) (v_leftNormSeg2) och linje 70 implementerar formeln. Du kan referera till hela Actionscript under Reaction1.as.

(Du bör känna igen det mesta av koden från föregående Snabba Tips.)

 Uppdatering av privat funktion (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;  

Steg 3: En interaktiv version

Observera att denna reflektionsformel är tillämplig på linjen av någon gradient. Faktum är att du kan programmera din linje för att vara justerbar vid körning och se den reflekterar cirklar som Flash-presentationen nedan. Klicka bara och dra nära den nedre delen av den för att omdefiniera den.


Steg 4: Glida längs linjen

Konceptet att glida längs linjen är nästan identiskt med reflektion. Observera diagrammet nedan.

Vektoren av bilden är A '= A + V (Ap) med V (Ap) representerar en vektor med storleksordningen enp. Återigen, för att erhålla Ap vi ska projicera A till vänster normal.

Observera att när cirkeln glider längs linjen kolliderar den med linjen. Självklart skiljer sig kollisionspunkter mellan cirklar som kolliderar på linjen, så vissa överlappar linjen när de rör sig längs den. Det ser inte bra ut, så vi måste omplacera dem.


Steg 5: Omdefiniera plats

Låt oss nu omplacera cirklar på linjen samtidigt som deras kontakt med linjen bibehålls. Se diagrammet nedan.

En viktig variabel att beräkna är projiceringen av A längs linjen. Cirkelns radie är lättillgänglig och vi har redan B, så vi kan bilda vektorerna B och C. Att lägga till de två kommer att ge oss A, den exakta platsen för att omplacera cirkeln. Enkel!

Flash-presentationen nedan kodas enligt nämnda idé. Men det finns ett problem: cirklarna jitter längs linjen.

Det finns en sista detalj vi saknade. Diagram ovan visar storleken på C bör motsvara cirkelns radie. Detta kommer dock att placera cirkeln tillbaka ovanför linjen. Eftersom ingen kollision detekteras där kommer cirkeln att falla på linjen igen, vilket i sin tur kommer att flagga kollisionsdetektering och få cirkeln att flyttas om.

Denna cykel kommer att upprepas tills den är förbi slutet av linjesegmentet; Det visuella resultatet av denna cykel är den jitterande effekten.

Lösningen på detta problem är att ställa in storleken på C till något mindre än cirkelns radie: (cirkelradie - 1), säga. Observera Flash-demo nedan som använder den här idén:


Steg 6: Implementering

Så här är det viktiga ActionScript-fragmentet för att glida längs linjen. Jag har markerat viktiga delar.

 Uppdatering av privat funktion (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;   

Slutsats

Hoppas detta är till hjälp. Tack för att du läser. Fråga mig om det finns frågor, och jag får se dig nästa snabba tips.