Gravity in Action

Undersökningen av krafter har ett centralt intresse för dynamik, studier av rörelseresor och förändringar i rörelse. Gravitationskraften är ett exempel; Det är detta som orsakar att satelliter kretsar kring planeter och att vi ska stanna kvar på marken.

I denna handledning kommer vi att bygga en simulering av sådant fenomen och kunna observera, experimentera och spela med partiklar på scenen.

Bland alla partiklar som genereras kommer en huvudpartikel att locka andra. Eftersom dessa partiklar rör sig mot huvuddelen kan användarna klicka på den här huvudpartikeln för att dra den runt, vilket leder till att dessa partiklar omdirigerar sin kurs. Dessa partiklar kommer att sluta röra sig eftersom de kolliderar med kugghjulets kant, men de kommer inte att överlappa varandra.

Strukturen i denna handledning är arrangerad på ett sätt där en kort teori i fysik levereras innan introduktionen av simuleringen genomförs. Njut av!


Slutresultatförhandsvisning

Låt oss ta en titt på det slutliga resultatet vi ska arbeta för:

Klicka och dra den stora gröna cirkeln för att flytta den och se hur de små blå cirklarna reagerar.


Steg 1: Gravitationsstyrka, Formel

Först, ett fysikförord. Den attraktiva gravitationskraften mellan några två objekt uttrycks genom följande formel:

F: attraktiv kraft utövas på objekt av intresse (sid2) av
en godtycklig partikel (s1).

G: Gravitationskonstant

m1: massa p1

m2: massa p2

r: Avstånd mellan s1 och p2

Var särskilt uppmärksam på följande:

  1. Relationen mellan gravitation och avstånd: F är omvänd proportionell mot kvadraten av avståndet som skiljer de två partiklarna. Det betyder att närmare A och B är till varandra, desto högre är den attraktiva kraften mellan dem och vice versa. Om du dubblar avståndet går kraften till en fjärdedel av dess ursprungliga värde.
  2. Värdet av gravitationskonstanten, G, är vetenskapligt 6.67259 x 10-11 N * m2 / kg2. Men 500 kommer att ersätta detta värde i Flash-miljö.
  3. Vi kan relatera partikelns bredd till sin massa. För det här exemplet har jag definierat en partikelmassa för att vara hälften av sin radie.

Steg 2: Newtons 2nd Lag, ekvation

För att kunna översätta kraft till kinematik måste vi beräkna partikelns acceleration. Den berömda ekvationen av Sir Isaac Newton visas nedan:

F: gravitationskraften utövas på objekt av intresse (sid2)

m: massa av objekt av intresse (sid2)

en: acceleration av objekt av intresse (sid2) under inflytande av F

Här är implikationen att en högre kraft applicerad på partikel A resulterar i en högre acceleration (förutsatt att dess massa blir densamma). Denna acceleration kommer att ändra partikelns hastighet.


Steg 3: Starta projektet

Implementering kommer att göras i FlashDevelop IDE. Bygg din projektfil.

  1. Starta ett nytt projekt, PROJECT> NEW PROJECT?
  2. Välj från popup-fönster, AS3 PROJECT
  3. Namn ditt projekt. I mitt fall Attractor
  4. Välj din projektplats

Se den här guiden för en introduktion till FlashDevelop.


Steg 4: Klasser du behöver

Det finns 4 klasser att skapa i mapp \ Src \: Main.as, Vector2D.as, Ball.as & Math2.as. Det är tillrådligt att du hämtar alla dessa filer från källpaketet och försöker kartlägga dem mot steg för att komma för att få en allmän förståelse av mekanismen innan du ändrar dem. Deras roller uttrycks som nedan:

Klassnamn Syftet med organisationen
Main.as Klass för att skapa bollarna visuellt och att bifoga animering till händelser.
Vector2D Klass som innehåller alla vektormanipuleringsfunktioner.
Boll Klass som innehåller funktioner för att visuellt generera en boll, implementerar dynamik och kinematik i en boll.
Math2 Statisk klass som har en funktion för att underlätta randomisering av bollens ursprungliga placering.

Steg 5: Randomiserande värden

