Gravitatea în acțiune

Studiul forțelor este de interes central în dinamică, studiul cauzelor mișcării și al mișcărilor. Forta gravitationala este un exemplu; aceasta este cauza care determină sateliții să se rotească în jurul planetelor și să rămânem la sol.

În acest tutorial, vom construi o simulare a unui astfel de fenomen și vom putea observa, experimenta și juca cu particule pe scena.

Dintre toate particulele generate, o particulă principală va atrage alții. Pe măsură ce aceste particule se deplasează spre cea principală, utilizatorii pot face clic pe această particulă principală pentru ao trage, cauzând astfel particulele să-și redirecționeze cursul. Aceste particule se vor opri în mișcare deoarece se ciocnesc cu marginea mingii principale, dar nu se vor suprapune reciproc.

Structura acestui tutorial este aranjată într-o manieră în care o teorie scurtă în fizică a fost prezentată înainte de introducerea implementării simulării. se bucura!


Rezultatul final al rezultatelor

Să aruncăm o privire asupra rezultatului final pe care îl vom strădui:

Faceți clic și trageți cercul verde mare pentru ao deplasa și urmăriți modul în care reacționează cercul albastru.


Pasul 1: forța gravitațională, formula

În primul rând, o prefață Fizică. Forța gravitațională atractivă dintre oricare două obiecte este exprimată prin următoarea formulă:

F: forța atractivă exercitată asupra obiectului de interes (p2) de
o particula arbitrară (p1).

G: Constanta gravitațională

m1: masa p1

m2: masa p2

r: distanța dintre p1 și p2

Luați în considerare următoarele:

  1. Relația dintre gravitație și distanță: F este invers proporțională cu pătratul distanței care separă cele două particule. Aceasta înseamnă că mai aproape de A și B unul față de celălalt, cu cât forța atractivă este mai mare între ele și invers. Dacă dublezi distanța, forța scade până la un sfert din valoarea inițială.
  2. Valoarea constantei gravitaționale, G, este științific 6.67259 x 10-11 N * m2 / kg2. Cu toate acestea, 500 va înlocui această valoare în mediul Flash.
  3. Putem relaționa lățimea particulei la masa lor. Pentru acest exemplu, am definit masa particulelor ca fiind jumătate din raza sa.

Pasul 2: Newton's 2nd Legea, Ecuația

Pentru a traduce forța în cinematică, trebuie să calculăm accelerația particulelor. Ecuația celebră a lui Sir Isaac Newton este prezentată mai jos:

F: forța gravitațională exercitată asupra obiectului de interes (p2)

m: masa obiectului de interes (p2)

A: accelerarea obiectului de interes (p2) sub influența lui F

Aici, implicația este că o forță mai mare aplicată pe particula A are ca rezultat o accelerație mai mare (presupunând că masa ei rămâne aceeași). Această accelerație va schimba viteza particulei.


Pasul 3: Pornirea proiectului

Implementarea se va face în FlashDevelop IDE. Construiți fișierul proiectului.

  1. Începeți un nou proiect, PROIECT> NOU PROIECT?
  2. Selectați din fereastra pop-up, AS3 PROJECT
  3. Denumiți proiectul. În cazul meu, Attractor
  4. Selectați locația proiectului

Consultați acest ghid pentru o introducere în FlashDevelop.


Pasul 4: Cursurile de care aveți nevoie

Există 4 clase de creat în dosar \ Src \: Main.as, Vector2D.as, Ball.as & Math2.as. Este recomandabil să descărcați toate aceste fișiere din pachetul sursă și să încercați să le cartografiați împotriva pașilor pentru a ajunge la o înțelegere generală a mecanismului înainte de a le modifica. Rolul lor este exprimat după cum urmează:

Numele clasei Scopul organizării
Main.as Clasa pentru a crea bilele vizual și pentru a atașa animație la evenimente.
Vector2D Clasă care deține toate funcțiile de manipulare vectorială.
Minge Clasa care conține funcții pentru a genera vizual o minge, implementează dinamica și cinematica unei mingi.
Math2 Clasa statică care deține o funcție pentru a facilita randomizarea locației inițiale a bilelor.

Pasul 5: Randomizarea valorilor

