De studie van krachten is van centraal belang in dynamica, de studie van oorzaken van beweging en veranderingen in beweging. Zwaartekracht is een voorbeeld; dit zorgt ervoor dat satellieten rond planeten draaien en dat we op de grond blijven.
In deze tutorial zullen we een simulatie van een dergelijk fenomeen bouwen en kunnen we observeren, experimenteren en spelen met deeltjes ter plaatse.
Van alle gegenereerde deeltjes zal één hoofddeeltje anderen aantrekken. Terwijl deze deeltjes zich naar de belangrijkste verplaatsen, kunnen gebruikers op dit hoofddeeltje klikken om het rond te slepen, waardoor deze deeltjes hun koers verleggen. Deze deeltjes stoppen met bewegen als ze botsen met de rand van de hoofdbal, maar ze zullen elkaar niet overlappen.
De structuur van deze tutorial is zo gerangschikt dat een korte theorie in de natuurkunde werd geleverd voordat de implementatie van de simulatie werd geïntroduceerd. Genieten!
Laten we eens kijken naar het eindresultaat waar we naartoe zullen werken:
Klik en sleep de grote groene cirkel om hem te verplaatsen en kijk hoe de kleine blauwe cirkels reageren.
Ten eerste een voorwoord van de natuurkunde. De aantrekkelijke zwaartekracht tussen twee objecten wordt uitgedrukt door de volgende formule:
F: aantrekkelijke kracht wordt uitgeoefend op een object van belang (p2) door
een willekeurig deeltje (p1).
G: Gravitationele constante
m1: massa van p1
m2: massa van p2
r: afstand tussen p1 en P2
Let vooral op het volgende:
Om kracht in kinematica te vertalen, moeten we de versnelling van deeltjes berekenen. De beroemde vergelijking van Sir Isaac Newton wordt hieronder getoond:
F: zwaartekracht wordt uitgeoefend op een object van belang (p2)
m: massa van object van belang (p2)
een: versnelling van object of interest (p2) onder invloed van F
Hier impliceert de implicatie dat een hogere kracht uitgeoefend op deeltje A resulteert in een hogere versnelling (ervan uitgaande dat de massa hetzelfde blijft). Deze versnelling zal de snelheid van het deeltje veranderen.
Implementatie zal worden gedaan in FlashDevelop IDE. Bouw uw projectbestand.
Raadpleeg deze handleiding voor een inleiding tot FlashDevelop.
Er zijn 4 klassen om in map te maken \ Src \: Main.as, Vector2D.as, Ball.as & Math2.as. Het is raadzaam om al deze bestanden te downloaden van het bronpakket en probeer ze in te delen tegen de stappen om een algemeen begrip te krijgen van het mechanisme voordat u ze wijzigt. Hun rollen worden uitgedrukt zoals hieronder:
Naam van de klasse | Doel van de organisatie |
Main.as | Klasse om de ballen visueel te maken en om animatie aan evenementen te hechten. |
Vector2D | Klasse die alle vectormanipulatiefuncties bevat. |
Bal | Klasse die functies bevat om visueel een bal te genereren, die de dynamiek en de kinematica van een bal implementeert. |
Math2 | Statische klasse die een functie bevat om het willekeurig maken van de initiële locatie van ballen mogelijk te maken. |
Laten we eerst praten over de Math2-klasse. De onderstaande functie helpt om een willekeurig getal binnen het opgegeven bereik te genereren. Accepteert twee ingangen, minimumlimiet en maximale limiet binnen bereik.
publieke statische functie randomiseTween (bereik_min: int, bereik_max: int): int var bereik: int = bereik_max - bereik_min; var randomized: int = Math.random () * bereik + bereik_min; terugkeer gerandomiseerd;
Het grootste deel van de gebruikte wiskunde bevindt zich in Vector2D. Deze tutorial veronderstelt een vertrouwd niveau in vectoranalyse in de gebruikers. De onderstaande functies worden meestal gebruikt om vectorcomponenten te krijgen en in te stellen, plus een methode om alle componenten opnieuw in te stellen op nul. In elk geval, als je je niet op je gemak voelt met Vectors, bezoek dan een geweldige post op Euclidean Vectors van Daniel Sidhion.
public function Vector2D (valueX: Number, valueY: Number) this._x = valueX; this._y = valueY; openbare functieset vecX (valueX: Number): void this._x = valueX; public function get vecX (): Number return this._x openbare functieset vecY (waardeY: Number): void this._y = valueY; public function get vecY (): Number return this._y public function setVector (waardeX: Number, valueY: Number): void this._x = valueX; this._y = valueY; public function reset (): void this._x = 0; this._y = 0;
De belangrijkste toepassingen van Vector2D liggen in de volgende functies, die:
public function getMagnitude (): Number var lengthX: Number = this._x; var lengthY: Number = this._y; return Math.sqrt (lengthX * lengthX + lengthY * lengthY); public function getAngle (): Number var lengthX: Number = this._x; var lengthY: Number = this._y; return Math.atan2 (lengthY, lengthX); public function getVectorDirection (): Vector2D var vectorDirection: Vector2D = new Vector2D (this._x / this.getMagnitude (), this._y / this.getMagnitude ()); return Vector2D (vectorDirection); openbare functie minusVector (vector2: Vector2D): void this._x - = vector2.vecX; this._y - = vector2.vecY; public function addVector (vector2: Vector2D): void this._x + = vector2.vecX; this._y + = vector2.vecY; public function multiply (scalar: Number): void this._x * = scalar; this._y * = scalar;
De Bal
klas is waar alle interessante operaties plaatsvinden. Om met onze animatie te beginnen, moeten we een bal tekenen en verschillende kinematica- en dynamiekgerelateerde variabelen instellen. De functie om een bal te tekenen is als volgt:
persoonlijke functie draw (straal: Number, color: uint): void graphics.beginFill (color, 1); graphics.drawCircle (0, 0, radius); graphics.endFill ();
De genoemde verschillende kinematica en dynamiek gerelateerde variabelen zijn als volgt aangegeven:
privé var _disp: Vector2D; // verplaatsingsvector, ten opzichte van de oorsprong private var _velo: Vector2D; // velocity vector private var _acc: Vector2D; // versnellingsvector private var _attractive_coeff: Number = 500; private var _mass: Number;
Terwijl de constructor van de klasse Ball wordt genoemd, worden afbeeldingen getekend. Eenmaal getekend, wordt de bal willekeurig op het podium geplaatst. We zullen ook de privévariabelen instellen. Alle vectorgrootheden worden ook geïnitialiseerd op 0, behalve de verplaatsing die wordt gemeten ten opzichte van de oorsprong.
openbare functie Ball (radius: Number = 20, color: uint = 0x0000FF) this.draw (radius, color); this._mass = radius / 2; // veronderstelt dat de massa de helft van de straal is this.x = Math2.randomiseTween (0, 550); this.y = Math2.randomiseBtween (0, 400); this._disp = nieuwe Vector2D (this.x, this.y); // stel initiële verplaatsing in this._velo = new Vector2D (0, 0); this._acc = nieuwe Vector2D (0, 0);
We moeten de onderliggende kracht berekenen die ervoor zorgt dat onze deeltjes gaan animeren. Raad eens, het is de zwaartekracht. De onderstaande functie zal helpen bij het berekenen van deze kracht. Merk op dat er een dop op de versnelling is aangebracht bij 5
. De horizontale en verticale krachtcomponenten worden afgeleid met behulp van trigonometrie; de bovenstaande animatie kan helpen om de wiskunde hiervan te begrijpen.
public function get massa (): Number return _mass; private functie getForceAttract (m1: Number, m2: Number, vec2Center: Vector2D): Vector2D / * berekent aantrekkingskracht op basis van de volgende formule: * F = K * m1 * m2 / r * r * / var countator: Number = this._attractive_coeff * m1 * m2; var noemer: Number = vec2Center.getMagnitude () * vec2Center.getMagnitude (); var forceMagnitude: Number = countator / denominator; var forceDirection: Number = vec2Center.getAngle (); // een cap instellen als (forceMagnitude> 0) forceMagnitude = Math.min (forceMagnitude, 5); // afleidende krachtcomponent, horizontaal, verticaal var forceX: Number = forceMagnitude * Math.cos (forceDirection); var forceY: Number = forceMagnitude * Math.sin (forceDirection); var force: Vector2D = new Vector2D (forceX, forceY); terugkeerkracht;
Zodra de force-vector is verkregen, kunnen we de resulterende versnelling berekenen. Onthouden, F = ma
, zo a = F / m
.
public function getAcc (vecForce: Vector2D): Vector2D // setting acceleration vanwege force var vecAcc: Vector2D = vecForce.multiply (1 / this._mass); return veccAcc;
Met de versnelling berekend, kunnen we de resulterende verplaatsing effectief berekenen.
Vergeet niet dat de berekende kracht eigenlijk gebaseerd is op de verplaatsing tussen het midden van de ballen.
private function getDispTo (ball: Ball): Vector2D var currentVector: Vector2D = new Vector2D (ball.x, ball.y); currentVector.minusVector (this._disp); return currentVector; public function attractedTo (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);
Dan zijn we in staat om onze bal naar zijn nieuwe locatie te verplaatsen, via de onderstaande functie. Merk op dat de berekende verplaatsing nooit wordt toegepast op de huidige locatie van de bal. Een dergelijk ontwerp is om controle mogelijk te maken: detectie van botsingen tussen ballen.
public function setPosition (vecDisp: Vector2D): void this.x = Math.round (vecDisp.vecX); this.y = Math.round (vecDisp.vecY);
Denk eraan, de kracht is gebaseerd op de afstand tussen de centra. Daarom zullen de ballen doordringen en blijven bewegen omdat de aantrekkingskracht groter is wanneer ze dichterbij zijn. We moeten de versnelling en snelheid opnieuw instellen op 0 als de ballen elkaars rand raken. We moeten echter een manier vinden om de botsing tussen twee ballen te detecteren.
Botsing kan eenvoudig worden gecontroleerd. De scheiding tussen twee ballen mag niet minder zijn dan de som van hun stralen. Dit is de functie voor botsingsdetectie:
public function collisionInto (ball: Ball): Boolean var hit: Boolean = false; var minDist: Number = (ball.width + this.width) / 2; if (this.getDispTo (ball) .getMagnitude () < minDist) hit = true; return hit;
Meestal overlapt elkaar de situatie wanneer een botsing tussen twee ballen is gedetecteerd. We moeten ervoor zorgen dat ze gewoon netjes op de rand blijven zitten en elkaar niet overlappen. Hoe? We kunnen een van de ballen van de andere weg verplaatsen, maar we moeten de juiste verplaatsing berekenen om als eerste aan te passen. Dit is de verplaatsingsberekening:
publieke functie getRepel (ball: Ball): Vector2D var minDist: Number = (ball.width + this.width) / 2; // bereken de afstand om var naar Ball af te weren: Vector2D = this.getDispTo (ball); var directToBall: Vector2D = toBall.getVectorDirection (); directToBall.multiply (minDist); directToBall.minusVector (Toball); directToBall.multiply (-1); return directToBall;
Nadat we de juiste verplaatsing hebben berekend, moeten we deze uitvoeren. De actie is als het afstoten van een van de ballen. Daarnaast moeten we nog twee extra opdrachten uitvoeren. Denk eraan, we hebben te maken met een dynamische omgeving. Zelfs nadat we de verplaatsing van een van de ballen op de rand hebben ingesteld, zal versnelling als gevolg van kracht en de resulterende snelheid deze animeren, wat een ongewenste beweging van schokken in en uit veroorzaakt. We moeten deze waarden van versnelling en snelheid op nul zetten.
publieke functie afgestotenDoor (ball: Ball): void this._acc.reset (); this._velo.reset (); var repelDisp: Vector2D = getRepel (ball); this._disp.addVector (repelDisp);
Ten slotte kunnen we onze bal animeren (renderen) alsof deze door een ander wordt aangetrokken. Wanneer een botsing wordt gedetecteerd, wordt de verplaatsing zodanig aangepast dat deze niet in de rand kan doordringen. Dit gebeurt eerst voor de ballen als ze botsen met het midden en dan voor de ballen als ze tegen elkaar botsen.
public function animate (center: Ball, all: Array): void this.attractedTo (center); if (collisionInto (center)) this.repelledBy (center); for (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);
Doorgaan naar onze laatste klas, Hoofd
. Hoofdklasse wordt gegenereerd aan het begin van het project. Particuliere variabelen omvatten de ene bal die alle anderen aantrekt en het aantal ballen in onze Flash-presentatie.
privévar mainBall: Ball; private var totalBalls: int = 10;
Allereerst moeten we ballen initialiseren. Er zal één hoofdbal zijn die alle anderen aantrekt. De andere namen zijn genoemd, zodat het later eenvoudig kan worden gerefereerd.
private function createBalls (): void mainBall = new Ball (50, 0x00FF00); this.addChild (mainBall); for (var i: int = 0; i < this.totalBalls; i++) var currentBall:Ball = new Ball(); currentBall.name = "ball" + i; this.addChild(currentBall);
Wijs vervolgens gebeurtenissen toe aan de hoofdbal om deze te verslepen wanneer erop wordt geklikt en stop wanneer deze wordt vrijgegeven.
private function init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // startpunt createBalls (); mainBall.addEventListener (MouseEvent.MOUSE_DOWN, onMouseDown); stage.addEventListener (MouseEvent.MOUSE_UP, onMouseUp); animateAll (); private function onMouseUp (e: MouseEvent): void stopDrag (); private function onMouseDown (e: MouseEvent): void e.target.startDrag ();
Ballen animeren die worden aangetrokken door de hoofdrolspeler. Aan elke bal is een EnterFrame-gebeurtenis toegewezen.
privéfunctie animerenAlle (): 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);
Druk ten slotte op Ctrl + Enter om een voorbeeld van de animatie te bekijken.
Om deze tutorial een stap verder te brengen, kunnen lezers dit project uitbreiden door andere lineaire krachten te implementeren.
In elk geval dienen simulaties als een geweldig hulpmiddel bij het leveren van ideeën die moeilijk te verklaren zijn door platte tekst en afbeelding in een Physics-klaslokaalomgeving, vooral wanneer de staat in de loop van de tijd verandert.
Ik hoop dat deze kleine tutorial je op een of andere manier helpt. Terima kasih (dat is "dank u" in Maleisië) voor het nemen van de tijd om te lezen en kijken uit naar het horen van opmerkingen van collega-lezers.