Schwerkraft in Aktion
German (Deutsch) translation by Nikol Angelowa (you can also view the original English article)
Die Untersuchung von Kräften ist von zentralem Interesse für die Dynamik, die Untersuchung von Bewegungsursachen und Bewegungsänderungen. Die Gravitationskraft ist ein Beispiel; Dies ist es, was dazu führt, dass sich Satelliten um Planeten drehen und wir am Boden bleiben.
In diesem Tutorial erstellen wir eine Simulation eines solchen Phänomens und können Partikel in der Szene beobachten, experimentieren und damit spielen.
Unter allen erzeugten Partikeln zieht ein Hauptpartikel andere an. Wenn sich diese Partikel in Richtung des Hauptpartikels bewegen, können Benutzer auf dieses Hauptpartikel klicken, um es herumzuziehen, wodurch diese Partikel ihren Kurs umleiten. Diese Partikel hören auf, sich zu bewegen, wenn sie mit der Kante der Hauptkugel kollidieren, aber sie überlappen sich nicht.
Die Struktur dieses Tutorials ist so angeordnet, dass eine kurze Theorie in Physik geliefert wird, bevor die Implementierung der Simulation eingeführt wird. Genießen!
Vorschau des Endergebnisses
Werfen wir einen Blick auf das Endergebnis, auf das wir hinarbeiten werden:
Klicken und ziehen Sie den großen grünen Kreis, um ihn zu verschieben, und beobachten Sie, wie die kleinen blauen Kreise reagieren.
Schritt 1: Gravitationskraft, Formel


Zunächst ein Physik-Vorwort. Die anziehende Gravitationskraft zwischen zwei beliebigen Objekten wird durch die folgende Formel ausgedrückt:
F: Anziehungskraft, die von auf das interessierende Objekt (p2) ausgeübt wird ein beliebiges Teilchen (p1).
G: Gravitationskonstante
m1: Masse von p1
m2: Masse von p2
r: Abstand zwischen p1 und p2
Beachten Sie insbesondere Folgendes:
- Die Beziehung zwischen Schwerkraft und Entfernung: F ist umgekehrt proportional zum Quadrat der Entfernung, die die beiden Teilchen trennt. Dies bedeutet, je näher A und B beieinander liegen, desto höher ist die Anziehungskraft zwischen ihnen und umgekehrt. Wenn Sie den Abstand verdoppeln, sinkt die Kraft auf ein Viertel ihres ursprünglichen Wertes.
- Der Wert der Gravitationskonstante G beträgt wissenschaftlich 6,67259 × 10–11 N * m2 / kg2. 500 ersetzt diesen Wert jedoch in der Flash-Umgebung.
- Wir können die Partikelbreite mit ihrer Masse in Beziehung setzen. In diesem Beispiel habe ich die Masse eines Partikels als die Hälfte seines Radius definiert.
Schritt 2: Newtons 2. Gesetz, Gleichung
Um Kraft in Kinematik umzuwandeln, müssen wir die Teilchenbeschleunigung berechnen. Die berühmte Gleichung von Sir Isaac Newton ist unten dargestellt:


