Lär dig om linjär kinematik

Att visa animering i vektorer är intuitiv, men att förstå vektormatematiken är en smärta. I denna handledning hoppas jag kunna lindra den smärtan och ge en lösning på animationsproblem med hjälp av en anpassad skriftlig Vector2D-klass. Vi kommer att titta på några grundläggande begrepp linjära kinematik i Eulerian-metoden: Förskjutning, hastighet och acceleration. Då bygger vi en enkel applikation med den.


Slutresultatförhandsvisning

Låt oss ta en titt på det slutliga resultatet vi kommer att arbeta för. Klicka på Flash-panelen nedan och styra pilhuvudet genom att trycka på de fyra riktknapparna.


Steg 1: Vektormängd

Alla vektormängder har två komponenter: storlek och riktning.


Steg 2: Förändring i vektormängd

En förändring i vektormängder hänför sig till ett av dessa fall:

  1. Ändring i riktning
  2. Ändring i storlek
  3. Ändra i både storlek och riktning

Steg 3: Förskjutning som en vektormängd

Förskjutning, hastighet och acceleration är vektormängder. Deras definitioner är följande:

  • Förskjutning - Vektor av den kortaste vägen som pekar från ursprung till destination. Jag definierar ursprung som punkt (0, 0) och destination som partikelns placering i förhållande till denna punkt. I grund och botten hänvisar det till det kartesiska koordinatsystemet som implementeras av Flash.
  • Hastighet - Hastighet är förändringen av förskjutning över tiden.
  • Acceleration - Acceleration är hastighetsförändringen över tiden.

Animationen nedan visar förskjutning som vi ska implementera i Flash senare.


Steg 4: Hastighet som en vektormängd

Hastighet illustreras av animeringen nedan. Nothastigheten är konstant, vilket innebär att acceleration saknas i detta scenario. Om hastigheten är noll, förblir förskjutningen konstant hela tiden.


Steg 5: Acceleration som en vektormängd

Accelerationen illustreras av animeringen nedan. Obs: kinematik innebär konstant acceleration. Om accelerationen förändras över tiden faller den under ämnet dynamik. Dynamik är studien av krafter som orsakar acceleration att variera över tiden. En sådan kraft är gravitation, och jag har skrivit ett inlägg på att animera det.


Steg 6: Börja bygga en projektil

Nu när du har fått en kort förståelse av linjära kinematikmängder och kan relatera till vektorer, kan vi börja bygga vår Projectile-klass. Vi vill att projektilen kan fånga alla dessa kvantiteter: Förskjutning, hastighet och acceleration - så att den kan manipuleras på varje ram.

Nedan är de data vi ska registrera i vår projektil klass:

 privat var förskjutna: Vector2D; privat var velo: Vector2D; privat var acc: Vector2D;

Steg 7: Initiera projektil

Vid initiering av denna projektilklass ska vi initiera de nämnda variablerna och rita dess grafiska representation.

 offentlig funktion Projectile () // draw graphics this.draw (); // init alla vektormängder förskjutna = ny vektor2D (this.x, this.y); velo = ny vektor2D (0, 0); acc = ny vektor2D (0, 0);  skyddad funktion teckning (): void // ritning pilhuvud var höjd: Number = 30; var bredd: nummer = 60; graphics.beginFill (0x0000FF); graphics.moveTo (0, 0); graphics.lineTo (bredd / -3, höjd / -2); graphics.lineTo (bredd / 2, 0); graphics.lineTo (bredd / -3, höjd / 2); graphics.lineTo (0, 0); graphics.endFill (); 

Steg 8: Accessorer av vektormängder

Följande är accessorer till våra privata variabler - förflytta, velo, acc - i Projectile-klassen.

 allmän funktion setDisp (mag: Nummer, vinkel: Nummer): tomrum displace.redefine (mag, vinkel);  offentlig funktion getDisp (): Vector2D return displace;  public function setVelo (mag: Number, angle: Number): void velo.redefine (mag, vinkel);  offentlig funktion getVelo (): Vector2D return velo;  allmän funktion setAcc (mag: Nummer, vinkel: Nummer): void acc.redefine (mag, vinkel);  offentlig funktion getAcc (): Vector2D return acc

Steg 9: Uppdaterare av vektormängder

