Gravity in Action

Studien av styrker har sentral interesse for dynamikk, studier av årsaker til bevegelse og endringer i bevegelse. Tyngdekraft er et eksempel; Det er dette som fører til at satellitter dreier seg om planeter og at vi skal være på bakken.

I denne opplæringen vil vi bygge en simulering av slike fenomener og kunne observere, eksperimentere og leke med partikler på scenen.

Blant alle partikler genereres, vil en hovedpartikkel tiltrekke seg andre. Som disse partiklene beveger seg mot hoveddelen, kan brukerne klikke på denne hovedpartikkelen for å trekke den rundt, noe som fører til at disse partiklene omdirigerer deres kurs. Disse partiklene vil slutte å bevege seg da de kolliderer med kanten av hovedballen, men de vil ikke overlappe hverandre.

Strukturen av denne opplæringen er arrangert på en måte der en kort teori i fysikk leveres før innføring av simuleringens gjennomføring. Nyt!


Endelig resultatforhåndsvisning

La oss se på det endelige resultatet vi vil jobbe for:

Klikk og dra den store grønne sirkelen for å flytte den rundt, og se hvordan de små blå sirklene reagerer.


Trinn 1: Gravitasjonskraft, Formel

Først, et fysikkforord. Den attraktive gravitasjonskraften mellom noen to objekter er uttrykt ved hjelp av følgende formel:

F: attraktiv kraft utøves på objekt av interesse (s2) av
en vilkårlig partikkel (s1).

G: Gravitasjonskonstant

m1: masse p1

m2: masse p2

r: avstand mellom s1 og s2

Vær spesielt oppmerksom på følgende:

  1. Forholdet mellom tyngdekraften og avstanden: F er omvendt proporsjonal med kvadratet av avstanden som separerer de to partiklene. Dette betyr at jo nærmere A og B er til hverandre, jo høyere er den attraktive kraften mellom dem og omvendt. Hvis du dobler avstanden, går kraften til en fjerdedel av den opprinnelige verdien.
  2. Verdien av gravitasjonskonstanten, G, er vitenskapelig 6.67259 x 10-11 N * m2 / kg2. Imidlertid vil 500 erstatte denne verdien i Flash-miljø.
  3. Vi kan forholde partikkelens bredde til deres masse. For dette eksempelet har jeg definert en partikkel masse for å være halvparten av sin radius.

Trinn 2: Newtons 2nd Lov, ligning

For å oversette kraft til kinematikk må vi beregne partikkelens akselerasjon. Den berømte ligningen av Sir Isaac Newton er vist nedenfor:

F: Gravitasjonskraft utøves på objekt av interesse (s2)

m: masse av objekt av interesse (s2)

en: akselerasjon av objekt av interesse (s2) under påvirkning av F

Her er implikasjonen at en høyere kraft som påføres partikkel A, resulterer i en høyere akselerasjon (forutsatt at massen forblir den samme). Denne akselerasjonen vil endre partikkelens hastighet.


Trinn 3: Starte prosjekt

Implementering vil bli gjort i FlashDevelop IDE. Bygg prosjektfilen din.

  1. Start et nytt prosjekt, PROJECT> NEW PROJECT?
  2. Velg fra popup-vindu, AS3 PROJECT
  3. Gi navn på prosjektet ditt. I mitt tilfelle, Attractor
  4. Velg prosjektstedet ditt

Se denne veiledningen for en introduksjon til FlashDevelop.


Trinn 4: Klasser du trenger

Det er 4 klasser å lage i mappe \ Src \: Main.as, Vector2D.as, Ball.as & Math2.as. Det anbefales at du laster ned alle disse filene fra kildepakken og prøver å kartlegge dem mot trinn for å komme for å få en generell forståelse av mekanismen før du endrer dem. Deres roller er uttrykt som nedenfor:

Klassenavn Formålet med organisasjonen
Main.as Klasse for å lage ballene visuelt og å knytte animasjon til hendelser.
Vector2D Klasse som inneholder alle vektormanipuleringsfunksjoner.
Ball Klasse som inneholder funksjoner for å visuelt generere en ball, implementerer dynamikk og kinematikk av en ball.
Math2 Statisk klasse som har en funksjon for å lette randomisering av den første plasseringen av baller.

Trinn 5: Randomiserende verdier

La oss snakke om Math2-klassen først. Funksjonen nedenfor vil bidra til å generere et tilfeldig tall innenfor det angitte området. Godtar to innganger, minimumsgrense og maksimumsgrense innenfor rekkevidde.

 offentlig statisk funksjon randomiseBetween (range_min: int, range_max: int): int var rekkevidde: int = range_max - range_min; var randomisert: int = Math.random () * rekkevidde + range_min; returnere randomisert; 

Trinn 6: Vector2D, Getters og Setters

Størstedelen av matematikk som brukes er plassert i Vector2D. Denne opplæringen antar et nivå av fortrolighet i vektoranalyse hos brukerne. Funksjonene under er vanligvis brukt til å få og sette vektorkomponenter, pluss en metode for å nullstille alle komponenter til null. I alle fall, hvis du er ubehagelig med vektorer, besøk et flott innlegg på euklidiske vektorer av Daniel Sidhion.

 offentlig funksjon Vector2D (valueX: Number, valueY: Number) this._x = valueX; this._y = valueY;  offentlig funksjon sett vecX (valueX: Number): void this._x = valueX;  offentlig funksjon få vecX (): Nummer return this._x offentlig funksjon sett vecY (valueY: Number): void this._y = valueY;  offentlig funksjon få vecY (): Nummer return this._y offentlig funksjon setVector (valueX: Number, valueY: Number): void this._x = valueX; this._y = valueY;  tilbakestilling av offentlig funksjon (): void this._x = 0; dette._y = 0; 

Trinn 7: Vector2D, Operasjoner

De viktigste bruksområdene til Vector2D ligger i følgende funksjoner, som:

  • få størrelsen på vektoren
  • få vinkelen fra vektoren i forhold til opprinnelsen
  • få vektorvektoren til vektoren
  • utfør enkle vektoroperasjoner av tillegg, subtraksjon og skalar
    multiplikasjon
 offentlig funksjon getMagnitude (): Nummer var lengthX: Number = this._x; var lengthY: Number = this._y; returnere Math.sqrt (lengdeX * lengdeX + lengde * lengdeY);  offentlig funksjon getAngle (): Nummer var lengthX: Number = this._x; var lengthY: Number = this._y; returnere Math.atan2 (lengde, lengdeX);  offentlig funksjon getVectorDirection (): Vector2D var vectorDirection: Vector2D = ny Vector2D (this._x / this.getMagnitude (), this._y / this.getMagnitude ()); returnere Vector2D (vectorDirection);  offentlig funksjon minusVector (vector2: Vector2D): void this._x - = vector2.vecX; this._y - = vector2.vecY;  offentlig funksjon addVector (vector2: Vector2D): void this.xx = vector2.vecX; this._y + = vector2.vecY;  offentlig funksjon multipliserer (skalar: tall): void this._x * = skalar; this._y * = skalar; 

Trinn 8: Ball.as Tegning

De Ball klassen er der alle de interessante operasjonene foregår. For å starte animasjonen må vi tegne en ball og sette flere kinematikk- og dynamikkrelaterte variabler. Funksjonen for å tegne en ball er som nedenfor:

 privat funksjonstegn (radius: tall, farge: uint): void graphics.beginFill (farge, 1); graphics.drawCircle (0, 0, radius); graphics.endFill (); 

Trinn 9: Ball.as Private Variabler

De nevnte flere kinematikk- og dynamikkrelaterte variabler er angitt som nedenfor:

 privat var _disp: Vector2D; // forskyvningsvektor, i forhold til opprinnelsen privat var _velo: Vector2D; // hastighetsvektor privat var _acc: Vector2D; // akselerasjonsvektor privat var _attractive_coeff: Nummer = 500; privat var _mass: nummer;