Låt oss prata om Math2-klassen först. Funktionen nedan hjälper till att generera ett slumptal inom det angivna intervallet. Accepterar två ingångar, minsta gräns och maxgräns inom räckvidd.

 offentlig statisk funktion randomiseBetween (range_min: int, range_max: int): int var intervall: int = range_max - range_min; var randomiserad: int = Math.random () * intervall + range_min; returnera randomiserad; 

Steg 6: Vector2D, Getters och Setters

Huvuddelen av matematik som används ligger i Vector2D. Denna handledning förutsätter en nivå av förtrogenhet i vektoranalys hos användarna. Funktionerna nedan brukar användas för att få och ställa in vektorkomponenter, samt en metod för att återställa alla komponenter till noll. I alla fall, om du är obekväma med vektorer, besök ett bra inlägg på euklidiska vektorer av Daniel Sidhion.

 allmän funktion Vector2D (valueX: Number, valueY: Number) this._x = valueX; this._y = valueY;  public function set vecX (valueX: Number): void this._x = valueX;  offentliga funktionen få vecX (): Number return this._x public function set vecY (valueY: Number): void this._y = valueY;  offentliga funktionen få vecY (): Antal return this._y public function setVector (valueX: Number, valueY: Number): void this._x = valueX; this._y = valueY;  återställning av allmän funktion (): void this._x = 0; this._y = 0; 

Steg 7: Vector2D, Operations

De viktigaste användningarna av Vector2D ligger i följande funktioner, vilka:

  • få storleken på vektorn
  • få den vinkel som gjorts av vektorn i förhållande till ursprunget
  • erhålla vektorriktningen av vektorn
  • utföra enkla vektoroperationer av addition, subtraktion och skalär
    multiplikation
 offentlig funktion getMagnitude (): Number var lengthX: Number = this._x; var lengthY: Number = this._y; returnera Math.sqrt (lengthX * lengthX + lengthY * lengthY);  offentlig funktion getAngle (): Number var lengthX: Number = this._x; var lengthY: Number = this._y; returnera Math.atan2 (längd, längdX);  allmän funktion getVectorDirection (): Vector2D var vectorDirection: Vector2D = ny Vector2D (this._x / this.getMagnitude (), this._y / this.getMagnitude ()); returnera Vector2D (vectorDirection);  allmän funktion minusVector (vector2: Vector2D): void this.xx = vector2.vecX; this._y - = vector2.vecY;  public function addVector (vector2: Vector2D): void this.xx = vector2.vecX; this._y + = vector2.vecY;  allmän funktion multiplicera (skalär: tal): void this._x * = scalar; this._y * = skalar; 

Steg 8: Ball.as Ritning

De Boll klassen är där alla intressanta operationer äger rum. För att börja animeringen måste vi rita en boll och ange flera kinematik- och dynamikrelaterade variabler. Funktionen att rita en boll är som nedan:

 privat funktionstegning (radie: nummer, färg: uint): void graphics.beginFill (color, 1); graphics.drawCircle (0, 0, radius); graphics.endFill (); 

Steg 9: Ball.as Private Variables

De nämnda flera kinematik- och dynamikrelaterade variablerna anges nedan:

 privat var _disp: Vector2D; // Förskjutningsvektor, i förhållande till ursprunget Private Var _velo: Vector2D; // hastighetsvektor privat var _acc: Vector2D; // accelerationsvektor privat var _attractive_coeff: Number = 500; privat var _mass: nummer;

Steg 10: Ball.as Initiering

Som konstruktören av Boll-klassen kallas, ritas grafik. När en gång dragits kommer bollen att släppas på scenen slumpmässigt. Vi kommer också att ställa in de privata variablerna. Alla vektormängder kommer också att initialiseras vid 0, förutom förskjutningen som mäts relativt ursprung.

 allmän funktion Boll (radie: Nummer = 20, färg: uint = 0x0000FF) this.draw (radie, färg); this._mass = radie / 2; // förutsatt att massan är halva radie this.x = Math2.randomiseBetween (0, 550); this.y = Math2.randomiseBetween (0, 400); this._disp = new Vector2D (this.x, this.y); // Ange initialförskjutning this._velo = ny Vector2D (0, 0); this._acc = ny Vector2D (0, 0); 

Steg 11: Ball.as Beräkna attraktiv kraft