Mai întâi să vorbim despre clasa Math2. Funcția de mai jos va ajuta la generarea unui număr aleatoriu în intervalul specificat. Acceptă două intrări, o limită minimă și o limită maximă în interval.

 funcția statică funcțională publică aleatorie Între (interval_min: int, interval_max: int): int var interval: int = interval_max - interval_min; var randomizat: int = Math.random () * interval + interval_min; întoarcerea este randomizată; 

Pasul 6: Vector2D, Getters și Setters

Cea mai mare parte a matematicii folosite este situată în Vector2D. Acest tutorial presupune un nivel de familiaritate în analiza vectorilor în cadrul utilizatorilor. Funcțiile de mai jos sunt utilizate în general pentru a obține și a seta componente vectoriale, plus o metodă de resetare a tuturor componentelor la zero. În orice caz, dacă nu te simți confortabil cu Vectorii, vizitează un post minunat pe vectorii euclidieni de Daniel Sidhion.

 funcția publică Vector2D (valoareX: număr, valoareY: număr) this._x = valueX; this._y = valueY;  set de funcții publice vecX (valueX: Number): void this._x = valueX;  funcția publică get vecX (): Număr return this._x funcția publică set vecY (valueY: Number): void this._y = valueY;  funcția publică get vecY (): Numărul return this._y funcția publică setVector (valueX: Number, valueY: Number): void this._x = valueX; this._y = valueY;  funcția publică reset (): void this._x = 0; this._y = 0; 

Pasul 7: Vector2D, Operații

Utilizările majore ale Vector2D constau în următoarele funcții, care:

  • obține magnitudinea vectorului
  • obține unghiul făcut de vector în raport cu originea
  • obține direcția vectorului vectorului
  • efectua operații vectoriale simple de adăugare, scădere și scalare
    multiplicare
 funcția publică getMagnitude (): Numărul var lengthX: Number = this._x; var lengthY: Număr = aceasta.y; retur Math.sqrt (lungimeX * lungimeX + lungimeY * longY);  funcția publică getAngle (): Numărul var lengthX: Number = this._x; var lengthY: Număr = aceasta.y; retur Math.atan2 (lungimeY, lengthX);  funcția publică getVectorDirection (): Vector2D var vectorDirection: Vector2D = Vector2D nou (this._x / this.getMagnitude (), this._y / this.getMagnitude ()); returnați Vector2D (vectorDirection);  funcția publică minusVector (vector2: Vector2D): void this._x - = vector2.vecX; this._y - = vector2.vecY;  funcția publică addVector (vector2: Vector2D): void this._x + = vector2.vecX; this._y + = vector2.vecY;  funcția publică multiplă (scalar: Număr): void this._x * = scalar; this._y * = scalar; 

Pasul 8: Desenul Ball.as

Minge clasa este locul în care au loc toate operațiile interesante. Pentru a începe animația, trebuie să trasăm o minge și să setăm câteva variabile cinematice și dinamice. Funcția de a trage o minge este după cum urmează:

 funcția privată (raza: Număr, culoare: uint): void graphics.beginFill (culoare, 1); grafica (0, 0, raza); graphics.endFill (); 

Pasul 9: Variabile private Ball.as

Sunt menționate mai multe variabile cinematice și dinamice menționate mai jos:

 privat var _disp: Vector2D; // vector de deplasare, relativ la originea privată var _velo: Vector2D; // viteza vectorului privat var _acc: Vector2D; // Vector de accelerare privat var _attractive_coeff: Number = 500; privat var _mass: Număr;

Pasul 10: Inițierea Ball.as

După cum se numește constructorul clasei Ball, graficul este desenat. Odată tras, mingea va fi plasată pe scenă în mod aleatoriu. De asemenea, vom seta variabilele private. Toate cantitățile vectoriale vor fi, de asemenea, inițializate la 0, cu excepția deplasării care este măsurată în raport cu originea.

 funcție publică Ball (rază: număr = 20, culoare: uint = 0x0000FF) this.draw (rază, culoare); această masă = raza / 2; // presupunând că masa este jumătate din raza aceasta.x = Math2.randomiseBetween (0, 550); this.y = Math2.randomise între (0, 400); this._disp = nou Vector2D (this.x, this.y); // setați deplasarea inițială this._velo = vector2D nou (0, 0); this._acc = Vector2D nou (0, 0); 

