Immaginare l'animazione in termini di vettori è intuitiva, ma comprendere la matematica vettoriale è un dolore. In questo tutorial, spero di alleviare quel dolore e di fornire una soluzione ai problemi di animazione usando una classe Vector2D scritta su misura. Vedremo alcuni concetti fondamentali della cinematica lineare nell'approccio Euleriano: spostamento, velocità e accelerazione. Quindi, costruiremo una semplice applicazione con esso.
Diamo un'occhiata al risultato finale su cui lavoreremo. Fai clic sul pannello Flash in basso e controlla la punta della freccia premendo i quattro tasti direzionali.
Tutte le quantità di vettori hanno due componenti: grandezza e direzione.
Una variazione delle quantità di vettori si riferisce a uno di questi casi:
Spostamento, velocità e accelerazione sono quantità vettoriali. Le loro definizioni sono le seguenti:
L'animazione in basso mostra lo spostamento come verrà implementato in Flash in seguito.
La velocità è illustrata dall'animazione sottostante. La velocità nota è costante, il che significa che l'accelerazione è assente in questo scenario. Se la velocità è zero, lo spostamento rimarrà costante per tutto il tempo.
L'accelerazione è illustrata dall'animazione sottostante. Nota: la cinematica implica costante accelerazione. Se l'accelerazione cambia nel tempo, rientra nell'argomento di dinamica. La dinamica è lo studio delle forze che le cause di accelerazione variano nel tempo. Una tale forza è la gravità, e ho scritto un post su come animarlo.
Ora che hai ottenuto una breve comprensione delle grandezze cinematiche lineari e sei in grado di collegarle ai vettori, possiamo iniziare a costruire la nostra classe proiettile. Vorremmo che il proiettile fosse in grado di catturare tutte queste quantità: spostamento, velocità e accelerazione - in modo che possa essere manipolato su ogni fotogramma.
Di seguito sono riportati i dati che registreremo nella nostra classe di proiettili:
private var displace: Vector2D; private var velo: Vector2D; private var acc: Vector2D;
All'inizio di questa classe proiettile, inizializzeremo le variabili citate e disegneremo la sua rappresentazione grafica.
public function Projectile () // disegna la grafica this.draw (); // init all vector quantity displace = new Vector2D (this.x, this.y); velo = new Vector2D (0, 0); acc = new Vector2D (0, 0); funzione protetta draw (): void // che disegna l'altezza var della freccia: Number = 30; var width: Number = 60; graphics.beginFill (0x0000FF); graphics.moveTo (0, 0); graphics.lineTo (larghezza / -3, altezza / -2); graphics.lineTo (width / 2, 0); graphics.lineTo (larghezza / -3, altezza / 2); graphics.lineTo (0, 0); graphics.endFill ();
Di seguito sono accennati alle nostre variabili private - spostare
, velo
, acc
- nella classe proiettile.
funzione pubblica setDisp (mag: Number, angle: Number): void displace.redefine (mag, angle); public function getDisp (): Vector2D return displace; public function setVelo (mag: Number, angle: Number): void velo.redefine (mag, angle); public function getVelo (): Vector2D return velo; public function setAcc (mag: Number, angle: Number): void acc.redefine (mag, angle); funzione pubblica getAcc (): Vector2D return acc
Dopo aver aggiornato ogni frame, è necessario aggiornare la velocità (usando l'accelerazione) e aggiornare lo spostamento (usando la velocità indicata). Questo può essere ottenuto usando le seguenti funzioni. Per una spiegazione approfondita sull'aggiunta di Vector, visita questo fantastico post di Daniel Sidhon.
funzione pubblica applyVelo (): void this.displace = this.displace.add (velo); public function applyAcc (): void this.velo = this.velo.add (acc); // aggiorna la posizione dello sprite per spostamento. public function animate (): void this.x = this.displace.x; this.y = this.displace.y;
Dovremo anche aggiornare l'orientamento dello Sprite. Questo può essere raggiunto attraverso il rotazione
proprietà di Sprite.
public function orient (): void this.rotation = Math2.degreeOf (velo.getAngle ());
Ho anche implementato a math2
classe statica, in cui ho scritto una funzione per convertire facilmente avanti e indietro dalle unità di gradi e radianti dell'angolo.
funzione statica pubblica radianOf (deg: Number): Number return deg / 180 * Math.PI; public static function degreeOf (rad: Number): Number return rad / Math.PI * 180;
Ora che abbiamo stabilito la nostra classe Projectile e Math2, possiamo iniziare a codificare la nostra classe Main. Avremo bisogno anche di una lezione di Vector2D anche se la spiegazione approfondita non è inclusa a causa del summenzionato articolo su Vettori di Daniel Sidhon. Presumo che i lettori capiscano la classe Vector2D dopo averla letta. Tuttavia, se sono necessari chiarimenti, chiedimi le tue domande.
Prima di tutto, abbiamo bisogno di conoscere le variabili private di questa classe.
private var b1: proiettile; // keypress flags private var UP: Boolean = false; private var DOWN: Boolean = false; private var LEFT: Boolean = false; private var RIGHT: Boolean = false;
All'inizializzazione di Main, funzione dentro
sarà lanciato. Questa funzione creerà un nuovo proiettile e stabilirà la sua velocità iniziale. Quindi, verranno assegnati gli ascoltatori agli eventi.
funzione privata init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // entry point b1 = new Projectile (); stage.addChild (b1); // impostazione iniziale velocity b1.setVelo (5, Math2.radianOf (30)); // impostazione dei listener di eventi b1.addEventListener (Event.ENTER_FRAME, proj_enterFrame); stage.addEventListener (KeyboardEvent.KEY_DOWN, handle_keyDown); stage.addEventListener (KeyboardEvent.KEY_UP, handle_keyUp);
Ho definito il controllo utente come tasti premuti dei tasti freccia Su, Sinistra, Giù e Sinistra. Premendo e rilasciando quei tasti, le variabili flag di Main (Step 11) saranno rese vere e false. Sulla base di questi flag, le quantità Vector verranno manipolate su ogni frame. Nota anche che ho diviso i controlli in manipolatori di assi orizzontali e verticali.
funzione privata handle_keyDown (e: KeyboardEvent): void if (e.keyCode == Keyboard.UP) UP = true; else if (e.keyCode == Keyboard.DOWN) DOWN = true; if (e.keyCode == Keyboard.LEFT) LEFT = true; else if (e.keyCode == Keyboard.RIGHT) RIGHT = true; private function handle_keyUp (e: KeyboardEvent): void if (e.keyCode == Keyboard.UP) UP = false; else if (e.keyCode == Keyboard.DOWN) DOWN = false; if (e.keyCode == Keyboard.LEFT) LEFT = false; else if (e.keyCode == Keyboard.RIGHT) RIGHT = false;
All'aggiornamento di ciascun frame verrà eseguito il codice seguente. È lungo, ma non preoccuparti; continua a leggere.
funzione privata proj_enterFrame (e: Event): void // define acceleration var accMag: Number = 0.1; if (UP) b1.setAcc (accMag, Math2.radianOf (-90)); b1.applyAcc (); else if (DOWN) b1.setAcc (accMag, Math2.radianOf (90)); b1.applyAcc (); if (LEFT) b1.setAcc (accMag, Math2.radianOf (180)); b1.applyAcc (); else if (RIGHT) b1.setAcc (accMag, Math2.radianOf (0)); b1.applyAcc (); // decelera quando viene premuto nothng per simulare l'attrito. if (UP + DOWN + LEFT + RIGHT == 0) var currentVeloMag: Number = b1.getVelo (). getMagnitude (); var currentVeloAng: Number = b1.getVelo (). getAngle (); if (currentVeloMag> 1) b1.setAcc (accMag * -1, currentVeloAng); b1.applyAcc (); b1.applyVelo (); // limitazione dello sprite ai bordi dello stage 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 ();
L'aggiornamento del movimento dovrebbe essere eseguito nel seguente ordine:
Ho evidenziato i codici per una facile identificazione di questi passaggi.
funzione privata proj_enterFrame (e: Event): void // define acceleration var accMag: Number = 0.1; if (UP) b1.setAcc (accMag, Math2.radianOf (-90)); b1.applyAcc (); else if (DOWN) b1.setAcc (accMag, Math2.radianOf (90)); b1.applyAcc (); if (LEFT) b1.setAcc (accMag, Math2.radianOf (180)); b1.applyAcc (); else if (RIGHT) b1.setAcc (accMag, Math2.radianOf (0)); b1.applyAcc (); // decelera quando non viene premuto nulla per simulare l'attrito. if (UP + DOWN + LEFT + RIGHT == 0) var currentVeloMag: Number = b1.getVelo (). getMagnitude (); var currentVeloAng: Number = b1.getVelo (). getAngle (); if (currentVeloMag> 1) b1.setAcc (accMag * -1, currentVeloAng); b1.applyAcc (); b1.applyVelo (); // limitazione dello sprite ai bordi dello stage 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 ();
Potresti scoprire che ci sono altre funzioni inserite tra questi codici evidenziati. Quali sono? Uno è quello di applicare un altro vettore per rallentare il nostro proiettile in quanto l'utente non preme alcun tasto. Questo è applicato prima di aggiungere velocità al nostro spostamento.
// decelera quando viene premuto nothng per simulare l'attrito. if (UP + DOWN + LEFT + RIGHT == 0) var currentVeloMag: Number = b1.getVelo (). getMagnitude (); var currentVeloAng: Number = b1.getVelo (). getAngle (); if (currentVeloMag> 1) b1.setAcc (accMag * -1, currentVeloAng); b1.applyAcc ();
Il prossimo è di limitare il nostro proiettile a rimanere sempre sul palco, altrimenti volerà fuori dallo schermo. Ancora, implementBound
è una funzione che ho incluso nella classe statica Math2. Dato un limite superiore, un limite inferiore e un valore casuale, implementBound
restituirà un valore che rientra nei limiti.
Dopo aver applicato questi vincoli sul nostro spostamento (e solo dopo), aggiorniamo la posizione dello Sprite con questo valore di spostamento.
// limitazione dello sprite ai bordi dello stage b1.getDisp (). x = Math2.implementBound (0, stage.stageWidth, b1.getDisp (). x); b1.getDisp (). y = Math2.implementBound (0, stage.stageHeight, b1.getDisp (). y);
Prima di lasciare questo sprite così com'è, dovremmo orientarlo in modo che punti sempre nella posizione in cui sta andando usando la funzione Oriente
.
Ora tutto è pronto per partire. Mentre avvii questo pezzo premendo Ctrl + Invio, vedrai una freccia che rallenta gradualmente mentre scende in diagonale lungo lo schermo. Premere sui quattro tasti direzionali per spostare la freccia. Non preoccuparti di perdere la tua freccia; rimarrà nella tua vista.
Questo articolo dovrebbe familiarizzare con l'utilizzo di vettori per animare il movimento. Una volta che hai capito la cinematica, procedi a leggere il mio post sulla dinamica. Fammi sapere come va. Terima Kasih.