Vid uppfriskande varje ram behöver vi uppdatera hastigheten (med acceleration) och uppdatera förskjutningen (med hjälp av hastigheten). Detta kan uppnås med följande funktioner. För en grundlig förklaring om Vector-tillägg, besök denna stora posten från Daniel Sidhon.

 offentlig funktion applyVelo (): void this.displace = this.displace.add (velo);  offentlig funktion applyAcc (): void this.velo = this.velo.add (acc);  // uppdatera sprite position genom förskjutning. allmän funktion animera (): void this.x = this.displace.x; this.y = this.displace.y; 

Steg 10: Uppdatering för Sprite s Orientation

Vi kommer också att behöva uppdatera orienteringen av Sprite. Detta kan uppnås genom rotation egenskap av Sprite.

 public function orient (): void this.rotation = Math2.degreeOf (velo.getAngle ()); 

Jag har också implementerat en Math2 statisk klass, där jag har skrivit en funktion för att enkelt konvertera fram och tillbaka från vinkelens enheter av grader och radianer.

 statisk statisk funktion radianOf (deg: Number): Number return deg / 180 * Math.PI;  statisk statisk funktion degreeOf (rad: Number): Number return rad / Math.PI * 180; 

Steg 11: Huvudklassen

Nu när vi har etablerat vår Projectile och Math2-klass kan vi börja koda vår huvudklass. Vi kommer också att behöva en Vector2D-klass, även om grundlig förklaring inte ingår på grund av den tidigare nämnda artikeln om vektorer av Daniel Sidhon. Jag antar att läsare förstår Vector2D-klassen efter att ha läst den. Men om det behövs förtydliganden, fråga mig om dina frågor.

Först av allt behöver vi veta privata variabler i den här klassen.

 privat var b1: projektil; // tangenttryck flaggor privat var UP: Boolean = false; privat var NED: Boolean = false; privat var VÄNSTER: Boolean = false; privat var RIGHT: Boolean = false;

Steg 12: Initialisering av Main

Vid initiering av Main, funktion i det kommer att lanseras. Denna funktion kommer att skapa en ny projektil och ställa in sin initialhastighet. Då kommer lyssnare till händelser att tilldelas.

 privat funktion init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // inträdespunkt b1 = nytt projektil (); stage.addChild (b1); // inställning av initialhastighet b1.setVelo (5, Math2.radianOf (30)); // inställning händelse lyssnare b1.addEventListener (Event.ENTER_FRAME, proj_enterFrame); stage.addEventListener (KeyboardEvent.KEY_DOWN, handle_keyDown); stage.addEventListener (KeyboardEvent.KEY_UP, handle_keyUp); 

Steg 13: Lyssnare för tangentbordshändelser

Jag har definierat användarkontroll som knapptryckningar på Upp, Vänster, Ned och Vänster piltangenter. När du trycker på och släpper ut dessa tangenter kommer flaggvariablerna för Main (Step 11) att bli sanna och falska. Baserat på dessa flaggor manipuleras vektormängderna på varje ram. Notera också Jag har delat kontroller i horisontella och vertikala axelmanipulatorer.

 privat funktion handle_keyDown (e: KeyboardEvent): void if (e.keyCode == Keyboard.UP) UP = true; annars om (e.keyCode == Keyboard.DOWN) DOWN = true; om (e.keyCode == Keyboard.LEFT) LEFT = true; annars om (e.keyCode == Keyboard.RIGHT) RIGHT = true;  privat funktion handle_keyUp (e: KeyboardEvent): void if (e.keyCode == Keyboard.UP) UP = false; annars om (e.keyCode == Keyboard.DOWN) DOWN = false; om (e.keyCode == Keyboard.LEFT) VÄNSTER = false; annars om (e.keyCode == Keyboard.RIGHT) RIGHT = false; 

Steg 14: EnterFrame Event-lyssnare

