Stardust Particle Engine oferă două abordări majore pentru a manipula liber mișcarea particulelor, și anume câmpurile gravitaționale și deflectorii. Câmpurile gravitaționale sunt câmpuri vectoriale care afectează accelerația particulelor, iar deflectorii manipulează atât poziția și viteza particulelor.
Prima parte a acestui tutorial acoperă principiile de mișcare a particulelor și câmpurile gravitaționale. De asemenea, aceasta demonstrează cum să creați propriile câmpuri gravitaționale personalizate. Partea a doua se concentrează asupra deflectorilor și asupra modului de a crea deflectori personalizați.
Cunoașterea prealabilă a utilizării de bază a Stardust este necesară pentru a continua să citiți acest tutorial. Dacă nu sunteți familiarizați cu Stardust, puteți să vedeți tutorialul meu anterior despre acest subiect, Împușcați stelele cu Stardust Particle Engine, înainte de a merge.
Să aruncăm o privire asupra rezultatului final la care vom lucra. Acesta este un exemplu de câmp gravitațional personalizat.
Este timpul pentru câteva flashback-uri rapide despre fizica liceului. Amintiți-vă de cinematica de bază? Este vorba despre deplasare, care este doar o modalitate mai bogată de a spune "poziția" și relația ei cu timpul. Pentru scopul acestui tutorial, avem nevoie doar de o înțelegere destul de simplă a subiectului.
Deplasare înseamnă poziția curentă a unui obiect. În acest tutorial, "obiectele" cu care ne ocupăm în primul rând sunt particulele în spațiul 2D. În spațiul 2D, deplasarea unui obiect este reprezentată de un vector 2D.
Viteza unui obiect denotă cât de repede se schimbă poziția obiectului și direcția schimbării. Viteza unui obiect în spațiul 2D este de asemenea reprezentată de un vector 2D. Componentele vectorului x și y reprezintă direcția schimbării poziției, iar valoarea absolută a vectorului denotă viteza obiectului, adică cât de repede se mișcă obiectul.
Accelerația este de viteză ca viteza de deplasare. Accelerația unui obiect denotă cât de repede se schimbă viteza obiectului și direcția schimbării. La fel ca viteza unui obiect în spațiul 2D, accelerarea unui obiect este reprezentată de un vector 2D.
Un alt lucru care merită menționat este conceptul de câmpuri vectoriale. Puteți vizualiza practic un câmp vectorial ca o funcție care ia un vector ca intrare și scoate un alt vector. Câmpurile gravitaționale sunt un fel de câmpuri vectoriale care iau vectori de poziție ca vectori de intrare și ieșire de accelerare. De exemplu, în simularea fizică, de obicei, o gravitate uniformă îndreptată în jos se aplică tuturor obiectelor; în acest caz, câmpul gravitațional reprezentând gravitația este un câmp vector care emite un vector constant (îndreptat în jos), indiferent de vectorii de poziție de intrare.
Acesta este un grafic vizualizat al unui câmp vectorial. Vectorul de ieșire al unui vector de intrare dat (1, 2) este (0,5, 0,5), în timp ce ieșirea unei intrări (4, 3) este (-0,5, 0,5).
Camp
clasa în Stardust reprezintă un câmp vectorial 2D, și omologul său 3D, Field3D
clasa reprezintă un câmp vectorial 3D. În acest tutorial, ne vom concentra doar pe câmpurile vectoriale 2D.
Field.getMotionData ()
metoda ia o Particle2D
obiect, care conține parametrul 2D al unei particule și informații despre viteză. Această metodă returnează a MotionData2D
obiect, un obiect de valoare 2D vector care constă din componente x și y. Combinat cu Gravitatie
acțiune, a Camp
obiect poate fi folosit ca un câmp gravitațional, a cărui ieșire este utilizată pentru a manipula viteza particulelor.
Asta-i totul pentru recapitulări ale liceului nostru. Acum este momentul pentru unele lucruri reale Stardust.
După cum sa menționat anterior, Gravitatie
clasa de acțiune face uz de Camp
obiecte ca câmpuri gravitaționale pentru a manipula viteza particulelor. Iată cum creați un câmp vectorial uniform, un câmp vector care returnează un vector constant, indiferent de ce este dat, și îl înfășurați într-un câmp vectorial Gravitatie
acțiune.
// crea un câmp vectorial uniform îndreptat în jos (amintiți poziția pozitivă a coordonatei y înseamnă "jos" în Flash) câmpul var: câmp = nou UniformField (0, 1); // creaza o actiune gravitationala var gravitate: gravitatea = noua gravitate (); // adăugați câmpul la acțiunea gravitatională gravity.addField (câmpul);
Acest Gravitatie
acțiunea este acum gata să fie utilizată în același mod ca orice alte acțiuni obișnuite Stardust.
// adăugați acțiunea gravitațională la un emițător de emițător. adație (gravitație);
Vom crea un efect de ploaie vânt folosind Gravitatie
acțiune.
Creați un nou document Flash, alegeți o culoare întunecată pentru fundal, trageți o picătură de ploaie pe scenă și convertiți pictura de ploaie într-un simbol de clip video, exportat pentru ActionScript cu numele de clasă "Raindrop". Ștergeți instanța de ploaie pe scenă după aceea.
Acum vom crea un fișier AS pentru clasa de documente și un fișier AS pentru emițătorul de ploaie. Nu voi explica codul aici, deoarece am acoperit deja utilizarea de bază a Stardust în tutorialul meu anterior. Dacă nu sunteți familiarizat cu Stardust sau aveți nevoie de o băutură răcoritoare, vă recomandăm să citiți tutorialul meu anterior înainte de a vă deplasa.
Aceasta este clasa de documente.
pachet import flash.display. *; import flash.events. *; import idv.cjcat.stardust.common.emitters. *; import idv.cjcat.stardust.common.renderers. *; import idv.cjcat.stardust.twoD.renderers. *; clasa publică WindyRain extinde Sprite private var emitter: Emitter; privat var renderer: Renderer; funcția publică WindyRain () emitter = new RainEmitter (); renderer = nou DisplayObjectRenderer (acest lucru); renderer.addEmitter (emițător); addEventListener (Event.ENTER_FRAME, mainLoop); funcția privată mainLoop (e: Event): void emitter.step ();
Și aceasta este clasa emițătorului folosită în clasa de documente.
pachet import idv.cjcat.stardust.common.clocks. *; import idv.cjcat.stardust.common.initializers. *; import idv.cjcat.stardust.common.math. *; import idv.cjcat.stardust.twoD.actions. *; import idv.cjcat.stardust.twoD.emitters. *; import idv.cjcat.stardust.twoD.initializers. *; import idv.cjcat.stardust.twoD.zones. *; clasa publică RainEmitter extinde Emitter2D funcția publică RainEmitter () super (noul SteadyClock (1)); // inițializatorii addInitializer (noul DisplayObjectClass (Raindrop)); addInitializer (poziție nouă (noul RectZone (-300, -40, 940, 20)); addInitializer (noua Velocitate (noua RectZone (-0.5, 2, 1, 3))); addInitializer (noua masă (noul UniformRandom (2, 1))); addInitializer (noua Scară (noul UniformRandom (1, 0.2))); // acțiuni addAction (new Move ()); addAction (nou orientat (1, 180)); addAction (noul DeathZone (noul RectZone (-300, -40, 960, 480), adevărat));
Acesta este modul în care arată progresul nostru actual.
Acum vom face efectul de ploaie vântând prin adăugarea unui câmp gravitațional uniform care "va trage" picăturile de ploaie la dreapta. Adăugați următorul cod în constructorul RainEmitter
clasă.
// crea un câmp uniform care întoarce întotdeauna (0.5, 0) var câmp: Field = new UniformField (0.5, 0); // luați în considerare masa de particule field.massless = false; // creati o actiune gravitationala si adaugati campul la aceasta var gravitate: gravitatea = noua gravitate (); gravity.addField (câmp); // adăugați acțiunea gravitațională la adaosul de emițător (gravitatea);
Rețineți că am setat Field.massless
proprietate la fals, ceea ce este adevărat în mod implicit. Când este setat la true, această proprietate determină câmpurile să acționeze ca câmpurile gravitaționale obișnuite, afectând toate obiectele în mod egal, indiferent de masa lor. Cu toate acestea, atunci când proprietatea este setată la falsă, se ia în considerare masa particulelor: particulele cu masa mai mare sunt mai puțin afectate de câmp, iar particulele cu masa mai mică sunt afectate mai mult. De aceea am folosit Masa
inițializator în codul nostru emițător anterior, pentru a adăuga o anumită aleatorie în efectul de ploaie.
Testați din nou filmul și acesta este rezultatul nostru. Picăturile de ploaie sunt acum afectate de un câmp gravitațional și sunt "trase" toate spre dreapta.
Acum o vom schimba UniformField
obiect cu a BitmapField
obiect, returnarea câmpurilor vectoriale pe baza canalelor de culori ale unui bitmap, pentru a crea un efect de turbulență. Dacă ați lucrat cu ActionScript pentru o perioadă de timp, s-ar putea să vă așteptați să utilizați BitmapData.perlinNoise ()
atunci când gândim la turbulențe și asta este exact ceea ce vom face.
Iată ce arată un exemplu de bitmap de zgomot Perlin. Zgomotul Perlin este un algoritm excelent de generare a zgomotului pentru simularea turbulențelor, a undelor de apă, a norilor etc. Puteți găsi mai multe informații despre zgomotul Perlin aici.
S-ar putea să te întrebi dacă o să folosim BitmapData.perlinNoise ()
pentru a genera un bitmap de zgomot pe perlină, cum vom folosi acest bitmap ca câmp vectorial? Ei bine, asta e ceea ce BitmapField
clasa este pentru. Este nevoie de un bitmap și îl convertește într-un câmp vectorial.
Să presupunem că avem un câmp bitmap al cărui Canal X este setat sa roșu și Canal Y este verde. Aceasta înseamnă că atunci când câmpul are un vector de intrare, să zicem, (2, 3), acesta privește până la pixelul bitmapului la (2, 3) și componenta X a vectorului de ieșire este determinată de canalul roșu al pixelului, iar componenta Y este determinată de canalul verde. Când componentele unui vector de intrare nu sunt întregi, ele sunt rotunjite mai întâi.
Valoarea canalului de culoare variază de la 0 la 255, 127 fiind media. O valoare mai mică de 127 este considerată negativă de câmpul bitmap, în timp ce o valoare mai mare de 127 este considerată pozitivă. Zero este cel mai negativ numărul și 255 este cel mai pozitiv unu. De exemplu, dacă avem un pixel cu o culoare 0xFF0000 în reprezentare hexazecimală, adică un canal roșu cu valoarea 255 și un canal verde cu 0, atunci ieșirea câmpului bitmap pentru acest pixel ar fi un vector cu componenta X dintr-un cel mai pozitiv numărul posibil și componenta Y a cel mai negativ număr posibil, în cazul în care acest lucru numărul cel mai pozitiv / negativ posibil, sau numărul maxim, este specific câmpului bitmap. Pentru a fi mai precis, iată formula conversiei pixel-vector.
Creați un nou document Flash. Desenați o săgeată pe scenă, convertiți-o într-un simbol numit "Arrow" și exportați-o pentru ActionScript.
Creați un fișier AS pentru clasa de documente. Acest lucru este aproape identic cu cel din exemplul precedent.
pachet import flash.display. *; import flash.events. *; import idv.cjcat.stardust.common.emitters. *; import idv.cjcat.stardust.common.renderers. *; import idv.cjcat.stardust.twoD.renderers. *; clasa publica Turbulence extinde Sprite private var emitter: Emitter; privat var renderer: Renderer; funcție publică Turbulență () emitter = new ArrowEmitter (); renderer = nou DisplayObjectRenderer (acest lucru); renderer.addEmitter (emițător); addEventListener (Event.ENTER_FRAME, mainLoop); funcția privată mainLoop (e: Event): void emitter.step ();
Creați un alt fișier AS pentru clasa emițătorului nostru.
pachet import idv.cjcat.stardust.common.actions. *; importă idv.cjcat.stardust.common.clocks. *; import idv.cjcat.stardust.common.initializers. *; import idv.cjcat.stardust.common.math. *; import idv.cjcat.stardust.twoD.actions. *; import idv.cjcat.stardust.twoD.emitters. *; import idv.cjcat.stardust.twoD.initializers. *; import idv.cjcat.stardust.twoD.zones. *; clasa publică ArrowEmitter extinde Emitter2D funcția publică ArrowEmitter () super (noul SteadyClock (1)); // inițializatorii addInitializer (noul DisplayObjectClass (Arrow)); addInitializer (viata noua (noua UniformRandom (50, 10))); addInitializer (poziție nouă (noul SinglePoint (320, 200))); addInitializer (noua Velocity (noua LazySectorZone (3, 2))); addInitializer (noua masă (noul UniformRandom (2, 1))); addInitializer (noua Scară (noul UniformRandom (1, 0.2))); // actions addAction (new Age ()); addAction (noul DeathLife ()); addAction (new Move ()); addAction (nou orientat ()); addAction (noul ScaleCurve (10, 10));
Progresul actual arată astfel.
Adăugați următorul cod care creează date bitmap de zgomot permise de 640 pe 480 în constructorul emițătorului. Pentru explicații detaliate despre fiecare parametru al parametrului BitmapData.perlinNoise ()
, vă puteți referi la această documentație. Pentru a simplifica, codul următor creează un bitmap de zgomot Perlin cu "octave" de aproximativ 50X50, iar zgomotul constă în canale de culoare roșii și verzi.
// a crea un bitmap de zgomot Perlin zgomot var: BitmapData = noi BitmapData (640, 400); noise.perlinNoise (50, 50, 1, 0, adevărat, adevărat, 1 | 2);
Apoi, creați un BitmapField
obiecte și să le atribuiți datele bitmap prin intermediul acestora Actualizați()
metodă. Apoi, restul codului cu privire la Gravitatie
acțiunea este exact aceeași ca în exemplul anterior.
// crea un câmp uniform care întoarce întotdeauna (0.5, 0) câmpul var: BitmapField = nou BitmapField (); field.channelX = 1; // setați canalul X pe câmpul roșu field.channelY = 2; // setați canalul Y la câmpul verde.max = 1; // setați valoarea maximă a domeniului vectorial absolute field.update (zgomot); // actualizați câmpul cu bitmap de zgomot // luați masa particulelor în considerare field.massless = false; // creati o actiune gravitationala si adaugati campul la aceasta var gravitate: gravitatea = noua gravitate (); gravity.addField (câmp); // adăugați acțiunea gravitațională la adaosul de emițător (gravitatea);
Acum încercați din nou filmul și veți vedea că săgețile noastre de zbor se confruntă acum cu turbulențe.
Am folosit-o UniformField
și BitmapField
furnizate de Stardust, iar acum vom crea propriile câmpuri personalizate prin extinderea Camp
clasa și suprascrierea getMotionData2D ()
metodă.
getMotionData2D
ia a Particle2D
parametru ca intrare, care conține informația despre vectorul de poziție a particulei și aceasta este intrarea în câmp. Metoda returnează a MotionData2D
obiect, reprezentând ieșirea câmpului. Asta e tot ce trebuie să știți pentru a crea un câmp particularizat. Să creăm un câmp de vortex personalizat.
Mai jos este graficul vizualizat al câmpului nostru vortex. E destul de explicativă de ce se numește câmp vortex.
Iată formula pentru câmpul vortex.
Și clasa câmpului vortex este la fel de simplă ca și codul de mai jos. Am folosit Vec2D
clasa de a face toate lucrurile murdare de rotire a unui vector de 90 de grade în sensul acelor de ceasornic și de stabilire a vectorului valoarea absolută. Apoi, dăm componentele vectorului x și y într-un a MotionData2D
obiect, care este de tip obiect care trebuie returnat.
pachet import idv.cjcat.stardust.twoD.fields. *; import idv.cjcat.stardust.twoD.geom. *; import idv.cjcat.stardust.twoD.particles. *; clasa publică VortexField extinde câmpul public var centerX: Number; public var centerY: Număr; public var strength: Number; funcție publică VortexField (centerX: număr = 0, centerY: număr = 0, putere: număr = 1) this.centerX = centerX; acest centru = centruY; această intensitate = putere; suprascrie funcția protejată calculateMotionData2D (particulă: Particle2D): MotionData2D var dx: Number = particle.x - centerX; var dy: Numărul = particle.y - centerY; var vec: Vec2D = nou Vec2D (dx, dy); vec.length = putere; vec.rotateThis (90); returnează MotionData2D (vec.x, vec.y);
Acum că avem domeniul nostru personalizat, să-l testăm în exemplul următor.
Acest exemplu servește drept unitate de test pentru câmpul vectorului vortex. Este la fel de simplu ca schimbarea unui câmp cu unul nou. Modificați următorul cod din exemplul anterior din acest
// crea un câmp uniform care întoarce întotdeauna (0.5, 0) câmpul var: BitmapField = nou BitmapField (); field.channelX = 1; // setați canalul X pe câmpul roșu field.channelY = 2; // setați canalul Y la câmpul verde.max = 1; / / setați câmpul de lungime maximă vecotr field.update (zgomot); // actualizați câmpul cu bitmap de zgomot
la acest
// crea un câmp vortex centrat la (320, 200) cu câmpul de putere 1 var: VortexField = new VortexField (); field.centerX = 320; field.centerY = 200; field.strength = 1;
Și am terminat. Puteți testa filmul și puteți vedea efectul de vortex. Dulce!
Ați văzut cum să utilizați Gravitatie
acțiune și Camp
clasa de a afecta viteza particulelor. Și ați învățat cum să creați propriile câmpuri vectoriale personalizate pentru a fi utilizate ca câmpuri gravitaționale. Următoarea parte a acestui tutorial vă va arăta cum să utilizați deflectorii pentru a manipula simultan poziția și viteza particulelor.
Vă mulțumesc foarte mult pentru lectură!