Vi måste beräkna den underliggande kraften som gör att våra partiklar kan animera. Gissa vad, det är gravitationskraften. Funktionen nedan hjälper till att beräkna denna kraft. Observera att ett lock appliceras på accelerationen vid 5. De horisontella och vertikala komponenterna av kraft är härledda med hjälp av trigonometri; animeringen ovan kan hjälpa till att förstå matematiken i detta.

 allmän funktion få massa (): Nummer return _mass;  Privat funktion getForceAttract (m1: Number, m2: Number, vec2Center: Vector2D): Vector2D / * beräkna attraktiv kraft baserad på följande formel: * F = K * m1 * m2 / r * r * / var täljare: Number = this._attractive_coeff * m1 * m2; var nämnare: Number = vec2Center.getMagnitude () * vec2Center.getMagnitude (); var forceMagnitude: Number = täljare / nämnare; var forceDirection: Number = vec2Center.getAngle (); // ställa in ett lock om (forceMagnitude> 0) forceMagnitude = Math.min (forceMagnitude, 5); // härledande kraft komponent, horisontell, vertikal var forceX: Number = forceMagnitude * Math.cos (forceDirection); var forceY: Number = forceMagnitude * Math.sin (forceDirection); var kraft: Vector2D = ny Vector2D (forceX, forceY); återvändande kraft; 

Steg 12: Ball.as Beräkna acceleration

När kraftvektor har erhållits kan vi beräkna den resulterande accelerationen. Kom ihåg, F = ma, så a = F / m.

 offentlig funktion getAcc (vecForce: Vector2D): Vector2D // inställningsacceleration på grund av kraft var vecAcc: Vector2D = vecForce.multiply (1 / this._mass); returnera veccAcc; 

Steg 13: Ball.as Beräkna Förskjutning

Med beräknad acceleration kan vi effektivt beräkna den resulterande förskjutningen.

Kom ihåg att beräknad kraft beror faktiskt på förskjutningen mellan bollens centrum.

 privat funktion getDispTo (boll: Boll): Vector2D var currentVector: Vector2D = ny Vector2D (ball.x, ball.y); currentVector.minusVector (this._disp); return currentVector;  allmän funktion lockas till (boll: boll): tomrum var toCenter: Vector2D = this.getDispTo (boll); var currentForceAttract: Vector2D = this.getForceAttract (ball.mass, this._mass, toCenter); this._acc = this.getAcc (currentForceAttract); this._velo.addVector (this._acc); this._disp.addVector (this._velo); 

Steg 14: Ball.as Implement Förskjutning

Då kan vi flytta vår boll till sin nya plats, genom funktionen nedan. Observera att förskjutning beräknad aldrig implementeras på bollens nuvarande läge genast. Sådan utformning är att möjliggöra kontroll görs: kollisionsdetektering mellan bollar.

 public function setPosition (vecDisp: Vector2D): void this.x = Math.round (vecDisp.vecX); this.y = Math.round (vecDisp.vecY); 

Kom ihåg att kraften är baserad på avstånd mellan centra. Därför kommer bollarna tränga igenom och fortsätta att flytta på grund av att attraktiv kraft är högre när de är närmare. Vi måste återställa acceleration och hastighet till 0 när kulorna berör varandra. Vi måste dock få ett medel för att upptäcka kollisionen mellan två bollar.


Steg 15: Ball.as Kollisionsdetektion

Kollision kan enkelt kontrolleras. Separation mellan två bollar borde inte vara mindre än summan av deras radier. Här är kollisionsdetekteringsfunktionen:

 offentlig funktion kollisionInto (boll: Boll): Booleska var hit: Booleskt = false; var minDist: Nummer = (ball.width + this.width) / 2; om (this.getDispTo (boll) .getMagnitude () < minDist)  hit = true;  return hit; 

Steg 16: Ball.as Beräkna Förskjut till Repel

Vanligen när kollision har detekterats mellan två bollar överlappar deras tillstånd varandra. Vi måste se till att de bara sitter snyggt på kanten och inte överlappar varandra. På vilket sätt? Vi kan förskjuta en av bollarna bort från den andra, men vi måste beräkna rätt förskjutning för att justera först. Här är förskjutningsberäkningen:

 offentlig funktion getRepel (boll: Boll): Vector2D var minDist: Number = (boll.width + this.width) / 2; // beräkna avstånd för att avvisa var toBall: Vector2D = this.getDispTo (boll); var directToBall: Vector2D = toBall.getVectorDirection (); directToBall.multiply (MinDist); directToBall.minusVector (Toball); directToBall.multiply (-1); returnera DirectToBall; 

