I min tidligere Quick Tip så vi på ideen om kollisjonsdeteksjon generelt, og spesielt for å oppdage kollisjoner mellom et par sirkler. I denne Quick Tip ser vi på å oppdage en kollisjon mellom en sirkel og en linje.
Dette er resultatet vi skal jobbe med. Klikk på Restart-knappen for å plassere alle sirkler øverst i scenen og se dem falle ned.
Merk at sirklene kolliderer med linjen selv utenfor segmentet som er tegnet. Min neste Quick Tip vil vise hvordan du løser dette.
For å sjekke om en sirkel har kollidert med en linje, må vi sjekke vinkelrett lengde fra linjen til sirkelen. Se diagrammet under.
Det fremgår av diagrammet ovenfor at tilfellene 3 og 4 skal oppdage en kollisjon mellom sirkelen og linjen. Så konkluderer vi at hvis den vinkelrette lengden (markert i rødt) er lik eller mindre enn sirkelens radius, skjedde en kollisjon på grunn av at sirkelen rørte eller overlapper linjen. Spørsmålet er, hvordan beregner vi denne vinkelrett lengden? Vel, vektorer kan bidra til å forenkle vårt problem.
For å tegne en linje på scenen, trenger vi to koordinater (c1 og c2). Linjen trukket fra c1 til c2 vil danne en vektor som peker mot c2 (Merk pilens retning).
Deretter må vi finne linjens normal. Linjens normale er en annen linje som gjør 90 ° med den opprinnelige linjen, og krysser med den på et punkt. Til tross for linjens normale vesen er det enda en linje, normalens vektormannelse kan videre identifiseres som venstre eller Ikke sant normal i forhold til linjens vektor. Venstre normal er linjevektoren selv, rotert -90 °. Riktig normal er den samme, men rotert 90 °. Husk at y-aksen i Flash-koordinatplassen er invertert sammenlignet med y-aksen på en typisk graf - så positiv rotasjon er med klokken og negativ rotasjon er mot klokken.
Venstre normal brukes i vårt forsøk på å beregne vinkelrett lengde mellom sirkelen og linjen. Detaljer finner du i diagrammet under. EN refererer til en vektor peker fra c1 til sirkelen. Den vinkelrette lengden refererer faktisk til vektoren A projeksjon på venstre normal. Vi utlede denne projeksjonen ved å bruke trigonometri: det er | A | Kosinisk (theta)
, hvor | A |
refererer til størrelsen på vektoren EN.
Den enkleste tilnærmingen er å benytte vektordrift, spesielt punktproduktet. Med utgangspunkt i ligningen til prikkproduktet, omarrangerer vi vilkårene slik at vi kommer til det andre uttrykket som vises nedenfor. Legg merke til at høyre side av den andre ligningen er projeksjonen som vi ønsket å beregne!
Vær også oppmerksom på at venstre og høyre side av ligningen vil gi det samme resultatet, selv om det er forskjellig i deres tilnærminger. Så i stedet for å bruke høyre side av ligningen, kan vi velge venstre side av ligningen. For å komme fram til sluttresultatet er det gunstig å bruke venstre fordi variabler enkelt kan løses. Hvis vi insisterer på å bruke likningsretten, må vi skyve ActionScript gjennom rigorisk matematisk arbeid ved beregning av vinkel theta. Vi konkluderer med diagrammet nedenfor.
(* Ytterligere notat: Hvis sirkelen faller under linjevektoren, vil den vinkelrette lengden beregnet ut fra formelen i diagrammet ovenfor gi en negativ verdi.)
Nå som vi har forstått tilnærmingen matematisk, la oss fortsette å implementere den i ActionScript. I denne første delen merker du at linjens vektor blir rotert -90 ° for å danne venstre normal.
// erklære koordinater x1 = 50; y1 = 100; x2 = 250; y2 = 150; // tegning linje grafikk.lineStyle (3); graphics.moveTo (x1, y1); graphics.lineTo (x2, y2) // forming line vectors line = ny Vector2D (x2 - x1, y2 - y1); leftNormal = line.rotate (Math.PI * -0.5);
I denne andre delen har jeg uthevet beregningene nevnt og betingelsen for å sjekke for kollisjon mellom sirkel og linje.
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); circles[i].y += 2; //if collision happened, undo movement if (Math.abs(c1_circle_onNormal) <= circles[i].radius) circles[i].y -= 2;
For de som ønsker å undersøke videre, er følgende utdrag av metoder som brukes i Vector.as
/ ** * Metode for å oppnå projeksjon av gjeldende vektor på en gitt akse * @param-akse En akse hvor vektoren projiseres på * @return Projeksjonslengden av gjeldende vektor på gitt akse * / offentlig funksjonprojeksjonOn (akse: Vector2D): Nummer return this.dotProduct (axis.normalise ())
/ ** * Metode for å utføre prikkprodukt med en annen vektor * @param vector2 En vektor for å utføre prikkprodukt med gjeldende vektor * @return Et skalar antall prikkprodukt * / offentlig funksjon dotProdukt (vektor2: Vector2D): Nummer var komponentX: Nummer = this._vecX * vector2.x; var komponentY: Nummer = this._vecY * vector2.y; returnere komponentX + komponentY;
/ ** * Metode for å få vektorenhet av gjeldende vektor * @return En kopi av normalisert vektor * / offentlig funksjon normaliserer (): Vector2D returner ny Vector2D (this._vecX / this.getMagnitude (), this._vecY / this. getMagnitude ())
/ ** * Metode for å oppnå den nåværende størrelsen på vektor * @return Magnitude of type Antall * / offentlig funksjon getMagnitude (): Nummer return Math.sqrt (_vecX * _vecX + _vecY * _vecY);
Trykk på Restart-knappen for å plassere alle sirkler øverst i scenen. Legg merke til at kollisjonen er mellom hel linje (inkludert delen ikke tegnet) og sirkler. For å begrense kollisjonen til kun linjesegmentet, hold deg innstilt for neste hurtigtips.
Takk for at du leste. Hold deg oppdatert på neste tips.