Lo studio delle forze è di interesse centrale nelle dinamiche, nello studio delle cause del movimento e dei cambiamenti nel movimento. Forza gravitazionale è un esempio; è questo che fa sì che i satelliti ruotino attorno ai pianeti e noi rimaniamo a terra.
In questo tutorial, costruiremo una simulazione di tale fenomeno e saremo in grado di osservare, sperimentare e giocare con le particelle sulla scena.
Tra tutte le particelle generate, una particella principale attrarrà altre. Mentre queste particelle si muovono verso la principale, gli utenti possono fare clic su questa particella principale per trascinarla, facendo sì che queste particelle reindirizzino la loro rotta. Queste particelle smetteranno di muoversi mentre entrano in collisione con il bordo della palla principale, ma non si sovrapporranno l'una con l'altra.
La struttura di questo tutorial è organizzata in modo da fornire una breve teoria in fisica prima di introdurre l'implementazione della simulazione. Godere!
Diamo un'occhiata al risultato finale su cui lavoreremo:
Fai clic e trascina il grande cerchio verde per spostarlo, e osserva come reagiscono i piccoli cerchi blu.
Innanzitutto, una prefazione fisica. La forza gravitazionale attraente tra due oggetti è espressa attraverso la seguente formula:
F: forza attrattiva esercitata su oggetto di interesse (p2) di
una particella arbitraria (p1).
sol: Costante gravitazionale
m1: massa di p1
m2: massa di p2
r: distanza tra p1 e p2
Prendete nota in particolare di quanto segue:
Per tradurre la forza in cinematica, dobbiamo calcolare l'accelerazione della particella. La famosa equazione di Sir Isaac Newton è la seguente:
F: forza gravitazionale esercitata sull'oggetto di interesse (p2)
m: massa dell'oggetto di interesse (p2)
un: accelerazione dell'oggetto di interesse (p2) sotto l'influenza di F
Qui, l'implicazione è che una forza più alta applicata sulla particella A produce un'accelerazione più alta (supponendo che la sua massa rimanga la stessa). Questa accelerazione cambierà la velocità della particella.
L'implementazione verrà eseguita in FlashDevelop IDE. Costruisci il tuo file di progetto.
Vedi questa guida per un'introduzione a FlashDevelop.
Ci sono 4 classi da creare nella cartella \ Src \: Main.as, Vector2D.as, Ball.as e Math2.as. È consigliabile scaricare tutti questi file dal pacchetto sorgente e provare a mapparli in base ai passaggi per ottenere una comprensione generale del meccanismo prima di modificarli. I loro ruoli sono espressi come di seguito:
Nome della classe | Scopo dell'organizzazione |
Main.as | Classe per creare visivamente le sfere e associare animazioni agli eventi. |
Vector2D | Classe che contiene tutte le funzioni di manipolazione vettoriale. |
Palla | Classe che contiene funzioni per generare visivamente una palla, implementa dinamiche e cinematiche di una palla. |
math2 | Classe statica che contiene una funzione per facilitare la randomizzazione della posizione iniziale delle palle. |
Parliamo prima della classe Math2. La funzione seguente aiuterà a generare un numero casuale nell'intervallo specificato. Accetta due ingressi, un limite minimo e un limite massimo nell'intervallo.
public static function randomiseBetween (range_min: int, range_max: int): int var range: int = range_max - range_min; var randomized: int = Math.random () * range + range_min; ritorno randomizzato;
La maggior parte della matematica utilizzata si trova in Vector2D. Questo tutorial presuppone un livello di familiarità nell'analisi dei vettori negli utenti. Le funzioni di seguito sono generalmente utilizzate per ottenere e impostare componenti vettoriali, oltre a un metodo per ripristinare tutti i componenti a zero. In ogni caso, se sei a disagio con i Vettori, visita un ottimo post sui Vettori Euclidei di Daniel Sidhion.
funzione pubblica Vector2D (valoreX: numero, valoreY: numero) this._x = valoreX; questo._y = valoreY; public function set vecX (valueX: Number): void this._x = valueX; public function get vecX (): Number return this._x public function set vecY (valueY: Number): void this._y = valueY; public function get vecY (): Number return this._y public function setVector (valueX: Number, valueY: Number): void this._x = valueX; questo._y = valoreY; public function reset (): void this._x = 0; this._y = 0;
I principali usi di Vector2D sono le seguenti funzioni, che:
funzione pubblica 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; restituire Math.atan2 (lengthY, lengthX); public function getVectorDirection (): Vector2D var vectorDirection: Vector2D = new Vector2D (this._x / this.getMagnitude (), this._y / this.getMagnitude ()); return Vector2D (vectorDirection); public function minusVector (vector2: Vector2D): void this._x - = vector2.vecX; this._y - = vettore2.vecY; public function addVector (vector2: Vector2D): void this._x + = vector2.vecX; this._y + = vettore2.vecY; public function multiply (scalar: Number): void this._x * = scalare; this._y * = scalare;
Il Palla
la classe è dove avvengono tutte le operazioni interessanti. Per iniziare la nostra animazione, dobbiamo disegnare una palla e impostare diverse variabili cinematiche e relative alla dinamica. La funzione per disegnare una palla è la seguente:
private function draw (raggio: Number, color: uint): void graphics.beginFill (color, 1); graphics.drawCircle (0, 0, raggio); graphics.endFill ();
Le citate diverse cinematiche e variabili relative alla dinamica sono indicate come segue:
private var _disp: Vector2D; // vettore di spostamento, relativo all'origine private var _velo: Vector2D; // velocity vector private var _acc: Vector2D; // vettore accelerazione private var _attractive_coeff: Number = 500; private var _mass: Number;
Come viene chiamato il costruttore della classe Ball, viene disegnata la grafica. Una volta estratta, la palla verrà posizionata sul palco a caso. Imposteremo anche le variabili private. Tutte le quantità dei vettori saranno anche inizializzate a 0, ad eccezione dello spostamento misurato rispetto all'origine.
funzione pubblica Ball (raggio: Number = 20, color: uint = 0x0000FF) this.draw (raggio, colore); this._mass = radius / 2; // supponendo che la massa sia metà del raggio this.x = Math2.randomiseBetween (0, 550); this.y = Math2.randomiseBetween (0, 400); this._disp = new Vector2D (this.x, this.y); // imposta lo spostamento iniziale this._velo = new Vector2D (0, 0); this._acc = new Vector2D (0, 0);
Abbiamo bisogno di calcolare la forza sottostante che fa animare le nostre particelle. Indovina, è la forza gravitazionale. La funzione seguente aiuterà a calcolare questa forza. Si noti che un attacco è applicato all'accelerazione a 5
. Le componenti orizzontali e verticali della forza sono derivate usando la trigonometria; l'animazione sopra può aiutare a capire la matematica di questo.
funzione pubblica get massa (): numero return _mass; funzione privata getForceAttract (m1: Number, m2: Number, vec2Center: Vector2D): Vector2D / * calcola la forza attrattiva in base alla seguente formula: * F = K * m1 * m2 / r * r * / var numeratore: Number = this._attractive_coeff * m1 * m2; var denominator: Number = vec2Center.getMagnitude () * vec2Center.getMagnitude (); var forceMagnitude: Number = numeratore / denominatore; var forceDirection: Number = vec2Center.getAngle (); // impostazione di un cap se (forceMagnitude> 0) forceMagnitude = Math.min (forceMagnitude, 5); // forza derivante componente, orizzontale, verticale var forceX: Number = forceMagnitude * Math.cos (forceDirection); var forceY: Number = forceMagnitude * Math.sin (forceDirection); var force: Vector2D = new Vector2D (forceX, forceY); forza di ritorno;
Una volta ottenuto il vettore di forza, possiamo calcolare l'accelerazione risultante. Ricorda, F = ma
, così a = F / m
.
funzione pubblica getAcc (vecForce: Vector2D): Vector2D // impostazione dell'accelerazione dovuta alla forza var vecAcc: Vector2D = vecForce.multiply (1 / this._mass); return veccAcc;
Con l'accelerazione calcolata, possiamo calcolare efficacemente lo spostamento risultante.
Ricorda che la forza calcolata è in realtà basata sullo spostamento tra il centro delle palle.
funzione privata getDispTo (palla: palla): Vector2D var currentVector: Vector2D = new Vector2D (ball.x, ball.y); currentVector.minusVector (this._disp); restituire currentVector; public function attredTo (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);
Quindi, siamo in grado di spostare la nostra palla nella sua nuova posizione, attraverso la funzione seguente. Si noti che lo spostamento calcolato non viene mai implementato immediatamente sulla posizione attuale della palla. Tale progettazione consente di effettuare il controllo: rilevamento di collisione tra le sfere.
funzione pubblica setPosition (vecDisp: Vector2D): void this.x = Math.round (vecDisp.vecX); this.y = Math.round (vecDisp.vecY);
Ricorda, la forza si basa sulla distanza tra i centri. Pertanto, le palline penetreranno e continueranno a muoversi a causa della forza attrattiva che è maggiore quando sono più vicine. Abbiamo bisogno di ripristinare l'accelerazione e la velocità a 0 quando le sfere si toccano l'un l'altro. Tuttavia, abbiamo bisogno di ottenere un mezzo per rilevare la collisione tra due palle.
La collisione può essere facilmente controllata. La separazione tra due palle qualsiasi non deve essere inferiore alla somma dei loro raggi. Ecco la funzione di rilevamento delle collisioni:
funzione pubblica 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;
Di solito quando una collisione è stata rilevata tra due sfere, il loro stato si sovrappone l'un l'altro. Dobbiamo assicurarci che si siedano bene sul bordo e non si sovrappongano. Come? Possiamo spostare una delle sfere lontano dall'altra, ma dobbiamo calcolare lo spostamento di destra per regolare prima. Ecco il calcolo dello spostamento:
funzione pubblica getRepel (palla: palla): Vector2D var minDist: Number = (ball.width + this.width) / 2; // calcola la distanza per respingere var toBall: Vector2D = this.getDispTo (ball); var directToBall: Vector2D = toBall.getVectorDirection (); directToBall.multiply (MinDist); directToBall.minusVector (toBall); directToBall.multiply (-1); return directToBall;
Dopo aver calcolato il dislocamento corretto, dobbiamo implementarlo. L'azione è come respingere una delle palle. Inoltre, abbiamo bisogno di fare altri due comandi extra. Ricorda, abbiamo a che fare con un ambiente dinamico. Anche dopo aver impostato lo spostamento di una palla verso il bordo, l'accelerazione dovuta alla forza e la velocità risultante lo animeranno, causando un indesiderato movimento di scatti dentro e fuori. Abbiamo bisogno di resettare questi valori di accelerazione e velocità a zero.
funzione pubblica respintaBy (ball: Ball): void this._acc.reset (); this._velo.reset (); var repelDisp: Vector2D = getRepel (palla); this._disp.addVector (repelDisp);
Infine, possiamo animare (rendere) la nostra palla come se fosse attratta da un'altra. Quando viene rilevata una collisione, lo spostamento verrà regolato in modo da non penetrare nel bordo. Questo succederà prima per le palle quando entrano in collisione con il centro, e poi per le palle quando entrano in collisione l'una con l'altra.
funzione pubblica animata (center: Ball, all: Array): void this.attractedTo (center); se (collisionInto (al centro)) this.repelledBy (al centro); per (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);
Passiamo alla nostra ultima lezione, Principale
. La classe principale viene generata all'inizio del progetto. Le variabili private includeranno la palla che attira tutti gli altri e il numero di palline nella nostra presentazione Flash.
private var mainBall: Ball; private var totalBalls: int = 10;
Prima di tutto, dovremmo inizializzare le palle. Ci sarà una palla principale che attirerà tutti gli altri. Gli altri sono nominati in modo tale che il riferimento può essere fatto facilmente in seguito.
funzione privata createBalls (): void mainBall = new Ball (50, 0x00FF00); this.addChild (mainBall); per (var i: int = 0; i < this.totalBalls; i++) var currentBall:Ball = new Ball(); currentBall.name = "ball" + i; this.addChild(currentBall);
Quindi, assegna eventi alla palla principale per renderla trascinabile quando si fa clic e si ferma quando viene rilasciato.
funzione privata init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // entry point createBalls (); mainBall.addEventListener (MouseEvent.MOUSE_DOWN, onMouseDown); stage.addEventListener (MouseEvent.MOUSE_UP, onMouseUp); animateAll (); funzione privata onMouseUp (e: MouseEvent): void stopDrag (); funzione privata onMouseDown (e: MouseEvent): void e.target.startDrag ();
Animare palle che sono attratte dal principale. Un evento EnterFrame è assegnato a ogni palla.
funzione privata animateAll (): 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);
Infine, premi Ctrl + Invio per visualizzare l'anteprima dell'animazione.
Per portare questo tutorial un ulteriore passo avanti, i lettori possono estendere questo progetto implementando altre forze lineari.
In ogni caso, le simulazioni sono un ottimo strumento per fornire idee difficili da spiegare con testo e immagini in un ambiente di classe di fisica, soprattutto quando lo stato cambia nel tempo.
Spero che questo piccolo tutorial ti aiuti in qualche modo. Terima kasih (che è "grazie" in Malesia) per aver dedicato del tempo a leggere e in attesa di sentire i commenti dei colleghi lettori.