Î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.
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ă.
a desena
FuncţieEfectuarea 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).
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ș
.
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. |
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ă)
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.
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.
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.
Î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.