Aflați mai multe despre kinematica liniară

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.


Rezultatul final al rezultatelor

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.


Pasul 1: Cantitatea vectorului

Toate cantitățile vectoriale au două componente: mărime și direcție.


Pasul 2: Modificarea cantității vectoriale

O modificare a cantităților vectoriale se referă la unul dintre aceste cazuri:

  1. Schimbarea direcției
  2. Schimbarea amplorii
  3. Schimbați atât amploarea cât și direcția

Pasul 3: Deplasarea ca o cantitate vectorică

Deplasarea, viteza și accelerația sunt cantități vectoriale. Definițiile lor sunt după cum urmează:

  • Displacement - Vectorul celei mai scurte căi care indică originea în destinație. Definim originea ca punct (0, 0) și destinație ca locația particulei față de acest punct. Practic, se referă la sistemul de coordonate carteziene implementat de Flash.
  • Viteza - Viteza este schimbarea deplasării în timp.
  • Accelerare - accelerarea este schimbarea vitezei în timp.

Animația de mai jos arată deplasarea pe măsură ce vom implementa mai târziu în Flash.


Pasul 4: Viteza ca o cantitate vectorică

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.


Pasul 5: Accelerația ca o cantitate vectorică

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.


Pasul 6: Începeți să construiți un proiectil

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;

Pasul 7: Inițializați proiectilul

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 (); 

Pasul 8: Accesorii pentru cantitățile vectoriale

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

Pasul 9: actualizatori de cantități vectoriale

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; 

Pasul 10: Actualizarea orientării Sprite

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; 

Pasul 11: Clasa principală

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;

Pasul 12: Inițializarea principalului

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); 

Pasul 13: Ascultători de evenimente de la tastatură

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; 

Pasul 14: Ascultători de evenimente EnterFrame

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 (); 

Pasul 15: Actualizați mișcarea

Actualizarea mișcării trebuie făcută în următoarea ordine:

  1. Definiți o nouă accelerare în funcție de apăsarea de taste a utilizatorului.
  2. Folosind accelerația, actualizați viteza curentului.
  3. Folosind viteza curentului, actualizați deplasarea curentă.
  4. Rafinați deplasarea pentru a păstra obiectul în interiorul limitelor.

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 (); 

Pasul 16: Încetinirea mișcării

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 (); 

Pasul 17: Stai înăuntru

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);

Pasul 18: Orient Sprite

Î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.


Pasul 19: Obțineți Set și Du-te!

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..


Concluzie

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.

Cod