F: Gravitationskraft, die auf das interessierende Objekt ausgeübt wird (p2)
m: Masse des interessierenden Objekts (p2)
a: Beschleunigung des interessierenden Objekts (p2) unter Einfluss von F.
Hier bedeutet dies, dass eine höhere Kraft, die auf Teilchen A ausgeübt wird, zu einer höheren Beschleunigung führt (vorausgesetzt, seine Masse bleibt gleich). Diese Beschleunigung ändert die Geschwindigkeit des Partikels.
Schritt 3: Projekt starten
Die Implementierung erfolgt in FlashDevelop IDE. Erstellen Sie Ihre Projektdatei.
- Starten Sie ein neues Projekt, PROJEKT > NEUES PROJEKT…
- Wählen Sie aus dem Popup-Fenster AS3 PROJECT
- Nennen Sie Ihr Projekt. In meinem Fall Attraktor
- Wählen Sie Ihren Projektstandort
In diesem Handbuch finden Sie eine Einführung in FlashDevelop.
Schritt 4: Klassen, die Sie brauchen
Im Ordner \src\ können 4 Klassen erstellt werden: Main.as, Vector2D.as, Ball.as & Math2.as. Es ist ratsam, dass Sie alle diese Dateien aus dem Quellpaket herunterladen und versuchen, sie den Schritten zuzuordnen, um ein allgemeines Verständnis des Mechanismus zu erhalten, bevor Sie sie ändern. Ihre Rollen werden wie folgt ausgedrückt:
| Klassenname | Zweck der Organisation |
| Main.as | Klasse zum visuellen Erstellen der Bälle und zum Anhängen von Animationen an Ereignisse. |
| Vector2D | Klasse, die alle Vektormanipulationsfunktionen enthält. |
| Ball | Eine Klasse, die Funktionen zum visuellen Erzeugen eines Balls enthält, implementiert die Dynamik und Kinematik eines Balls. |
| Math2 | Statische Klasse, die eine Funktion enthält, die das Randomisieren der anfänglichen Position von Bällen erleichtert. |
Schritt 5: Randomisieren von Werten
Lassen Sie uns zuerst über die Math2-Klasse sprechen. Die folgende Funktion hilft dabei, eine Zufallszahl innerhalb des angegebenen Bereichs zu generieren. Akzeptiert zwei Eingänge, Mindestgrenze und Höchstgrenze im Bereich.
1 |
public static function randomiseBetween(range_min:int, range_max:int):int |
2 |
{
|
3 |
var range:int = range_max - range_min; |
4 |
var randomised:int = Math.random() * range + range_min; |
5 |
return randomised; |
6 |
}
|
Schritt 6: Vector2D, Getter und Setter
Der Großteil der verwendeten Mathematik befindet sich in Vector2D. In diesem Lernprogramm wird davon ausgegangen, dass die Benutzer mit der Vektoranalyse vertraut sind. Die folgenden Funktionen werden im Allgemeinen verwendet, um Vektorkomponenten abzurufen und festzulegen, sowie eine Methode zum Zurücksetzen aller Komponenten auf Null. Wenn Sie sich mit Vektoren nicht wohl fühlen, besuchen Sie auf jeden Fall einen großartigen Beitrag über euklidische Vektoren von Daniel Sidhion.
1 |
public function Vector2D(valueX:Number, valueY:Number) |
2 |
{
|
3 |
this._x = valueX; |
4 |
this._y = valueY; |
5 |
}
|
6 |
public function set vecX(valueX:Number):void |
7 |
{
|
8 |
this._x = valueX; |
9 |
}
|
10 |
public function get vecX():Number |
11 |
{
|
12 |
return this._x |
13 |
}
|
14 |
public function set vecY(valueY:Number):void |
15 |
{
|
16 |
this._y = valueY; |
17 |
}
|
18 |
public function get vecY():Number |
19 |
{
|
20 |
return this._y |
21 |
}
|
22 |
public function setVector(valueX:Number, valueY:Number):void |
23 |
{
|
24 |
this._x = valueX; |
25 |
this._y = valueY; |
26 |
}
|
27 |
public function reset():void |
28 |
{
|
29 |
this._x = 0; |
30 |
this._y = 0; |
31 |
}
|
Schritt 7: Vector2D, Operationen
Die Hauptanwendungen von Vector2D liegen in den folgenden Funktionen:
- Ermitteln Sie die Größe des Vektors
- Ermitteln Sie den Winkel, den der Vektor in Bezug auf den Ursprung bildet
- Erhalten Sie die Vektorrichtung des Vektors
- Führen Sie einfache Vektoroperationen für Addition, Subtraktion und Skalar aus Multiplikation
1 |
public function getMagnitude():Number |
2 |
{
|
3 |
var lengthX:Number = this._x; |
4 |
var lengthY:Number = this._y; |
5 |
return Math.sqrt(lengthX * lengthX +lengthY * lengthY); |
6 |
}
|
7 |
public function getAngle():Number |
8 |
{
|
9 |
var lengthX:Number = this._x; |
10 |
var lengthY:Number = this._y; |
11 |
return Math.atan2(lengthY, lengthX); |
12 |
}
|
13 |
public function getVectorDirection():Vector2D |
14 |
{
|
15 |
var vectorDirection:Vector2D = new Vector2D(this._x / this.getMagnitude(), this._y / this.getMagnitude()); |
16 |
return Vector2D(vectorDirection); |
17 |
}
|
18 |
public function minusVector(vector2:Vector2D):void |
19 |
{
|
20 |
this._x -= vector2.vecX; |
21 |
this._y -= vector2.vecY; |
22 |
}
|
23 |
public function addVector(vector2:Vector2D):void |
24 |
{
|
25 |
this._x += vector2.vecX; |
26 |
this._y += vector2.vecY; |
27 |
}
|
28 |
public function multiply (scalar:Number):void |
29 |
{
|
30 |
this._x *= scalar; |
31 |
this._y *= scalar; |
32 |
}
|
Schritt 8: Ball.as Zeichnung
In der Ball klasse finden alle interessanten Operationen statt. Um mit unserer Animation zu beginnen, müssen wir einen Ball zeichnen und mehrere kinematik- und dynamikbezogene Variablen festlegen. Die Funktion zum Zeichnen eines Balls ist wie folgt:
1 |
private function draw(radius:Number, color:uint) :void |
2 |
{
|
3 |
graphics.beginFill(color, 1); |
4 |
graphics.drawCircle(0, 0, radius); |
5 |
graphics.endFill(); |
6 |
}
|
Schritt 9: Ball.as private Variablen
Die verschiedenen kinematik- und dynamikbezogenen Variablen sind nachstehend aufgeführt:
1 |
private var _disp:Vector2D; //displacement vector, relative to the origin |
2 |
private var _velo:Vector2D; //velocity vector |
3 |
private var _acc:Vector2D; //acceleration vector |
4 |
private var _attractive_coeff:Number = 500; |
5 |
private var _mass:Number; |
Schritt 10: Ball.as Initiation
Wie der Konstruktor der Ball-Klasse genannt wird, werden Grafiken gezeichnet. Nach dem Ziehen wird der Ball zufällig auf die Bühne gelegt. Wir werden auch die privaten Variablen setzen. Alle Vektorgrößen werden ebenfalls bei 0 initialisiert, mit Ausnahme der Verschiebung, die relativ zum Ursprung gemessen wird.
1 |
public function Ball(radius:Number = 20, color:uint = 0x0000FF) |
2 |
{
|
3 |
this.draw(radius, color); |
4 |
this._mass = radius / 2; //assuming mass is half of radius |
5 |
this.x = Math2.randomiseBetween(0, 550); |
6 |
this.y = Math2.randomiseBetween(0, 400); |
7 |
this._disp = new Vector2D(this.x, this.y); //set initial displacement |
8 |
this._velo = new Vector2D(0, 0); |
9 |
this._acc = new Vector2D(0, 0); |
10 |
}
|
Schritt 11: Ball.as Berechnung der Anziehungskraft
Wir müssen die zugrunde liegende Kraft berechnen, durch die unsere Partikel animiert werden. Ratet mal, es ist die Gravitationskraft. Die folgende Funktion hilft bei der Berechnung dieser Kraft. Beachten Sie, dass die Beschleunigung bei 5 mit einer Kappe versehen ist. Die horizontalen und vertikalen Kraftkomponenten werden mithilfe der Trigonometrie abgeleitet. Die obige Animation kann zum Verständnis der Mathematik beitragen.
1 |
public function get mass():Number |
2 |
{
|
3 |
return _mass; |
4 |
}
|
5 |
private function getForceAttract (m1:Number, m2:Number, vec2Center:Vector2D):Vector2D |
6 |
{
|
7 |
/* calculate attractive force based on the following formula:
|
8 |
* F = K * m1 * m2 / r * r
|
9 |
*/
|
10 |
var numerator:Number = this._attractive_coeff * m1 * m2; |
11 |
var denominator:Number = vec2Center.getMagnitude() * vec2Center.getMagnitude(); |
12 |
var forceMagnitude:Number = numerator / denominator; |
13 |
var forceDirection:Number = vec2Center.getAngle(); |
14 |
|
15 |
//setting a cap
|
16 |
if (forceMagnitude > 0) forceMagnitude = Math.min(forceMagnitude, 5); |
17 |
|
18 |
//deriving force component, horizontal, vertical
|
19 |
var forceX:Number = forceMagnitude * Math.cos(forceDirection); |
20 |
var forceY:Number = forceMagnitude * Math.sin(forceDirection); |
21 |
var force:Vector2D = new Vector2D(forceX, forceY); |
22 |
return force; |
23 |
}
|
Schritt 12: Ball.as Beschleunigung berechnen
Sobald der Kraftvektor erhalten wurde, können wir die resultierende Beschleunigung berechnen. Denken Sie daran, F = ma, also a = F/m.
1 |
public function getAcc(vecForce:Vector2D):Vector2D |
2 |
{
|
3 |
//setting acceleration due to force
|
4 |
var vecAcc:Vector2D = vecForce.multiply(1 / this._mass); |
5 |
return veccAcc; |
6 |
}
|
Schritt 13: Ball.as Verschiebung berechnen
Mit der berechneten Beschleunigung können wir die resultierende Verschiebung effektiv berechnen.
Denken Sie daran, dass die berechnete Kraft tatsächlich auf der Verschiebung zwischen der Mitte der Kugeln basiert.
1 |
private function getDispTo(ball:Ball):Vector2D |
2 |
{
|
3 |
var currentVector:Vector2D = new Vector2D(ball.x, ball.y); |
4 |
currentVector.minusVector(this._disp); |
5 |
return currentVector; |
6 |
}
|
7 |
public function attractedTo(ball:Ball) :void |
8 |
{
|
9 |
var toCenter:Vector2D = this.getDispTo(ball); |
10 |
var currentForceAttract:Vector2D = this.getForceAttract(ball.mass, this._mass, toCenter); |
11 |
this._acc = this.getAcc(currentForceAttract); |
12 |
this._velo.addVector(this._acc); |
13 |
this._disp.addVector(this._velo); |
14 |
}
|
Schritt 14: Ball.as Implementierung der Verschiebung
Dann können wir unseren Ball durch die folgende Funktion an seinen neuen Ort bewegen. Beachten Sie, dass die berechnete Verschiebung niemals sofort auf die aktuelle Position des Balls implementiert wird. Ein solches Design soll eine Überprüfung ermöglichen: Kollisionserkennung zwischen Kugeln.
1 |
public function setPosition(vecDisp:Vector2D):void |
2 |
{
|
3 |
this.x = Math.round(vecDisp.vecX); |
4 |
this.y = Math.round(vecDisp.vecY); |
5 |
}
|
Denken Sie daran, dass die Kraft auf dem Abstand zwischen den Zentren basiert. Daher dringen die Kugeln ein und bewegen sich weiter, da die Anziehungskraft höher ist, wenn sie näher sind. Wir müssen Beschleunigung und Geschwindigkeit auf 0 zurücksetzen, wenn die Kugeln die Kante des anderen berühren. Wir müssen jedoch ein Mittel erhalten, um die Kollision zwischen zwei Kugeln zu erfassen.
Schritt 15: Ball.as Kollisionserkennung
Kollision kann leicht überprüft werden. Der Abstand zwischen zwei beliebigen Kugeln sollte nicht kleiner sein als die Summe ihrer Radien. Hier ist die Kollisionserkennungsfunktion:
1 |
public function collisionInto (ball:Ball):Boolean |
2 |
{
|
3 |
var hit:Boolean = false; |
4 |
var minDist:Number = (ball.width + this.width) / 2; |
5 |
|
6 |
if (this.getDispTo(ball).getMagnitude() < minDist) |
7 |
{
|
8 |
hit = true; |
9 |
}
|
10 |
|
11 |
return hit; |
12 |
}
|
Schritt 16: Ball.as Berechnen Verschieben, um abzustoßen


