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!
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.
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:
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.
Implementering kommer att göras i FlashDevelop IDE. Bygg din projektfil.
Se den här guiden för en introduktion till FlashDevelop.
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. |
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;
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;
De viktigaste användningarna av Vector2D ligger i följande funktioner, vilka:
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;
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 ();
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;
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);
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;
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;
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);
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.
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;
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;
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);
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);
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;
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);
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 ();
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);
Slutligen trycker du på Ctrl + Enter för att förhandsgranska animeringen.
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.