Pasul 11: Ball.as Calculați Forța Atractivă

Trebuie să calculam forța de bază care determină animația particulelor noastre. Ghici ce, e forța gravitațională. Funcția de mai jos va ajuta la calcularea acestei forțe. Rețineți că se aplică un plafon la accelerație la 5. Componentele orizontale și verticale ale forței sunt derivate folosind trigonometria; animația de mai sus poate ajuta la înțelegerea matematicii acestui lucru.

 funcția publică obține masa (): Numărul return _mass;  funcția privată getForceAttract (m1: Number, m2: Number, vec2Center: Vector2D): Vector2D / * calcula forța atractivă pe baza următoarei formule: * F = K * m1 * m2 / r * r * this._attractive_coeff * m1 * m2; var numitor: număr = vec2Center.getMagnitude () * vec2Center.getMagnitude (); var forceMagnitude: număr = numărător / numitor; var forceDirection: Număr = vec2Center.getAngle (); // setarea unui capac dacă (forceMagnitude> 0) forceMagnitude = Math.min (forceMagnitude, 5); // componenta de forță derivată, forța orizontală verticală var forceX: Number = forceMagnitude * Math.cos (forceDirection); var forceY: Număr = forțăMagnitură * Math.sin (forceDirection); var force: Vector2D = Vector2D nou (forceX, forceY); forță de întoarcere; 

Pasul 12: Ball.as Calculați accelerarea

Odată ce a fost obținut vectorul de forță, putem calcula accelerația rezultată. Tine minte, F = ma, asa de a = F / m.

 funcția publică getAcc (vecForce: Vector2D): Vector2D // setarea accelerației datorată forței var vecAcc: Vector2D = vecForce.multiply (1 / this._mass); returna veccAcc; 

Pasul 13: Ball.as Calculați deplasarea

Cu accelerația calculată, putem calcula efectiv deplasarea rezultată.

Amintiți-vă că forța calculată se bazează de fapt pe deplasarea dintre centrul bilelor.

 funcția privată getDispTo (minge: Ball): Vector2D var curentVector: Vector2D = Vector2D nou (ball.x, ball.y); currentVector.minusVector (this._disp); retur actualVector;  funcția publică atrăgătăTo (minge: Ball): void var toCenter: Vector2D = this.getDispTo (minge); var actualForceAttract: Vector2D = this.getForceAttract (minge.mass, acest_mass, toCenter); this._acc = this.getAcc (actualForceAttract); this._velo.addVector (this._acc); this._disp.addVector (this._velo); 

Pasul 14: Balansarea deplasării implementării

Apoi, suntem capabili să ne mutăm mingea în noua sa locație, prin funcția de mai jos. Rețineți că deplasarea calculată nu este niciodată implementată direct pe poziția actuală a mingii. Un astfel de design este acela de a permite verificarea: detectarea coliziunilor între mingi.

 funcția publică funcțiaPosition (vecDisp: Vector2D): void this.x = Math.round (vecDisp.vecX); this.y = Math.round (vecDisp.vecY); 

Amintiți-vă, forța se bazează pe distanța dintre centre. Prin urmare, bilele vor pătrunde și vor continua să se deplaseze din cauza forței atractive, fiind mai mari atunci când sunt mai aproape. Trebuie să resetăm accelerația și viteza la 0 când bilele se ating între ele. Cu toate acestea, trebuie să obținem un mijloc de detectare a coliziunii dintre două bile.


Pasul 15: Detectarea coliziunii Ball.as

Coliziunea poate fi ușor verificată. Separarea între oricare două bile nu trebuie să fie mai mică decât suma razei lor. Iată funcția de detectare a coliziunii:

 funcția publică coliziuneInto (minge: Ball): Boolean var hit: Boolean = false; var minDist: Numărul = (lățimea bilei + această lățime) / 2; dacă (this.getDispTo (ball) .getMagnitude () < minDist)  hit = true;  return hit; 

Pasul 16: Calculați Ball.as pentru a respinge

