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!
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.
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:
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.
Implementering vil bli gjort i FlashDevelop IDE. Bygg prosjektfilen din.
Se denne veiledningen for en introduksjon til FlashDevelop.
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. |
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;
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;
De viktigste bruksområdene til Vector2D ligger i følgende funksjoner, som:
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;
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 ();
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;
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);
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;
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;
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);
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.
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;
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;
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);
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);
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;
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);
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 ();
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);
Til slutt trykker du på Ctrl + Enter for å forhåndsvise animasjonen.
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.