Steg 17: Ball.as Implementera förskjutning att upphäva

När vi har beräknat rätt förskjutning måste vi implementera det. Åtgärden är som att avvisa en av bollarna. Dessutom behöver vi göra ytterligare två extra kommandon. Kom ihåg att vi har att göra med en dynamisk miljö. Även efter att vi har ställt förskjutningen en av bollen till kanten, acceleration på grund av kraft och den resulterande hastigheten kommer att animera den, vilket orsakar en oönskad rörelse av ryckning in och ut. Vi måste återställa dessa värden för acceleration och hastighet till noll.

 Offentlig funktion repelledBy (boll: Ball): void this._acc.reset (); this._velo.reset (); var repelDisp: Vector2D = getRepel (boll); this._disp.addVector (repelDisp); 

Steg 18: Ball.as Animera

Slutligen kan vi animera (göra) vår boll som om den attraherades av en annan. När kollision upptäcks kommer förskjutningen att justeras så att den inte tränger in i kanten. Detta kommer att hända först för bollarna när de kolliderar med centrum, och sedan för bollarna när de kolliderar med varandra.

 allmän funktion animera (center: Boll, allt: Array): void this.attractedTo (center); om (collisionInto (center)) this.repelledBy (center); för (var i: int = 0; i < all.length; i++)  var current_ball:Ball = all[i] as Ball; if (collisionInto(current_ball) && current_ball.name != this.name) this.repelledBy(current_ball);  this.setPosition(this._disp); 

Steg 19: Main.as Private Variables

Att gå vidare till vår sista klass, Huvudsaklig. Huvudklassen genereras i början av projektet. Privata variabler kommer att innehålla den enda bollen som lockar alla andra och antalet bollar i vår Flash-presentation.

 privat var mainBall: Ball; privat var totaltBollar: int = 10;

Steg 20: Main.as Draw Balls

Först av allt bör vi initiera bollar. Det kommer att finnas en huvudboll som lockar alla andra. De andra namnges så att hänvisning lätt kan göras senare.

 privat funktion createBalls (): void mainBall = new Ball (50, 0x00FF00); this.addChild (mainBall); för (var i: int = 0; i < this.totalBalls; i++)  var currentBall:Ball = new Ball(); currentBall.name = "ball" + i; this.addChild(currentBall);  

Steg 21: Main.as Implementera Ball Interaction

Sedan tilldela händelser till huvudbollen för att få den att släppas när den klickas och stoppas när den släpps.

 privat funktion init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // Ingångspunkt createBalls (); mainBall.addEventListener (MouseEvent.MOUSE_DOWN, onMouseDown); stage.addEventListener (MouseEvent.MOUSE_UP, onMouseUp); animateAll ();  privat funktion onMouseUp (e: MouseEvent): void stopDrag ();  privat funktion onMouseDown (e: MouseEvent): void e.target.startDrag (); 

Steg 22: Main.as Anime Balls

Animerande bollar som lockas av huvudpersonen. En EnterFrame-händelse tilldelas varje boll.

 privat funktion animateAll (): void for (var i: uint = 0; i < totalBalls; i++)  //each ball is pulled by main_ball var current_ball:Ball = this.getChildByName("ball" + i) as Ball; current_ball.addEventListener(Event.ENTER_FRAME, enterFrame);   private function enterFrame(e:Event):void  var allObj:Array = new Array(); for (var i:int = 0; i <= totalBalls; i++)  var current_ball:Ball = this.getChildAt(i) as Ball; allObj.push(current_ball);  e.target.animate(mainBall, allObj); 

Steg 23: Testa film

Slutligen trycker du på Ctrl + Enter för att förhandsgranska animeringen.


Slutsats

För att få denna handledning ett steg längre kan läsarna förlänga detta projekt genom att genomföra andra linjära krafter.

Under alla omständigheter fungerar simuleringar som ett bra verktyg för att leverera idéer som är svåra att förklara med vanlig text och bild i en fysikklassmiljö, speciellt när staten förändras över tiden.

Jag hoppas att den här lilla handledningen hjälper dig på något sätt. Terima Kasih (det är "tack" i Malaysia) för att ta tid att läsa och ser fram emot att höra kommentarer från medläsare.