I den tidligere opplæringen gikk vi gjennom det grunnleggende om kollisionsdeteksjon på pikselnivå. I denne opplæringen skal vi undersøke bruken av matriser ved å bedre definere området av interesse - veldig nyttig for grafikk som er blitt rotert, oversatt eller skjev.
Dette er det siste stykket vi vil prøve å progam. Klikk på ballen og krok for å starte den interaktive demoen.
Legg merke til hvordan, til tross for at kokosnøttet grafisk roterer og blir ellers forvandlet, har vi fortsatt pixel-perfekt kollisjonsdeteksjon.
tegne
FunksjonUtførelse av kollisionsdeteksjon på pikselnivå krever at grafikken skal kastes til en BitmapData
gjenstand. Vi har sett på dette i den forrige opplæringen ved å bruke analogi av en røntgenstråle. I denne opplæringen skal jeg forklare denne "røntgen" -prosessen.
Anta at vi har et stykke grafikk (diagram 1) og ønsket å kaste det til en BitmapData
gjenstand; Vi må definere dimensjonene til BitmapData
objekt først (diagram 2). I dette tilfellet er det ganske enkelt fordi grafikken er bredde
og høyde
egenskaper gir dette. Da kaller vi tegne()
metode; Piksler som er minst halvt opptatt av grafikken, fylles opp, teoretisk (diagram 3). Denne mengden piksler vil bli sammenlignet mot enda en rekke piksler fra en annen grafikk for å sjekke for en kollisjon mellom de to (diagram 4).
Det finnes forskjellige koordinatrom som brukes i Flash IDE (diagram 1 og 2 ovenfor). Jeg er sikker på at hver leser ville ha opplevd dette - se min veiledning på affine mellomrom for et mer detaljert utseende.
I Flash IDE tegner vi et bilde og gjør det til et symbol på typen Filmklipp
. Når vi dobbeltklikker på Filmklipp
, vi kommer til en annen koordinatplass (diagram 3). Herfra kan vi klikke på scenenetiketten for å avslutte denne grafikkens lokale koordinatrom og komme til scenens koordinatrom. Da kan vi begynne å forandre forekomsten av Filmklipp
på scenen (diagram 4). Faktisk kan vi opprette flere forekomster av Filmklipp
, hver av dem har forskjellige transformasjoner.
I biblioteket forblir den opprinnelige grafikken uendret til tross for alle tweaksene som er gjort på kopiene på scenen. Dette er rasjonelt fordi når vi lager en ny kopi av en Filmklipp
På scenen er de alltid de samme som den originale kopien i biblioteket. Nå er spørsmålet: "Hvordan fanger Flash hele transformasjonen vi har gjort på kopiene på scenen?" Vel, de bruker hver MovieClip.transform.matrix
eiendom for å fange opp alle dine forvandlinger (oversettelse, rotasjon, skew, etc).
La oss nå falle tilbake til hvor vi sluttet. Det er avgjørende at vi forstår dette fordi tegne()
Metode av BitmapData
refererer ikke til den grafiske forekomsten på scenen når du utfører en "røntgen", men heller til den uendrede grafiske kilden i biblioteket.
De BitmapData
objektets første piksel justeres med registreringspunktet (den røde prikken) til Filmklipp
på det lokale koordinasjonsområdet (se diagram 3 i trinn 1), og fanger deretter grafikken i pikselform med de dimensjonene vi spesifiserer.
Når det gjelder hitTest
sjekker, justerer ActionScript denne første piksel (den øverste venstre piksel) av BitmapData
objekt med registreringspunktet til grafisk forekomst på scenen. Med dette, alle piksler i BitmapData
objektet blir kartlagt på koordinatplassen på scenen og får sine individuelle koordinater. Kontroller kan senere utføres ved å sammenligne disse koordinatene mellom to bitmaps for å se om noen piksler overlapper.
Merk: Denne forklaringen forutsetter Filmklipp
eller Sprite
forekomst legges til scenens visningsliste. I ActionScript kan vi faktisk legge til visningsobjekter i selve dokumentklassen fordi den strekker seg Filmklipp
eller Sprite
.
Så hvis grafikken av interesse er rotert på scenen, hvordan utfører vi det tegne()
?
Fra ovenstående diagram kan vi tydeligvis se disse problemene.
Diagram | Problem | Beskrivelse |
1 | Dimensjonen av BitmapData gjenstand | Siden objektorienteringen har endret seg, er den nødvendige dimensjonen av BitmapData Støpt kan ikke lenger være hensiktsmessig tatt fra bredde og høyde egenskaper av grafisk forekomst. |
2 | Orientering av grafisk kilde | Eksemplet på grafikken på scenen er rotert, men den i biblioteket er det ikke. Vi må ta et øyeblikksbilde av den transformerte grafiske kilden fra biblioteket. |
3 | Koordinere øverste venstre piksel (startpunkt piksel) av BitmapData gjenstand | Vi kan ikke justere BitmapData objektets første piksel med registreringspunktet for grafisk forekomst. Dette vil være feil. |
For å løse disse problemene, vil vi først definere et rektangel som tett begrenser den roterte grafiske forekomsten på scenen. ActionScript-bestemmelser for dette gjennom getBounds ()
funksjon. Dette vil løse vårt første problem. Vær oppmerksom på bildet nedenfor. Legg merke til at det er forskjell mellom det grafiske forekomens registreringspunkt og rektangelets.
Jeg har tatt med Flash-presentasjonen under for å vise den rektangulære grenseboksen (rød boks) og den lokale plassgrenseboksen (svart boks)
Deretter skal vi ta et øyeblikksbilde av den transforriske grafiske kilden inn i dette rektangel på scenen. Vær oppmerksom på bildet nedenfor.
Vi starter med å ha registreringspunktet til grafikkilden på linje med det rektangulære området (diagram 1). Deretter roterer vi (diagram 2) og kompenserer det (diagram 3) før du tar "røntgen" -fangst av bildet på BitmapData
objekt (diagram 4).
Vi kan gjøre dette manuelt, eller velg å lage en kopi av den grafiske forekomsten transform.matrix
eiendom. Når vi bruker den andre tilnærmingen, bør vi være forsiktige med ikke å bruke transform.matrix
oversettelse eiendom - ellers vil registreringspoengene ikke justere slik du ser i diagram 1. I begge tilfeller må vi beregne x- og y-avstanden mot offset.
Etter denne lange forklaringen håper jeg det er lettere å forstå koden. Jeg har fremhevet de viktige linjene og lagt til kommentarer:
privat var kokosnøtt: CTree, hk: Hook; private var bdat1: BitmapData, bdat2: BitmapData; privat var t1: TextField; privat varvinkel: tall = 45 privat var kokosnøkkelbok: rektangel; offentlig funksjon Matrix_Bitmap4 () kokosnøtt = ny CTree (); addChild (kokos); kokosnøtt.rotasjon = vinkel; coconut.x = stage.stageWidth * 0,3; coconut.y = scene.stageHeight * 0.2; coconutBox = coconut.getBounds (dette); // få rektangulær boks i trinn 2 var coconut_newX: Nummer = coconut.x - coconutBox.x // få offset x i trinn 3 var coconut_newY: Nummer = coconut.y - coconutBox.y // få offset y i trinn 3 var m : Matrise = Ny Matrise (); m.rotate (vinkel / 180 * Math.PI); // roter grafikk i trinn 3 // var m: Matrise = coconut.transform.matrix // anbefales dersom mange transformasjoner skjedde. //m.tx = 0; m.ty = 0; // For dette tilfellet gjør det samme jobb som forrige linje. m.translate (coconut_newX, coconut_newY); // implementere offset bdat1 = ny BitmapData (coconutBox.width, coconutBox.width, true, 0x00000000); bdat1.draw (kokosnøtt, m);
Også, for ikke å glemme å endre plasseringen av den første piksel (øverst til venstre) i BitmapData
motsette seg den rektangulære boksen
privat funksjonskontroll (e: Begivenhet): void var closeEnough: Boolean = coconut.hitTestObject (hk) hvis (closeEnough) // var punkt1: Punkt = nytt punkt (coconut.x, coconut.y); // nå at vi har en annen boks med forskjellig plassering for å starte piksel, // vi bør referere til kokosnøkkel som utgangspunktpunktet punkt 1: Punkt = nytt punkt (coconutBox.x, coconutBox.y); var punkt2: Punkt = nytt punkt (hk.x, hk.y); hvis (bdat1.hitTest (punkt1, 1, bdat2, punkt2, 1)) t1.text = "Minst ett piksel har kollidert" annet t1.text = "Ingen kollisjon"
Og her er et eksempel på arbeidet.
Hvis formen av interesse, i dette tilfellet kokosnøttet, forvandles kontinuerlig (roterende, skalering, krymping, skjevhet, osv.), Så BitmapData
objektet må oppdateres på hver ramme, og dette vil ta litt behandling. Vær også oppmerksom på at jeg har valgt alternativ tilnærming nevnt i trinn 4. Her er skriptet for å oppdatere røntgenkopien av grafikken for hver ramme:
privat funksjon updateBmp (): void coconutBox = coconut.getBounds (dette); // få rektangulær boks i trinn 2 var coconut_newX: Nummer = coconut.x - coconutBox.x // få offset x i trinn 3 var coconut_newY: Nummer = coconut.y - coconutBox.y // få offset y i trinn 3 // var m: Matrise = ny Matrix (); //m.rotate(angle / 180 * Math.PI); // roter grafikk i trinn 3 var m: Matrise = coconut.transform.matrix // anbefales dersom mange transformasjoner skjedde, m.tx = 0; m.ty = 0; // for dette tilfellet, gjør det samme jobb som forrige linje. m.translate (coconut_newX, coconut_newY); // implementere offset bdat1 = ny BitmapData (coconutBox.width, coconutBox.width, true, 0x00000000); b = ny Bitmap (bdat1); addChild (b); b.x = scene.stagebredde * 0,3; b.y = stage.stageHeight * 0.2; bdat1.draw (kokosnøtt, m);
Følgende funksjon utføres hver ramme:
privat funksjonskontroll (e: Event): void coconut.rotation + = angle; // dynamiske endringer ved runtime coconut.scaleX + = 0.01 var closeEnough: Boolean = coconut.hitTestObject (hk) hvis (closeEnough) updateBmp (); var punkt1: Punkt = nytt punkt (coconutBox.x, coconutBox.y); var punkt2: Punkt = nytt punkt (hk.x, hk.y); hvis (bdat1.hitTest (punkt1, 1, bdat2, punkt2, 1)) t1.text = "Minst ett piksel har kollidert" annet t1.text = "Ingen kollisjon" bdat1.dispose ();
Og dette er produksjonen. Begynn å dra kroken for å se animasjonen.
Jeg forstår at denne opplæringen kanskje ikke er for rask til å lese, men det er viktig å få en klar forståelse av hva som skjer. Håper dette har vært nyttig, og hvis du er interessert i å manipulere denne 2x2-matrisen mer, kan du gå til artikkelen min om emnet. Takk.