Detectarea coliziunii la nivel de pixel pentru grafica transformată

În tutorialul anterior, am trecut prin elementele de bază ale detectării coliziunii la nivel de pixel. În acest tutorial, vom explora utilizarea matricelor în definirea mai bine a zonei de interes - foarte util pentru graficele care au fost rotite, traduse sau înclinate.


Detectarea coliziunii

Aceasta este ultima piesă pe care vom încerca să o progamăm. Faceți clic pe minge și pe cârlig pentru a începe demo-ul interactiv.

Observați cum, în ciuda faptului că graficul arborelui de nucă de cocos se rotește și altfel se transformă, avem încă o detecție a coliziunii pixel-perfectă.


Pasul 1: The a desena Funcţie

Efectuarea detecției de coliziune la nivel de pixel necesită ca grafica să fie exprimată la a BitmapData obiect. Am analizat acest lucru în tutorialul anterior utilizând analogia unui radiograf. În acest tutorial, voi explica acest proces "x-ray".

Să presupunem că avem o bucată de grafică (diagrama 1) și am vrut să o punem la un BitmapData obiect; trebuie să definim dimensiunile BitmapData obiect primul (diagrama 2). În acest caz, este destul de simplu, deoarece graficul este lăţime și înălţime proprietățile oferă acest lucru. Atunci sunăm a desena() metodă; pixelii care sunt cel puțin pe jumătate ocupați de grafic vor fi umpluți, teoretic (diagrama 3). Această gamă de pixeli va fi comparată cu o altă gamă de pixeli dintr-o altă grafică pentru a verifica o coliziune între cele două (diagrama 4).


Pasul 2: Diferite spații de coordonate

Există spații de coordonate diferite utilizate în Flash IDE (diagramele 1 și 2 de mai sus). Sunt sigur că fiecare cititor ar fi experimentat acest lucru - vedeți tutorialul meu pe spațiile afine pentru o privire mai detaliată.

În Flash IDE, tragem o imagine și transformăm-o într-un simbol de tip MovieClip. Când faceți dublu clic pe MovieClip, ajungem la un alt spațiu de coordonate (diagrama 3). De aici, putem face clic pe eticheta de scenă pentru a ieși din spațiul de coordonate local al acestui grafic și ajungem la spațiul de coordonate al stadiului. Apoi putem începe să transformăm instanța lui MovieClip pe scenă (diagrama 4). De fapt, putem crea mai multe instanțe ale MovieClip, fiecare având transformări diferite.

În Bibliotecă, graficul original rămâne neschimbat, în ciuda tuturor modificărilor efectuate asupra copiilor pe scenă. Acest lucru este rațional pentru că de fiecare dată când facem o copie nouă a MovieClip pe scenă, ele sunt întotdeauna aceleași cu cele originale din bibliotecă. Acum, întrebarea este: "Cum Flash captează toate transformările pe care le-am făcut copiilor pe scenă?" Ei bine, ei folosesc fiecare MovieClip.transform.matrix proprietate pentru a capta toate transformările dvs. (traducere, rotire, înclinare, etc).

Acum, să ne întoarcem la locul unde am rămas. Este esențial să înțelegem acest lucru pentru că a desena() Metodă de BitmapData nu se referă la instanța grafică pe scenă atunci când efectuează o "radiografie", ci mai degrabă la sursa grafică neschimbată din bibliotecă.

BitmapData obiectul primul pixel se aliniază cu punctul de înregistrare (punctul roșu) al MovieClip pe spațiul local de coordonate (consultați diagrama 3 din pasul 1), apoi captează graficul în formă de pixeli cu dimensiunile pe care le specificăm.

Cand vine vorba de hitTest verifică, ActionScript aliniază acest prim pixel (pixelul de sus-stânga) al BitmapData obiect cu punctul de înregistrare al instanței grafice pe scenă. Cu aceasta, toți pixelii din BitmapData obiect va fi cartografiat pe spațiul de coordonate de pe scenă și să obțină coordonatele individuale ale acestora. Verificările pot fi executate ulterior prin compararea acestor coordonate între două fișiere bitmaps pentru a vedea dacă se suprapun vreun pixel.

