Quick Tips: Kollisjon Detection Mellom en sirkel og en linje Segment

Quick Tips: Kollisjon Detection Mellom en sirkel og linjesegmenter
to
Del
10
Del

Dette Cyber ​​mandag Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av
Dette innlegget er en del av en serie som heter Collision Detection og Reaction.Quick. Tips: Kollisjon Detection Mellom en sirkel og en LineQuick Tips: Kollisjon reaksjon mellom en sirkel og linjesegmenter

Vi dekket kollisjon deteksjon mellom en uendelig linje og sirkel i vår forrige Quick Tips. Men problemet som oppsto var at linjen strekker seg lenger enn den synlige linjesegment; Faktisk strekker seg inn i et hyperplan. I denne hurtig Tips, skal vi begrense våre dueller som i en linje segment
bare.




Endelig resultat Forhåndsvisning

skal arbeide mot dette resultatet:

Klikk på Restart-knappen for å flytte sirkler på toppen av scenen



Trinn 1:. To tilnærminger

Det er mange fremgangsmåter for å begrense kollisjonsdeteksjon til innenfor et linjesegment. Vi skal se på to tilnærminger denne gangen. Den første tilnærmingen er litt strengere matematisk enn den andre, men disse er begreper som, hvis du forstå vellykket, vil sikkert nytte for deg i fremtiden. Begge tilnærmingene manipulere dot produktets karakteristikk av å være et mål på hvor parallelle to gitte vektorer er.

La oss ta en titt på den første tilnærmingen. Anta A og B er vektorer. Hvis A og B er parallelle med - eller i det minste å peke i samme retning - skalarproduktet mellom A og B vil produsere et positivt tall. Hvis A og B er peker rett overfor hverandre, - eller i det minste som peker i motsatte retninger - skalarproduktet mellom A og B vil produsere et negativt tall. Hvis A og B er ortogonale (danner 90 ° til hverandre) så prikk-produktet vil produsere 0.

I diagrammet nedenfor oppsummerer denne beskrivelsen



Trinn 2:. Relate Dot Product om betingelser

Vi må danne vektorer B og C fra begge ender av linjen segmentet slik at deres dot produkt med linjesegmentet er vektor, A, kan avgjøre om sirkelen er innenfor segmentet.

Følg diagrammet nedenfor. Når sirkelen er innenfor segmentet, da verdien av skalarproduktet mellom A og B er positive og at mellom A og C er negativ.

Diagrammet nedenfor viser hvordan dot produktet endres avhengig av om kretsen er utenfor eller innenfor linjesegment. Legg merke til forskjellen i verdien av prikk-produktet.

Merk også at "innenfor linjesegmentet" ikke betyr at ringen er nødvendigvis kryssende linjesegmentet, bare at det faller innenfor de to tynne linjer på Diagrammet ovenfor.

Så når kollisjon oppstår mellom linje og sirkel, som vi har sett i forrige Quick Tips, må vi undersøke nærmere om sirkelen er plassert innenfor linjen segmentet. Hvis det er, så vet vi sikkert at det er en ekte krysset



Trinn 3:. Implementering

Trinn 2 forklarte konseptet vi bruke til å begrense dueller å være innenfor linjestykke. Men det er fortsatt en feil i presisjon. Du skjønner, det området som defineres er litt på skrå; vi bør sikte på å bruke området definert i henhold til diagrammet nedenfor

Dette er enkelt:. vi bare regne D som den horisontale projeksjon av A. Så, i stedet for å bruke A, vi bruker D til prikk produkt med B og C. Alle forholdene som forklart i trinn 2 fortsatt står, men i stedet for en skråstilt segment, har vi definert et vertikalt område

Denne korreksjonen kan visuelt verdsatt hvis sirkelen er stor.; hvis sirkelen var små, ville dens sentrum være så nær linjen som denne visuelle feilen ville være vanskelig å oppdage, slik at vi kunne komme unna med å bruke det litt på skrå området og spare oss litt prosessorkraft.

Likevel , vil jeg prøve å gjøre ting på den riktige måten. Du kan velge din tilnærming ved å endre tilstanden litt



Trinn 4:. Implementering

Den første Actionbiten her setter opp vektor D (v_line_onX)
//Att2: å få horisontal vectorvar line_onX: Number = line.projectionOn (ny Vector2D (1, 0)); v_line_onX = new Vector2D (1, 0); v_line_onX.setMagnitude (line_onX);

