Rask tips Kollisionsreaksjon mellom en sirkel og et linjesegment

I de forrige hurtigtipsene har vi sett på kollisjon gjenkjenning: I det vesentlige oppdager at to former har overlappet. Nå er vi klare til å se på kollisjon reaksjon: å få noe til å skje på grunn av en kollisjon. I denne Quick Tip ser vi på reaksjonene av refleksjon og glidning.


Endelig resultatforhåndsvisning

La oss se på sluttresultatet vi vil oppnå på slutten av denne opplæringen. Hver Flash-demo har en omstartsknapp; klikk på den for å tilbakestille posisjonen til kretsene øverst i scenen.

Den første demoen viser seg refleksjon:

Den andre viser glide:


Trinn 1: Refleksjon Formel

Jeg har gjennomgått dette emnet flere runder med studenter, og erfaringen har lært meg at hovedveien til å forklare vektormatematikk til freshers resulterer i blanke ansikter og forvirrede sinn. Så i stedet for å sette opp en matteforelesning her, skal jeg referere de som er interessert i å undersøke dette emnet videre til Wolframs side om refleksjon.

Her skal jeg forenkle mine forklaringer med diagrammer nedenfor. Tilbakekall vektortilsetning:

Nå observere diagrammet nedenfor. A er sirkelens hastighet før kollisjon, og A 'er dens hastighet etter kollisjonen.

Det er åpenbart det A '= A + 2 V (Ap), hvor V (Ap) representerer vektoren med en størrelsesorden Ap, i retning av venstre normal. (Du kan se dette ved å følge stiplede linjer.)

For å skaffe V (Ap), vi skal projisere A til venstre normalt.


Trinn 2: Implementering

Her kommer ActionScript-implementeringen av refleksjon. Jeg har fremhevet viktige deler. Linje 67 - 69 er å beregne V (Ap) (v_leftNormSeg2) og linje 70 implementerer formelen. Du kan referere til det fulle Handlingsskriftet under Reaction1.as.

(Du bør gjenkjenne det meste av koden fra forrige hurtigtips.)

 privat funksjon oppdatering (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;  

Trinn 3: En interaktiv versjon

Vær oppmerksom på at denne refleksjonsformelen gjelder for linjer av enhver gradient. Faktisk kan du programmere linjen din for å være justerbar på kjøretid og se den reflekterer sirkler som Flash-presentasjonen nedenfor. Bare klikk og dra nær den nedre enden av den for å omdefinere den.


Trinn 4: Glidende langs linjen

Konseptet med å skyve langs linjen er nesten identisk med refleksjon. Se diagrammet under.

Vektoren av lysbilde er A '= A + V (Ap) med V (Ap) representerer en vektor med størrelsen på ENp. Igjen, for å få Ap vi skal projisere A til venstre normalt.

Merk at når sirkelen glir langs linjen, kolliderer den med linjen. Selvfølgelig varierer kollisjonspunktene mellom sirkler som kolliderer på linje, så noen overlapper linjen mens de beveger seg langs den. Dette ser ikke bra ut, så vi må reposisjonere dem.


Trinn 5: Definer plassering

La oss nå plassere sirkler på linjen samtidig som de holder kontakten med linjen. Se diagrammet under.

En viktig variabel for å beregne er projeksjonen av A langs linje. Radius av sirkel er lett tilgjengelig, og vi har allerede B, slik at vi kan danne vektorer av B og C. Å legge de to vil gi oss A, det nøyaktige stedet for å reposisjonere sirkelen. Enkel!

Flash-presentasjonen nedenfor er kodet i henhold til den nevnte ideen. Men det er ett problem: kretsene jitter langs linjen.

Det er en siste detalj vi savnet. Diagram over viser at størrelsen på C burde være ekvivalent med sirkelens radius. Dette vil imidlertid posisjonere sirkelen tilbake over linjen. Siden det ikke oppdages noen kollisjon der, vil sirkelen falle på linjen igjen, som igjen vil flagg kollisjonsdeteksjonen og føre til at sirkelen blir reposisjonert.

Denne syklusen vil gjenta til den er forbi slutten av linjesegmentet; Det visuelle resultatet av denne syklusen er den jitterende effekten.

Løsningen på dette problemet er å sette størrelsen på C til litt mindre enn sirkelens radius: (radius av sirkel - 1), si. Følg Flash-demoen nedenfor som bruker denne ideen:


Trinn 6: Implementering

Så her er det viktige ActionScript-stykket for å skyve langs linjen. Jeg har fremhevet viktige deler.

 privat funksjon oppdatering (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;   

Konklusjon

Håper dette er nyttig. Takk for at du leste. Spør meg om det er spørsmål, og jeg får se deg neste hurtigtips.