Vid uppdatering av varje ram kommer följande kod att utföras. Det är länge, men oroa dig inte; bara läs vidare.

 privat funktion proj_enterFrame (e: Event): void // definiera acceleration var accMag: Number = 0.1; om (UP) b1.setAcc (accMag, Math2.radianOf (-90)); b1.applyAcc ();  annars om (DOWN) b1.setAcc (accMag, Math2.radianOf (90)); b1.applyAcc ();  om (VÄNSTER) b1.setAcc (accMag, Math2.radianOf (180)); b1.applyAcc ();  annars om (HÖGER) b1.setAcc (accMag, Math2.radianOf (0)); b1.applyAcc ();  // decelerera eftersom nothng trycks för att simulera friktion. om (UP + NER + VÄNSTER + RÄTT = = 0) var currentVeloMag: Number = b1.getVelo (). getMagnitude (); var currentVeloAng: Number = b1.getVelo (). getAngle (); om (currentVeloMag> 1) b1.setAcc (accMag * -1, currentVeloAng); b1.applyAcc ();  b1.applyVelo (); // Begränsa sprite till gränserna för scenen 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 (); 

Steg 15: Uppdatera Motion

Uppdatering av rörelsen ska ske i följande ordning:

  1. Definiera ny acceleration enligt användarknapptryck.
  2. Använd acceleration, uppdatera nuvarande hastighet.
  3. Använd aktuell hastighet, uppdatera nuvarande förskjutning.
  4. Förfina förskjutningen för att behålla objektets inre gränser.

Jag har markerat koderna för enkel identifiering av dessa steg.

 privat funktion proj_enterFrame (e: Event): void // definiera acceleration var accMag: Number = 0.1; om (UP) b1.setAcc (accMag, Math2.radianOf (-90)); b1.applyAcc ();  annars om (DOWN) b1.setAcc (accMag, Math2.radianOf (90)); b1.applyAcc ();  om (VÄNSTER) b1.setAcc (accMag, Math2.radianOf (180)); b1.applyAcc ();  annars om (HÖGER) b1.setAcc (accMag, Math2.radianOf (0)); b1.applyAcc ();  // decelerera eftersom inget trycks för att simulera friktion. om (UP + NER + VÄNSTER + RÄTT = = 0) var currentVeloMag: Number = b1.getVelo (). getMagnitude (); var currentVeloAng: Number = b1.getVelo (). getAngle (); om (currentVeloMag> 1) b1.setAcc (accMag * -1, currentVeloAng); b1.applyAcc ();  b1.applyVelo (); // Begränsa sprite till gränserna för scenen 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 (); 

Steg 16: Slow Down Motion

Det kan hända att det finns andra funktioner som slits in mellan dessa markerade koder. Vad är dem? En är att tillämpa en annan vektor för att sakta ner vår projektil eftersom användaren inte trycker på några tangenter. Detta tillämpas innan vi lägger till hastighet på vår förskjutning.

 // decelerera eftersom nothng trycks för att simulera friktion. om (UP + NER + VÄNSTER + RÄTT = = 0) var currentVeloMag: Number = b1.getVelo (). getMagnitude (); var currentVeloAng: Number = b1.getVelo (). getAngle (); om (currentVeloMag> 1) b1.setAcc (accMag * -1, currentVeloAng); b1.applyAcc (); 

Steg 17: Stanna inuti

Nästa är att begränsa vår projektil för att alltid stanna på scenen, annars kommer den att flyga ur skärmen. Igen, implementBound är en funktion som jag har inkluderat i den statiska klassen Math2. Givet en övre gräns, nedre gräns och ett slumpmässigt värde, implementBound kommer att returnera ett värde som ligger inom gränserna.

Efter att ha tillämpat dessa begränsningar på vår förskjutning (och först efter det) uppdaterar vi Sprite position med detta förskjutningsvärde.

 // Begränsa sprite till gränserna för scenen b1.getDisp (). x = Math2.implementBound (0, stage.stageWidth, b1.getDisp (). x); b1.getDisp (). y = Math2.implementBound (0, stage.stageHeight, b1.getDisp (). y);

Steg 18: Orientera Sprite

Innan vi lämnar den här spriten som den ska vi rikta den så att den alltid pekar ut i den position det är på väg att använda funktionen orientera.


Steg 19: Ställ in och gå!

Nu är allt klart att gå. När du startar det här stycket genom att trycka på Ctrl + Enter, kommer du att se en pil som gradvis saktar ner när den hinner diagonalt ner på skärmen. Tryck på de fyra riktknapparna för att flytta pilen om. Oroa dig inte för att förlora din pil; det kommer att ligga inom din åsikt.


Slutsats

Denna artikel ska göra dig bekant med att använda vektorer för att animera rörelse. När du väl har förstått kinematik, fortsätt läsa på min post på dynamik. Låt mig få höra hur det går. Terima Kasih.