Trinn 10: Ball.as Initiering

Som konstruktøren av Ball-klassen kalles, tegnes grafikk. Når en gang er tegnet, vil ballen bli plassert på scenen tilfeldig. Vi vil også sette de private variablene. Alle vektormengder vil også initialiseres til 0, med unntak av forskyvningen som måles i forhold til opprinnelsen.

 offentlig funksjon Ball (radius: tall = 20, farge: uint = 0x0000FF) this.draw (radius, farge); this._mass = radius / 2; // antar at massen er halv av radius this.x = Math2.randomiseBetween (0, 550); this.y = Math2.randomiseBetween (0, 400); this._disp = ny Vector2D (this.x, this.y); // sett initial forskyvning this._velo = ny Vector2D (0, 0); this._acc = ny Vector2D (0, 0); 

Trinn 11: Ball.as Beregn attraktiv kraft

Vi må beregne den underliggende kraften som får våre partikler til å animere. Gjett hva, det er gravitasjonskraften. Funksjonen nedenfor vil bidra til å beregne denne kraften. Legg merke til at en kappe påføres akselerasjonen på 5. De horisontale og vertikale komponenter av kraft er avledet ved hjelp av trigonometri; animasjonen ovenfor kan bidra til å forstå matematikken til dette.

 offentlig funksjon få masse (): tall return _mass;  Private funksjon getForceAttract (m1: Nummer, m2: Nummer, vec2Center: Vector2D): Vector2D / * Beregn attraktiv kraft basert på følgende formel: * F = K * m1 * m2 / r * r * / var teller: Nummer = this._attractive_coeff * m1 * m2; var nevner: Nummer = vec2Center.getMagnitude () * vec2Center.getMagnitude (); var forceMagnitude: Number = teller / nevner; var forceDirection: Number = vec2Center.getAngle (); // sette en hette hvis (forceMagnitude> 0) forceMagnitude = Math.min (forceMagnitude, 5); // deriving force komponent, horisontal, vertikal var forceX: Number = forceMagnitude * Math.cos (forceDirection); var forceY: Number = forceMagnitude * Math.sin (forceDirection); var kraft: Vector2D = ny Vector2D (forceX, forceY); tilbake kraft; 

Trinn 12: Ball.as Beregn akselerasjon

Når kraftvektor er oppnådd, kan vi beregne den resulterende akselerasjonen. Huske, F = ma, så a = F / m.

 offentlig funksjon getAcc (vecForce: Vector2D): Vector2D // innstilling akselerasjon på grunn av kraft var vecAcc: Vector2D = vecForce.multiply (1 / this._mass); returnere veccAcc; 

Trinn 13: Ball.as Beregn forskyvning

Ved beregning av akselerasjon kan vi effektivt beregne den resulterende forskyvningen.

Husk at kraft beregnet er faktisk basert på forskyvningen mellom midten av ballene.

 privat funksjon getDispTo (ball: Ball): Vector2D var currentVector: Vector2D = ny Vector2D (ball.x, ball.y); currentVector.minusVector (this._disp); return currentVector;  offentlig funksjon tiltrukket til (ball: ball): void var toCenter: Vector2D = this.getDispTo (ball); 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); 

Trinn 14: Ball.as Implement Displacement

Deretter kan vi flytte vår ball til sin nye plassering, gjennom funksjonen nedenfor. Legg merke til at forskyvning beregnet aldri implementeres på ballens nåværende posisjon straks. Slik utforming er å tillate kontroll gjøres: kollisjonssensor mellom baller.

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

Husk at kraften er basert på avstand mellom sentre. Derfor vil ballene trenge inn og fortsette å bevege seg på grunn av at attraktiv kraft er høyere når de er nærmere. Vi må nullstille akselerasjon og hastighet til 0 når ballene berører hverandres kant. Imidlertid må vi få et middel til å oppdage kollisjon mellom to baller.


Trinn 15: Ball.as Kollisjonsdeteksjon