Merk: Vi bruker klasser fra min forrige tutorials her. Vector2D ble introdusert i Gravity in Action, men du trenger ikke å lese at å bruke klassen, det er inkludert i kilde nedlasting.

Den andre Actionbiten her setter opp B (c1_circle) og C (c2_circle ) og sjekker for kollisjonen og om sirkelen er inne segmentet eller ikke
privat funksjon refresh (e: Hendelses): void {for (var i.: int = 0; i < circles.length, jeg ++) { //beregning linjen vinkelrett avstand til ballen Var c1_circle: Vector2D = nye Vector2D (sirkler [i] .x - x1, sirkler [i] .Y - y1); Var c1_circle_onNormal: Number = c1_circle.projectionOn (leftNormal); //Att2: få vektor fra c2 til sirkel Var c2_circle: Vector2D = nye Vector2D (sirkler [i] .x - x2, sirkler [i] .Y - Y2); sirkler [i] .Y + = 2; if (c1_circle_onNormal < = sirkler [i] .radius & & v_line_onX.dotProduct (c1_circle) > 0 & & v_line_onX.dotProduct (c2_circle) < 0) {//hvis kollisjonen skjedde, angre bevegelse sirkler [ ,,,0],i] .Y - = 2; }}}



Trinn 5: Resultat

Her er resultatet for første tilnærming. Klikk på knappen for å tilbakestillinger av alle kretser til toppen av scenen



Trinn 6:. Second Approach

Den andre metoden er mye enklere. Jeg skal prøve å jobbe bakover fra slutten denne gangen.

Følg diagrammet nedenfor. Linjesegmentet er fra c1 til c2. Det er klart at collide1 og collide3 er begge utenfor linjen segmentet, og at bare collide2 er innenfor linjesegmentet.

La v1, v2 og v3 være vektorer fra c1 til respektive kretser. Bare v2 og v3 er parallelle - eller i det minste peker i lignende retninger til linjen vektor (C1 c2). Ved å kontrollere for en positiv verdi i skalarproduktet mellom linjevektor og hver av disse vektorene fra c1 til de tilsvarende sirkel sentre (v1, v2, v3), kan vi lett fastslå at collide1 er utenfor linjestykket. Med andre ord, c1. v1.

Neste, vi skal tenke ut en metode for å fastslå at collide3 er utenfor linjesegmentet. Dette bør være enkelt. Det er tydelig at v3 projeksjon langs linjen vektor vil overstige lengden på linjesegmentet. Vi skal bruke denne egenskapen for å luke ut collide3

Så la meg oppsummere den andre tilnærmingen..

  • Først sjekker vi for et skjæringspunkt mellom den uendelige linjen og sirkelen

    Hvis det er et kryss, videre undersøke følgende for å finne ut om det skjer innenfor linjen segment:

    Kontroller at en positiv verdi produseres når vi tar skalarproduktet av vektoren fra c1 til sirkel og linjen vektor, og Selge
    Kontroller at omfanget av projeksjonen av vektoren langs linjen vektoren er kortere enn linjesegmentet lengde.


    Trinn 7: Gjennomføring

    Her er den Action gjennomføringen av ovenstående:
    privat funksjon refresh (e: Hendelses): void {for (var i: int = 0; i < circles.length, jeg ++ ) {//beregning linjen vinkelrett avstand til ballen Var c1_circle: Vector2D = nye Vector2D (sirkler [i] .x - x1, sirkler [i] .Y - y1); Var c1_circle_onNormal: Number = c1_circle.projectionOn (leftNormal); //Att2: å få den aktuelle vektorer Var c1_circle_onLine: Number = c1_circle.projectionOn (linje); sirkler [i] .Y + = 2; if (Math.abs (c1_circle_onNormal) < = sirkler [i] .radius & & line.dotProduct (c1_circle) > 0 & & c1_circle_onLine < line.getMagnitude ()) {//hvis kollisjonen skjedde, angre bevegelse sirkler [i] .Y - = 2; }}}



    Trinn 8: Resultat

    I hovedsak vil det gi samme resultat som forrige, men siden det er et par linjer med kode kortere i andre tilnærmingen, tror jeg det er bedre .

    Konklusjon

    Håper dette har hjulpet. Takk for lesing. Neste opp, vil vi se på kollisjons reaksjon. Anmeldelser