De obicei, când a fost detectată o coliziune între două bile, starea lor se suprapune reciproc. Trebuie să ne asigurăm că ei vor sta bine pe margine și nu se vor suprapune. Cum? Putem deplasa una dintre mingi departe de cealalta, dar trebuie sa calculam deplasarea corecta pentru a ne ajusta mai intai. Iată calculul deplasării:

 funcția publică getRepel (minge: Ball): Vector2D var minDist: Number = (bal.width + this.width) / 2; // calcula distanta pentru a respinge var laBall: Vector2D = this.getDispTo (ball); var directToBall: Vector2D = toBall.getVectorDirection (); directToBall.multiply (minDist); directToBall.minusVector (toBall); directToBall.multiply (-1); retur directToBall; 

Pasul 17: Deplasați Deplasarea Ball.as pentru a respinge

După ce am calculat deplasarea corectă, trebuie să o implementăm. Acțiunea este ca respingerea uneia dintre bile. În plus, trebuie să facem încă două comenzi suplimentare. Amintiți-vă, avem de-a face cu un mediu dinamic. Chiar și după ce am setat deplasarea una dintre minge pe margine, accelerația datorată forței și viteza rezultată o vor anima, provocând o mișcare nedorită a jerking-ului în și out. Trebuie să resetăm aceste valori ale accelerației și ale vitezei la zero.

 funcția publică respinsăBy (minge: Ball): void this._acc.reset (); this._velo.reset (); var respingeDisp: Vector2D = getRepel (minge); this._disp.addVector (repelDisp); 

Pasul 18: Jocul Ball.as Animate

În cele din urmă, putem anima (render) mingea ca și cum ar fi fost atrasă de altul. Când se detectează o coliziune, deplasarea va fi reglată astfel încât să nu penetreze marginea. Acest lucru se va întâmpla mai întâi pentru bile atunci când se ciocnesc cu centrul și apoi pentru bile când se ciocnesc unul cu celălalt.

 funcția publică animată (centru: Ball, toate: Array): void this.attractedTo (center); dacă (collisionInto (centru)) this.repelledBy (centru); pentru (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); 

Pasul 19: Principalele variabile private

Trecem la ultima noastră clasă, Principal. Clasa principală este generată la începutul proiectului. Variabilele private vor include o singură minge care atrage toate celelalte și numărul de bile din prezentarea noastră Flash.

 privat var principal: Ball; private var totalBalls: int = 10;

Pasul 20: Main.as Draw Balls

Mai întâi de toate, ar trebui să inițializăm bilele. Va exista o minge principală care atrage toate celelalte. Celelalte sunt numite astfel încât referirea poate fi efectuată cu ușurință mai târziu.

 funcția privată createBalls (): void mainBall = new Ball (50, 0x00FF00); this.addChild (mainBall); pentru (var i: int = 0; i < this.totalBalls; i++)  var currentBall:Ball = new Ball(); currentBall.name = "ball" + i; this.addChild(currentBall);  

Pasul 21: Main.as Implementați interacțiunea cu bilele

Apoi, atribuiți evenimente mingii principale pentru a fi ușor de tras atunci când faceți clic și opriți când este lansat.

 funcția privată init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // punct de intrare createBalls (); mainBall.addEventListener (MouseEvent.MOUSE_DOWN, onMouseDown); stage.addEventListener (MouseEvent.MOUSE_UP, onMouseUp); animateAll ();  funcția privată onMouseUp (e: MouseEvent): void stopDrag ();  funcția privată onMouseDown (e: MouseEvent): void e.target.startDrag (); 

Pasul 22: Main.as Animate Balls

Animarea bilelor care sunt atrase de principalele. Un eveniment EnterFrame este atribuit fiecărei mingi.

 funcția privată animateAll (): void pentru (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); 

Pasul 23: Testați filmul

În cele din urmă, apăsați pe Ctrl + Enter pentru a previzualiza animația.


Concluzie

Pentru a aduce acest tutorial cu un pas mai departe, cititorii pot extinde acest proiect prin implementarea altor forțe liniare.

În orice caz, simulările servesc ca un instrument excelent în a furniza idei greu de explicat prin text și imagine simple într-un mediu de clasă în fizică, mai ales atunci când statul se schimbă în timp.

Sper că acest mic tutorial vă ajută într-un fel. Terima kasih (care este "mulțumesc" în Malaezia) pentru că ați luat timp să citiți și așteptați cu nerăbdare să auziți comentariile cititorilor colegi.

Cod