Kollisjon kan enkelt kontrolleres. Separasjon mellom noen to baller bør ikke være mindre enn summen av deres radius. Her er kollisjonsdetekteringsfunksjonen:

 offentlig funksjon kollisjonInto (ball: Ball): Boolsk var hit: Boolsk = false; var minDist: Nummer = (ball.width + this.width) / 2; hvis (this.getDispTo (ball) .getMagnitude () < minDist)  hit = true;  return hit; 

Trinn 16: Ball.as Beregn Forskyv for å repel

Vanligvis når kollisjon er blitt oppdaget mellom to baller, overlapper staten deres hverandre. Vi må sørge for at de bare sitter pent på kanten og ikke overlapper. Hvordan? Vi kan forflytte en av ballene bort fra den andre, men vi må beregne den høyre forskyvningen for å justere først. Her er forskyvningsberegningen:

 offentlig funksjon getRepel (ball: Ball): Vector2D var minDist: Nummer = (ball.width + this.width) / 2; // beregne avstand for å avvise var toBall: Vector2D = this.getDispTo (ball); var directToBall: Vector2D = toBall.getVectorDirection (); directToBall.multiply (minDist); directToBall.minusVector (Toball); directToBall.multiply (-1); returner direkteToBall; 

Trinn 17: Ball.as Implementere displacement to Repel

Etter at vi har beregnet riktig forskyvning, må vi implementere den. Handlingen er som å avvise en av ballene. I tillegg må vi gjøre ytterligere to ekstra kommandoer. Husk at vi har et dynamisk miljø. Selv etter at vi har satt forskyvningen en av ballen til kanten, vil akselerasjon på grunn av kraft og den resulterende hastigheten animere den, noe som forårsaker en uønsket bevegelse av jerking inn og ut. Vi må nullstille disse verdiene for akselerasjon og hastighet.

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

Trinn 18: Ball.as Animate

Til slutt kan vi animere (gjengi) vår ball som om den ble tiltrukket av en annen. Når kollisjonen oppdages, vil forskyvningen justeres slik at den ikke vil trenge inn i kanten. Dette skjer først for ballene når de kolliderer med senteret, og deretter for ballene når de kolliderer med hverandre.

 offentlig funksjon animere (senter: Ball, alle: Array): void this.attractedTo (center); hvis (kollisjonInto (senter)) this.repelledBy (senter); for (var jeg: 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); 

Trinn 19: Main.as Private Variables

Fortsett videre til vår siste klasse, Hoved. Hovedklassen genereres ved starten av prosjektet. Private variabler vil inkludere den ene ballen som tiltrekker alle de andre og antall baller i vår Flash presentasjon.

 private var mainBall: Ball; privat var totaltBalls: int = 10;

Trinn 20: Main.as Draw Balls

Først av alt, bør vi initialisere baller. Det vil være en hovedball som tiltrekker seg alle de andre. De andre er navngitt slik at henvisninger lett kan gjøres senere.

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

Trinn 21: Main.as Implementere ballinteraksjon

Deretter tilordne hendelser til hovedballen, slik at den blir draget når du klikker og stopper når den slippes ut.

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

Trinn 22: Main.as Anime Balls

Animerende baller som blir tiltrukket av de viktigste. En EnterFrame-hendelse er tildelt hver ball.

 privat funksjon animateAll (): void for (var jeg: 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); 

Trinn 23: Test film

Til slutt trykker du på Ctrl + Enter for å forhåndsvise animasjonen.


Konklusjon

For å bringe denne opplæringen ett skritt videre, kan leserne utvide dette prosjektet ved å implementere andre lineære krefter.

I alle fall tjener simuleringer som et godt verktøy for å levere ideer som er vanskelig å forklare med ren tekst og bilde i et fysikkklassemiljø, spesielt når staten endrer seg over tid.

Jeg håper denne lille opplæringen hjelper deg på en eller annen måte. Terima kasih (det er "takk" i Malaysia) for å ta deg tid til å lese og ser frem til å høre kommentarer fra andre lesere.