Hittills har våra kollisionsdetekteringsmetoder lagts matematiskt. Även om det här är till hjälp, finns det fall där det matematiska tillvägagångssättet inte bara är värt det, till exempel med oregelbunden organisk form - beräkningarna är för komplexa och dyra att motivera. Istället kan vi kontrollera varje enskild pixel av formerna. Detta är också ett dyrt tillvägagångssätt, men det kan åtminstone optimeras.
Detta är det sista stycket vi ska försöka skapa. Dra kroken över kokosnötet och notera vad texten längst ner säger.
Anta att vi har två bitmaps och vi vill kolla om de kolliderar, pixel med pixel: vad betyder det? Tja, låt oss anta att båda dina bitmaps är 3x3px, och alla pixlar är fyllda.
Vi gör bokstavligen detta:
Det finns några observationer som jag skulle vilja påpeka.
Observation | Beskrivning |
Överst vänstra bildpunkter | De övre vänstra bildpunkterna för båda bitmapparna används som startpunkt för kontroller. Exempelvis är a1 startpunkten kontrollerad mot alla pixlar i b, som börjar med b1. Båda vänstra bildpunkterna. |
Scan-line progression | Som nämnts i föregående punkt görs kontrollen i ordning av a1, a2, a3 ... a9. Observera hur dessa pixlar är ordnade. |
Gemensamt koordinatutrymme | Antag att båda bilderna läggs till i scenens visningslista. Platsen för varje pixel i båda bitmapparna, i scenens koordinatutrymme, kommer att jämföras för att se om några överlappningar uppstår. |
Dyrt beräkning | För två 3x3 bitmappar krävs högst 9x9 repetitioner. Om min bitmappsstorlek går till 100x100 kan du se hur snabbt den totala beräkningen växer. Om någon kontroll returnerar ett positivt resultat kan resten av kontrollerna avbrytas, eftersom när en pixel överlappar varandra i båda bitmapparna, kan vi säga att en kollision händer mellan bitmapparna |
Nu kan steg 1 tas bokstavligen om alla pixlar är fyllda. Med bitmapgrafik definierar vi ett område med rektangulär dimension. Men inte alla pixlar fylls för att bilda grafiken.
Exemplet nedan visar rätt bitmapp som bara upptar b2, b4, b5, b6 och b8. I det här fallet bör vi kontrollera varje pixel i den vänstra bitmappen (a1, a2, a3 ... a9) mot endast pixlarna b2, b4, b5, b6, b8 i rätt bitmapp.
Nu ger ActionScript oss en annan parameter, alfa
, som definierar pixelns transparens, varvid 0 är helt transparent och 1 är helt ogenomskinlig. För b2, b4, b5, b6, b8 kan vi definiera ett tröskelvärde för alfa
, säg 0,5.
Så antar att b2 och b8 är båda pixlarna med alfa
0,1; Eftersom de är mindre än tröskelvärdet 0,5, anser vi inte att de ska fyllas pixlar och därför inte kontrollera dem. Så i slutändan kontrolleras varje pixel i den vänstra bitmappen (a1, a2, a3 ... a9) mot b4, b5, b6 endast i rätt bitmapp.
I ActionScript kan vi överföra vektorgrafik till BitmapData
instanser. Du kan tänka dig att ActionScript tar en röntgen av en vektorgrafik och överför den till en BitmapData
, som fungerar som den fotografiska filmen.
(Tips: Om du skriver in Flash IDE och sedan exporterar till FlashDevelop så gör jag att du måste se till att dimensionerna för BitmapData
är tillräckligt stora för att innehålla ritningen.)
Här, Ctree
och Krok
är två MovieClip-symboler, ritade i Flash; vi "X-ray" dem för att få en BitmapData-förekomst för varje:
privat var kokosnöt: CTree, hk: Hook; privat var bdat1: BitmapData, bdat2: BitmapData; privat var t1: TextField; allmän funktion Matrix_Bitmap () kokosnöt = ny CTree (); addChild (kokosnöt); coconut.x = stage.stageWidth * 0,3; coconut.y = stage.stageHeight * 0.2; bdat1 = ny BitmapData (150, 150, true, 0x00000000); bdat1.draw (kokosnöt); hk = ny krok (); addChild (hk); bdat2 = ny BitmapData (100, 50, true, 0x00000000); bdat2.draw (hk); hk.addEventListener (MouseEvent.MOUSE_DOWN, start); hk.addEventListener (MouseEvent.MOUSE_UP, slutet); t1 = nytt TextField (); addChild (t1); t1.x = stadium.stageWidth * 0.2; t1.y = stadium.stageHeight * 0,8; t1.width = 300; t1. höjd = 100; stage.addEventListener (Event.ENTER_FRAME, check);
Så efter det börjar vi kontrollerna genom att använda hitTest ()
metod för BitmapData
klass.
På varje bildande ram uppdaterar vi platsen för den övre vänstra pixeln för varje bitmapp innan vi lägger instanser av BitmapData
genom dessa rigorösa hitTest ()
kontroller. Notera också att intervallet för alfa
input här är 0 ~ 255 - dvs det finns inget tröskelvärde. Mer om öppenhet i nästa steg.
privatfunktionskontroll (e: Event): void var punkt1: Punkt = ny punkt (coconut.x, coconut.y); // topp-vänster pixel av träd var punkt2: Punkt = Ny punkt (hk.x, hk.y); // högsta vänster pixel av krok om (bdat1.hitTest (punkt1, 255, bdat2, punkt2, 255)) // kontrollera om några fyllda pixlar överlappar t1.text = "Minst en pixel har kolliderat" annat t1 .text = "Ingen kollision"
Här är ett exempel på produktionen från ActionScript ovan. Klicka på kroken och ta den nära kokosnötträdet och kolla svaret på textrutan. Leka med detta genom att föra änden av kroken nära kanten av kokosnötets löv, för att se om denna kollision är pixelnivåns precision.
Om du har en bild som säger att du gradvis försvinner (blir transparent) kan du berätta ActionScript på vilken nivå av öppenhet du anser vara en pixel som passar för att utföra kollisionskontroller.
Ta exemplet nedan: Det finns flera nivåer av öppenhet på sprite och, som du kan se, sänkas den gradvis till höger. Om vi ställer in transparensnivån till 0,5, anses en pixel med en alfa på 0,5 ~ 1 vara ogenomskinlig och lämpad för kollisionsdetektering. De som är lägre än 0,5 anses vara transparenta. Även när dessa pixlar kolliderar med ett annat objekt, registrerar de inte en riktig kollision.
En annan detalj som jag nämnde just nu är att ActionScript BitmapData
s hitTest funktion alfa
parametervärdet varierar faktiskt från 0 ~ 255. Så vad jag gör är att multiplicera mitt tröskelvärde med 255 för att omvandla intervallet.
privat funktionskontroll (e: Event): void var punkt1: Punkt = ny punkt (bar1.x, bar1.y); var punkt2: Punkt = ny punkt (bar2.x, bar2.y); var tröskelvärde: Number = 255 * 0.5 if (bdat1.hitTest (punkt1, tröskelvärde, bdat2, punkt2, tröskelvärde)) t1.text = "Minst en pixel har kolliderat" else t1.text = "No collision"
Jag har nämnt att kollisionsdetektering på pixelnivå är beräkningsmässigt dyrt. Det betyder att vi bara väljer det när det är absolut nödvändigt. Om två föremål är väldigt långt ifrån varandra är det ingen anledning att använda detta tillvägagångssätt, och en normal kollisionsdetektering av avgränsningsboxen (hitTestObject ()
) ska göra.
Här är idén:
hitTestObject ()
för att se om två objektets gränsvålar har kolliderat.privat funktionskontroll (e: Event): void var closeEnough: Boolean = coconut.hitTestObject (hk) om (closeEnough) var punkt1: Punkt = ny punkt (coconut.x, coconut.y); var punkt2: Punkt = ny punkt (hk.x, hk.y); om (bdat1.hitTest (punkt1, 255, bdat2, punkt2, 255)) t1.text = "Minst en pixel har kolliderat" annars t1.text = "Ingen kollision"
För en fullständig ActionScript-referens, kolla in Matrix_Bitmap3.as
från källans nedladdning.
Tack för läsningen. I nästa Quick Tip använder vi matriser för att omvandla BitmapData
.