Wenn eine Kollision zwischen zwei Kugeln festgestellt wurde, überlappt sich ihr Zustand normalerweise. Wir müssen sicherstellen, dass sie nur schön am Rand sitzen und sich nicht überlappen. Wie? Wir können eine der Kugeln von der anderen weg verschieben, aber wir müssen die richtige Verschiebung berechnen, um sie zuerst anzupassen. Hier ist die Verschiebungsberechnung:
1 |
public function getRepel (ball:Ball): Vector2D |
2 |
{
|
3 |
var minDist:Number = (ball.width + this.width) / 2; |
4 |
//calculate distance to repel
|
5 |
var toBall:Vector2D = this.getDispTo(ball); |
6 |
var directToBall:Vector2D = toBall.getVectorDirection(); |
7 |
directToBall.multiply(minDist); |
8 |
directToBall.minusVector(toBall); |
9 |
directToBall.multiply( -1); |
10 |
return directToBall; |
11 |
}
|
Schritt 17: Ball.as Implementierung der Verschiebung zur Abwehr


Nachdem wir die richtige Verschiebung berechnet haben, müssen wir sie implementieren. Die Aktion ist wie das Abstoßen eines der Bälle. Zusätzlich müssen wir zwei weitere Befehle ausführen. Denken Sie daran, wir haben es mit einer dynamischen Umgebung zu tun. Selbst nachdem wir die Verschiebung eines Balls auf die Kante eingestellt haben, wird sie durch die Beschleunigung aufgrund der Kraft und der daraus resultierenden Geschwindigkeit animiert, was zu einer unerwünschten Bewegung des Ein- und Ausstoßens führt. Wir müssen diese Werte für Beschleunigung und Geschwindigkeit auf Null zurücksetzen.
1 |
public function repelledBy(ball:Ball):void |
2 |
{
|
3 |
this._acc.reset(); |
4 |
this._velo.reset(); |
5 |
var repelDisp:Vector2D = getRepel(ball); |
6 |
this._disp.addVector(repelDisp); |
7 |
}
|
Schritt 18: Ball.as animieren
Schließlich können wir unseren Ball animieren (rendern), als würde er von einem anderen angezogen. Wenn eine Kollision erkannt wird, wird die Verschiebung so angepasst, dass sie die Kante nicht durchdringt. Dies geschieht zuerst für die Bälle, wenn sie mit der Mitte kollidieren, und dann für die Bälle, wenn sie miteinander kollidieren.
1 |
public function animate(center:Ball, all:Array):void |
2 |
{
|
3 |
this.attractedTo(center); |
4 |
if (collisionInto(center)) this.repelledBy(center); |
5 |
for (var i:int = 0; i < all.length; i++) |
6 |
{
|
7 |
var current_ball:Ball = all[i] as Ball; |
8 |
if (collisionInto(current_ball) && current_ball.name != this.name) this.repelledBy(current_ball); |
9 |
}
|
10 |
this.setPosition(this._disp); |
11 |
}
|
Schritt 19: Main.as Private Variablen
Weiter zu unserer letzten Klasse, Main. Die Hauptklasse wird zu Beginn des Projekts generiert. Zu den privaten Variablen gehören der eine Ball, der alle anderen anzieht, und die Anzahl der Bälle in unserer Flash-Präsentation.
1 |
private var mainBall:Ball; |
2 |
private var totalBalls:int = 10; |
Schritt 20: Main.as Draw Balls
Zunächst sollten wir die Bälle initialisieren. Es wird einen Hauptball geben, der alle anderen anzieht. Die anderen werden benannt, damit die Referenzierung später problemlos erfolgen kann.
1 |
private function createBalls ():void |
2 |
{
|
3 |
mainBall = new Ball(50, 0x00FF00); |
4 |
this.addChild(mainBall); |
5 |
for (var i:int = 0; i < this.totalBalls; i++) |
6 |
{
|
7 |
var currentBall:Ball = new Ball(); |
8 |
currentBall.name = "ball" + i; |
9 |
this.addChild(currentBall); |
10 |
}
|
11 |
}
|
Schritt 21: Main.as Implementieren der Ballinteraktion
Weisen Sie dann dem Hauptball Ereignisse zu, um ihn beim Klicken ziehbar zu machen und beim Loslassen anzuhalten.
1 |
private function init(e:Event = null):void |
2 |
{
|
3 |
removeEventListener(Event.ADDED_TO_STAGE, init); |
4 |
// entry point
|
5 |
createBalls(); |
6 |
mainBall.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); |
7 |
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); |
8 |
animateAll(); |
9 |
}
|
10 |
private function onMouseUp(e:MouseEvent):void |
11 |
{
|
12 |
stopDrag(); |
13 |
}
|
14 |
private function onMouseDown(e:MouseEvent):void |
15 |
{
|
16 |
e.target.startDrag(); |
17 |
}
|
Schritt 22: Main.as Animate Balls
Animierende Bälle, die von der Hauptleitung angezogen werden. Jedem Ball wird ein EnterFrame-Ereignis zugewiesen.
1 |
private function animateAll():void |
2 |
{
|
3 |
for (var i:uint = 0; i < totalBalls; i++) |
4 |
{
|
5 |
//each ball is pulled by main_ball
|
6 |
var current_ball:Ball = this.getChildByName("ball" + i) as Ball; |
7 |
current_ball.addEventListener(Event.ENTER_FRAME, enterFrame); |
8 |
}
|
9 |
}
|
10 |
private function enterFrame(e:Event):void |
11 |
{
|
12 |
var allObj:Array = new Array(); |
13 |
for (var i:int = 0; i <= totalBalls; i++) |
14 |
{
|
15 |
var current_ball:Ball = this.getChildAt(i) as Ball; |
16 |
allObj.push(current_ball); |
17 |
}
|
18 |
e.target.animate(mainBall, allObj); |
19 |
}
|
Schritt 23: Film testen
Drücken Sie abschließend Strg + Eingabetaste, um eine Vorschau der Animation anzuzeigen.
Abschluss
Um dieses Tutorial noch einen Schritt weiter zu bringen, können Leser dieses Projekt erweitern, indem sie andere lineare Kräfte implementieren.
In jedem Fall sind Simulationen ein großartiges Werkzeug, um Ideen zu liefern, die in einer Unterrichtsumgebung für Physik nur schwer durch einfachen Text und Bild zu erklären sind, insbesondere wenn sich der Zustand im Laufe der Zeit ändert.
Ich hoffe, dieses kleine Tutorial hilft Ihnen irgendwie. Terima kasih (das ist "Danke" in Malaysia), dass sie sich die Zeit zum Lesen genommen hat und sich darauf freut, Kommentare von anderen Lesern zu hören.