Notă: Această explicație presupune MovieClip sau spiriduș instanța este adăugată la lista de afișare a etapei. În ActionScript, putem adăuga de fapt obiecte de afișare la clasa de documente în sine, deoarece se extinde MovieClip sau spiriduș.


Pasul 3: Problema

Deci, dacă graficul de interes este rotit pe scenă, cum putem face a desena()?

Din diagrama de mai sus, putem vedea clar aceste probleme.

Diagramă Problemă Descriere
1 Dimensiunea BitmapData obiect Deoarece orientarea obiectului sa schimbat, dimensiunea necesară a BitmapData cast nu mai poate fi luată în mod convenabil din lăţime și înălţime proprietățile instanței grafice.
2 Orientarea sursei grafice Exemplul graficului pe scenă este rotit, dar cel din bibliotecă nu este. Trebuie să luăm o imagine a sursei grafice transformate din bibliotecă.
3 Coordonarea pixelului din stânga sus (pixelul de pornire) din BitmapData obiect Nu putem alinia BitmapData primul pixel al obiectului cu punctul de înregistrare al instanței grafice. Acest lucru va fi incorect.

Pasul 4: Soluția

Pentru a rezolva aceste probleme, vom defini mai întâi un dreptunghi legat strâns de instanța grafică rotită pe scenă. Dispozițiile ActionScript pentru acest lucru prin getBounds () funcţie. Aceasta ne va rezolva prima problemă. Observați imaginea de mai jos. Observați că există o diferență între punctul de înregistrare al instanței grafice și cel al dreptunghiului.

Am inclus prezentarea Flash de mai jos pentru a afișa caseta delimitată dreptunghiulară (caseta roșie) și caseta de legare a spațiului local (cutie neagră)


Pasul 5: Transformarea

Apoi vom aduce un instantaneu al sursei grafice transformate în acest dreptunghi pe scenă. Observați imaginea de mai jos.

Începem să avem punctul de înregistrare al sursei grafice aliniat cu cel al zonei dreptunghiulare (diagrama 1). Apoi, rotiți (diagrama 2) și compensați-o (diagrama 3) înainte de a efectua capturarea "imaginii" a imaginii pe BitmapData obiect (diagrama 4).

Putem face acest lucru manual sau alegem să facem o copie a instanței grafice transform.matrix proprietate. Când folosim cea de-a doua abordare, ar trebui să fim atenți să nu folosim transform.matrix traducere proprietatea - în caz contrar, punctele de înregistrare nu se vor alinia după cum vedeți în diagrama 1. În ambele cazuri, va trebui să calculați distanța x și y pentru a compensa.


Pasul 6: Implementarea ActionScript

După această explicație îndelungată, sper că este mai ușor să înțelegem codul. Am subliniat liniile importante și am adăugat comentarii:

 privat Var de nucă de cocos: CTree, hk: Hook; privat var bdat1: BitmapData, bdat2: BitmapData; privat var t1: TextField; privat var angle: Number = 45 priv var coconutBox: dreptunghi; funcția publică Matrix_Bitmap4 () coconut = CTree nou (); addChild (cocos); coconut.rotation = unghi; coconut.x = stage.stageWidth * 0.3; coconut.y = stage.stageHeight * 0.2; coconutBox = coconut.getBounds (acest lucru); // obtineti caseta dreptunghiulara in pasul 2 var coconut_newX: Number = coconut.x - coconutBox.x // sa se depaseasca x la pasul 3 var coconut_newY: Number = coconut.y - coconutBox.y // sa se depaseasca y in pasul 3 var m : Matrice = matrice nouă (); m.rotate (unghi / 180 * Math.PI); // rotiți graficul în pasul 3 // var m: Matrix = coconut.transform.matrix // recomandat dacă au avut loc multe transformări. //m.tx = 0; m.ty = 0; // În acest caz, face același lucru ca și linia precedentă. m.translate (coconut_newX, coconut_newY); // implementați offsetul bdat1 = BitmapData nou (coconutBox.width, coconutBox.width, true, 0x00000000); bdat1.draw (nucă de cocos, m);

