Afișarea animației în termeni de vectori este intuitivă, dar înțelegerea vectorială a matematicii este o durere. În acest tutorial, sper să ușurez acea durere și să ofer o soluție la problemele de animație utilizând o clasă Vector2D personalizată. Vom analiza câteva concepte fundamentale ale cinematicii lineare în abordarea Eulerian: deplasare, viteză și accelerare. Apoi vom construi o aplicație simplă cu ea.
Să aruncăm o privire asupra rezultatului final la care vom lucra. Faceți clic pe panoul Flash aflat mai jos și controlați săgeata apăsând cele patru taste direcționale.
Toate cantitățile vectoriale au două componente: mărime și direcție.
O modificare a cantităților vectoriale se referă la unul dintre aceste cazuri:
Deplasarea, viteza și accelerația sunt cantități vectoriale. Definițiile lor sunt după cum urmează:
Animația de mai jos arată deplasarea pe măsură ce vom implementa mai târziu în Flash.
Viteza este ilustrată de animația de mai jos. Viteza de citire este constantă, ceea ce înseamnă că nu există o accelerație în acest scenariu. Dacă viteza este zero, deplasarea va rămâne constantă pe tot parcursul.
Accelerația este ilustrată de animația de mai jos. Notă: implică cineză constant accelerare. Dacă accelerația se modifică în timp, aceasta se încadrează subiectul dinamică. Dinamica este studiul forțelor care determină accelerația să varieze în timp. O astfel de forță este gravitația, și am scris un post despre animarea asta.
Acum că ați obținut o înțelegere succintă a cantităților cinematice liniare și ați putea să le legați de vectori, putem începe să construim clasa Projectile. Dorim ca proiectilul să capteze toate aceste cantități: deplasare, viteză și accelerare - astfel încât acesta să poată fi manipulat pe fiecare cadru.
Mai jos sunt datele pe care le vom înregistra în clasa noastră de Projectile:
privat var displace: Vector2D; privat var velo: Vector2D; privat var ac: Vector2D;
La inițierea acestei clase de Proiectil, vom inițializa variabilele menționate și vom desena reprezentarea grafică.
funcția publică Projectile () // desena grafica this.draw (); // init toate cantitățile vectorului displace = Vector2D nou (this.x, this.y); velo = Vector2D nou (0, 0); acc = vector2D noi (0, 0); funcția protejată draw (): void // desenarea vârfului vârfului săgeții var: numărul = 30; var lățime: Număr = 60; graphics.beginFill (0x0000FF); graphics.moveTo (0, 0); graphics.lineTo (lățime / -3, înălțime / -2); graphics.lineTo (lățime / 2, 0); graphics.lineTo (lățime / -3, înălțime / 2); graphics.lineTo (0, 0); graphics.endFill ();
Următoarele sunt accesori ai variabilelor noastre private - deplasa
, velo
, acc
- în clasa Projectile.
funcția publică setDisp (mag: Număr, unghi: Număr): void displace.redefine (mag, unghi); funcția publică getDisp (): Vector2D return displace; funcția publică setVelo (mag: Număr, unghi: Număr): void velo.redefine (mag, unghi); funcția publică getVelo (): Vector2D return velo; funcția publică setAcc (mag: număr, unghi: număr): void acc.redefine (mag, unghi); funcția publică getAcc (): Vector2D return acc
La reîmprospătarea fiecărui cadru, trebuie să actualizăm viteza (folosind accelerația) și să actualizăm deplasarea (folosind viteza menționată). Acest lucru se poate realiza utilizând următoarele funcții. Pentru o explicație amănunțită despre adăugarea Vectorului, accesați acest post minunat de la Daniel Sidhon.
funcția publică se aplicăVelo (): void this.displace = this.displace.add (velo); funcția publică applyAcc (): void this.velo = this.velo.add (acc); // actualizați poziția sprite după deplasare. funcția publică animate (): void this.x = this.displace.x; this.y = this.displace.y;
De asemenea, va trebui să actualizăm orientarea Sprite. Acest lucru se poate realiza prin rotație
proprietatea Sprite.
funcția publică (): void this.rotation = Math2.degreeOf (velo.getAngle ());
Am implementat de asemenea a Math2
clasa statică, în care am scris o funcție pentru a converti cu ușurință înainte și înapoi unghiurile de grade și radiani.
funcția publică statică radianOf (deg: Număr): Număr return deg / 180 * Math.PI; gradul funcției statice publiceOf (rad: număr): Număr return rad / Math.PI * 180;
Acum, când am stabilit clasa noastră Proiectil și Math2, putem începe să codificăm clasa noastră principală. Vom avea nevoie și de o clasă Vector2D, deși explicația detaliată nu este inclusă datorită articolului despre vectori mai sus menționat de Daniel Sidhon. Presupun că cititorii înțeleg clasa Vector2D după ce au citit-o. Cu toate acestea, dacă sunt necesare clarificări, solicitați-mi întrebările.
Mai întâi de toate, trebuie să cunoaștem variabilele private din această clasă.
privat var b1: Projectile; // apăsați tasta privată var UP: Boolean = false; privat var DOWN: Boolean = false; private var LEFT: Boolean = false; privat var RIGHT: Boolean = false;
La inițializarea funcției principale init
va fi lansat. Această funcție va crea un nou Proiectil și va stabili viteza inițială. Apoi, vor fi alocate ascultători la evenimente.
funcția privată init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // punct de intrare b1 = proiectil nou (); stage.addChild (b1); // stabilirea vitezei inițiale b1.setVelo (5, Math2.radianOf (30)); // setarea ascultătorilor de evenimente b1.addEventListener (Event.ENTER_FRAME, proj_enterFrame); stage.addEventListener (tastaturăEvent.KEY_DOWN, handle_keyDown); stage.addEventListener (tastaturaEvent.KEY_UP, handle_keyUp);
Am definit controlul utilizatorilor ca tastele cheie ale tastelor săgeți sus, stânga, jos și stânga. La apăsarea și eliberarea acelor chei, variabilele de pavilion din Main (Pasul 11) vor fi transformate în true și false. Pe baza acestor steaguri, cantitățile Vector vor fi manipulate pe fiecare cadru. Notă de asemenea am împărțit comenzile în manipulatoarele axei orizontale și verticale.
funcția privată handle_keyDown (e: KeyboardEvent): void if (e.keyCode == Keyboard.UP) UP = true; altceva dacă (e.keyCode == Keyboard.DOWN) DOWN = true; dacă (e.keyCode == Keyboard.LEFT) LEFT = true; altceva dacă (e.keyCode == Keyboard.RIGHT) DREAPTA = adevărat; funcția privată handle_keyUp (e: KeyboardEvent): void if (e.keyCode == Keyboard.UP) UP = false; altfel dacă (e.keyCode == Keyboard.DOWN) DOWN = false; dacă (e.keyCode == Keyboard.LEFT) LEFT = false; altceva dacă (e.keyCode == Keyboard.RIGHT) RIGHT = false;
După reîmprospătarea fiecărui cadru, va fi executat următorul cod. Este lung, dar nu vă faceți griji; citiți mai departe.
funcția privată proj_enterFrame (e: Event): void // definește accelerația var accMag: Number = 0.1; dacă (UP) b1.setAcc (accMag, Math2.radianOf (-90)); b1.applyAcc (); altfel dacă (DOWN) b1.setAcc (accMag, Math2.radianOf (90)); b1.applyAcc (); dacă (STÂNGA) b1.setAcc (accMag, Math2.radianOf (180)); b1.applyAcc (); altfel dacă (dreapta) b1.setAcc (accMag, Math2.radianOf (0)); b1.applyAcc (); // decelerate ca nu este apăsat pentru a simula frecare. dacă (UP + DOWN + LEFT + RIGHT == 0) var actualVeloMag: Număr = b1.getVelo (). getMagnitude (); var currentVeloAng: Numărul = b1.getVelo (). getAngle (); dacă (actualVeloMag> 1) b1.setAcc (accMag * -1, actualVeloAng); b1.applyAcc (); b1.applyVelo (); // restricționează sprite la marginile scenei b1.getDisp () x = Math2.implementBound (0, stage.stageWidth, b1.getDisp () x); b1.getDisp (), y = Math2.implementBound (0, stage.stageHeight, b1.getDisp () y); b1.animate (); b1.orient ();
Actualizarea mișcării trebuie făcută în următoarea ordine:
Am evidențiat codurile pentru identificarea ușoară a acestor pași.
funcția privată proj_enterFrame (e: Event): void // definește accelerația var accMag: Number = 0.1; dacă (UP) b1.setAcc (accMag, Math2.radianOf (-90)); b1.applyAcc (); altfel dacă (DOWN) b1.setAcc (accMag, Math2.radianOf (90)); b1.applyAcc (); dacă (STÂNGA) b1.setAcc (accMag, Math2.radianOf (180)); b1.applyAcc (); altfel dacă (dreapta) b1.setAcc (accMag, Math2.radianOf (0)); b1.applyAcc (); // decelerate ca nimic nu este presat pentru a simula frecare. dacă (UP + DOWN + LEFT + RIGHT == 0) var actualVeloMag: Număr = b1.getVelo (). getMagnitude (); var currentVeloAng: Numărul = b1.getVelo (). getAngle (); dacă (actualVeloMag> 1) b1.setAcc (accMag * -1, actualVeloAng); b1.applyAcc (); b1.applyVelo (); // restricționează sprite la marginile scenei b1.getDisp () x = Math2.implementBound (0, stage.stageWidth, b1.getDisp () x); b1.getDisp (), y = Math2.implementBound (0, stage.stageHeight, b1.getDisp () y); b1.animate (); b1.orient ();
S-ar putea să observați că există alte funcții între aceste coduri evidențiate. Ce sunt ei? Unul este de a aplica un alt vector pentru a încetini proiectilul nostru, deoarece utilizatorul nu apasă pe nici o tastă. Acest lucru este aplicat înainte de a adăuga viteza la deplasarea noastră.
// decelerate as nohng este apăsat pentru a simula frecare. dacă (UP + DOWN + LEFT + RIGHT == 0) var actualVeloMag: Număr = b1.getVelo (). getMagnitude (); var currentVeloAng: Numărul = b1.getVelo (). getAngle (); dacă (actualVeloMag> 1) b1.setAcc (accMag * -1, actualVeloAng); b1.applyAcc ();
Următoarea este să ne limităm proiectilul să rămână mereu pe scenă, altfel va ieși din ecran. Din nou, implementBound
este o funcție pe care am inclus-o în clasa statică Math2. Având o limită superioară, o limită inferioară și o valoare aleatorie, implementBound
va întoarce o valoare care se încadrează în limitele.
După aplicarea acestor constrângeri asupra deplasării noastre (și numai după aceea), actualizăm poziția Sprite cu această valoare de deplasare.
// restricționează sprite la marginile scenei b1.getDisp () x = Math2.implementBound (0, stage.stageWidth, b1.getDisp () x); b1.getDisp (), y = Math2.implementBound (0, stage.stageHeight, b1.getDisp () y);
Înainte de a lăsa acest sprite așa cum este, ar trebui să orientăm-o astfel încât să puncteze mereu în poziția în care se îndreaptă folosind funcția orienta
.
Acum totul este setat să meargă. Când lansați această piesă apăsând pe Ctrl + Enter, veți vedea o săgeată care încetinește treptat, pe măsură ce merge în diagonală pe ecran. Apăsați pe cele patru taste direcționale pentru a muta săgeata în jur. Nu vă faceți griji că vă veți pierde săgeata; va rămâne în interiorul viziunii dvs..
Acest articol ar trebui să vă familiarizeze cu utilizarea vectorilor pentru a anima mișcarea. După ce ați înțeles cinematica, continuați să citiți pe postul meu despre dinamică. Lasă-mă să știu cum merge. Terima Kasih.