De asemenea, să nu uitați să schimbați locația primului pixel (din stânga sus) în BitmapData obiect cu cel al cutiei dreptunghiulare

 verificarea funcției private (e: Event): void var closeEnough: Boolean = coconut.hitTestObject (hk) dacă (closeEnough) // var point1: Point = new Point (coconut.x, coconut.y); // acum că avem o cutie diferită cu locația diferită pentru pixelul de pornire, // ar trebui să ne referim la coconutBox ca punct de pornire var point1: Point = new Point (coconutBox.x, coconutBox.y); var punctul2: Punct = punct nou (hk.x, hk.y); dacă bdat1.hitTest (punctul1, 1, bdat2, punctul2, 1)) t1.text = "Cel puțin un pixel sa ciocnit" altceva t1.text = "Nicio coliziune"

Iată un exemplu al lucrării.


Pasul 7: Actualizare constantă

Dacă forma de interes, în acest caz copacul de nucă de cocos, se transformă în mod constant (rotație, scalare, micșorare, înclinare etc.), atunci BitmapData obiect trebuie să fie actualizat pe fiecare cadru și acest lucru va necesita o prelucrare. De asemenea, rețineți că am optat pentru abordarea alternativă menționată în pasul 4. Iată scriptul pentru actualizarea copiei cu raze X a graficului pentru fiecare cadru:

 funcția privată updateBmp (): void coconutBox = coconut.getBounds (this); // obtineti caseta dreptunghiulara la pasul 2 var coconut_newX: Number = coconut.x - coconutBox.x // sa se depaseasca x la pasul 3 var coconut_newY: Number = coconut.y - coconutBox.y // sa se depaseasca y la pasul 3 // var m: Matrice = Matrice nouă (); //m.rotate(angle / 180 * Math.PI); // rotiți graficul în pasul 3 var m: Matrix = coconut.transform.matrix // recomandat dacă s-a produs o mulțime de transformări, m.tx = 0; m.ty = 0; // pentru acest caz, face același lucru ca linia anterioară. m.translate (coconut_newX, coconut_newY); // implementați offsetul bdat1 = BitmapData nou (coconutBox.width, coconutBox.width, true, 0x00000000); b = Bitmap nou (bdat1); addChild (b); b.x = stadiu.stațiuLățime * 0,3; b.y = stage.stageHeight * 0.2; bdat1.draw (nucă de cocos, m); 

Următoarea funcție este efectuată în fiecare cadru:

 verificarea funcției private (e: Event): void coconut.rotation + = unghiul; // modificări dinamice la execuție coconut.scaleX + = 0.01 var closeEnough: Boolean = coconut.hitTestObject (hk) dacă (closeEnough) updateBmp (); var punct1: Punct = punct nou (coconutBox.x, coconutBox.y); var punctul2: Punct = punct nou (hk.x, hk.y); dacă bdat1.hitTest (punctul1, 1, bdat2, punctul2, 1)) t1.text = "Cel puțin un pixel sa ciocnit" altceva t1.text = "Nicio ciocnire" bdat1.dispose (); 

Și acesta este rezultatul. Începeți să trageți cârligul pentru a vedea animația.


Concluzie

Înțeleg că acest tutorial nu poate fi prea rapid pentru a citi, dar este esențial să înțelegeți clar ce se întâmplă. Sper că acest lucru a fost de ajutor și dacă sunteți interesat să manipulați această matrice 2x2 mai mult, vizitați articolul meu pe această temă. Mulțumiri.

Cod