Redarea în jur a coliziunilor elastice

În acest tutorial vom crea un joc în care obiectivul este de a împiedica alte obiecte să se ciocnească cu cursorul dumneavoastră. Nu vom folosi Flash-ul încorporat hitTestObject () metode; în schimb, vom scrie propriile rutine de detectare a coliziunilor.

Tutorial publicat

La fiecare câteva săptămâni, revizuim câteva postări preferate ale cititorului nostru de-a lungul istoriei site-ului. Acest tutorial a fost publicat pentru prima dată în februarie 2011.


Rezultatul final al rezultatelor

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


Pasul 1: Porniți

Creați un nou fișier Flash (ActionScript 3.0)

Setați dimensiunile scenei la 500x500px și FPS la 32.


Pasul 2: Clasa de minge

Această clasă va conține toate datele referitoare la o minge. O minge are a _masa, A _rază, un _xSpeed și a _ySpeed. Deci, vom face o proprietate pentru fiecare. În constructor vom trece masa, unghiul și viteza mingii. Deoarece clasa va fi legată de un obiect afișat putem extrage raza mingii noastre împărțind lățimea obiectului de afișare cu 2. _xSpeed și _ySpeed poate fi calculată prin utilizarea funcțiilor sinusoidale și cosinus simple.

 pachet import flash.display.Stage import flash.display.Sprite import flash.events.Event clasa publica Ball extinde Sprite private var _radius: Number = 0 private var _mass: Number = 0 private var _xSpeed: Number = 0 private var _ySpeed : Number = 0 funcție publică Ball (masă: număr = 10,0, unghi: număr = Math.PI, viteză: număr = 10,0): void this.mass = mass this.xSpeed ​​= * Math.sin (unghi) this.ySpeed ​​= viteza * Math.cos (unghiul)

Pentru mai multe informații despre aceste funcții trigonometrice Math.sin () și Math.cos (), consultați acest sfat rapid.


Pasul 3: Furnizarea de Getters și Setters

În clasa noastră de mingi oferim pentru noi proprietățile noastre.

 funcția publică a obține o rază (): Numărul return this._radius funcția publică setată masă (masă: Număr): void this._mass = mass funcția publică get mass (): Number return this._mass setul funcției publice xSpeed (xSpeed: Number): void this._xSpeed ​​= xSpeed funcția publică get xSpeed ​​(): Număr return this._xSpeed setul funcției publice ySpeed ​​(ySpeed: Number): void this._ySpeed ​​= ySpeed (): Număr return this._ySpeed

Pasul 4: Funcția de actualizare

Această funcție actualizează proprietățile x și y ale mingii noastre în funcție de _xSpeed și _ySpeed. Vom implementa această funcție în cadrul nostru Minge clasă.

 funcția publică (): void this.x + = _xSpeed ​​this.y + = _ySpeed

Pasul 5: Clasa finalizată

Ne vom termina Minge clasă în acest pas.

 pachet import flash.display.Stage import flash.display.Sprite import flash.events.Event clasa publica Ball extinde Sprite private var _radius: Number = 0 private var _mass: Number = 0 private var _xSpeed: Number = 0 private var _ySpeed : Number = 0 funcție publică Ball (masă: număr = 10,0, unghi: număr = Math.PI, viteză: număr = 10,0): void this.mass = mass this.xSpeed ​​= * Math.sin (unghi) this.ySpeed ​​= viteza * Math.cos (unghi) funcția publică a obține raza (): Numărul return this.radius funcția publică set masa (masa: număr): void this._mass = mass functie publica get mass (): numar return this._mass set public function set xSpeed ​​(xSpeed: Number): void this._xSpeed ​​= xSpeed functie publica get xSpeed ​​(): Number return this.xSpeed (): void this._ySpeed ​​= ySpeed funcția publică get ySpeed ​​(): Numărul return this._ySpeed funcția publică funcțională (): void this.x + = _xSpeed ​​this.y + = _ySpeed 

Pasul 6: Afișați obiecte pentru clasa noastră de mingi

În fișierele sursă am inclus un FLA de start care conține toate elementele de bibliotecă de care aveți nevoie. Le puteți desena, dacă doriți, bineînțeles. Asigurați-vă că FLA are următoarele obiecte de afișare:

(Ed note: este o tipo: "ennemyball" ar trebui să spună "enemyball".)


Pasul 7: Legarea obiectelor noastre de bibliotecă

Minge clasa pe care tocmai am creat-o trebuie să fie legată de enemyball Sprite în bibliotecă.

playerball Sprite trebuie să aibă Minge ca clasă de bază și PlayerBall ca clasă.

scor clipul de film trebuie să aibă un Scor clasă.


Pasul 8: Clasa de aplicații (clasa de documente)

cerere clasa va conține toate logica jocului. Importem toate clasele de care avem nevoie. După cum puteți vedea, vom folosi TweenMax.

Apoi definim variabilele noastre de câmp. Prima variabilă de câmp este ballPlayer.

Deoarece clasa de bază a noastră playerball Sprite este Minge putem stoca această clasă în ballPlayer variabil. Acest lucru face mai ușor mai târziu pentru a verifica pentru coliziunile dintre ballPlayer și bilele inamice.

A doua variabilă de câmp este o matrice care va conține toate bilele inamice. Cea de-a treia variabilă este timerul care va fi folosit pentru a efectua bucla principală de joc. Al patrulea și ultimul câmp este o instanță a noastră Scor care va fi folosit pentru a afișa timpul de joc scurs. În constructor îl numim init () funcție pe care o voi explica în pasul următor.

 pachet import flash.display.Sprite import flash.display.Graphics import flash.events.Event import flash.events.TimerEvent import flash.events.MouseEvent import flash.geom.Matrix import flash.utils.Timer import flash.ui.Mouse importul com.greensock.TweenMax import com.greensock.easing. * Aplicația de clasă publică extinde Sprite private var ballPlayer: Ball private var eballs: Array privat var tmr: Timer private var scor: Scorul funcției publice Aplicație (): void init )

Nu uitați să conectați clasa de documente!.


Pasul 9: Funcția init ()

Aruncați o privire la acest cod:

 funcția privată init (): void ballPlayer = nou PlayerBall () eballs = nou Array () tmr = nou Cronometru (10) scor = nou Scor () stage.align = "TL" stage.scaleMode = "noScale" Mouse.hide () scorul.x = stage.stageWidth / 2 score.y = etapa.stageHeight / 2 stage.addChild (scor) stage.addEventListener (MouseEvent.MOUSE_MOVE, updatePlayerBall) stage.addChild (ballPlayer) tmr.addEventListener (TimerEvent .TIMER, updateTime) stage.addEventListener (MouseEvent.CLICK, startGame)

În primele patru rânduri inițializăm variabilele noastre de câmp.

Apoi ne asigurăm că etapa noastră este aliniată la colțul din stânga sus și nu scară.

Ascundem cursorul mouse-ului. Cursorul nostru va fi înlocuit cu playerball Sprite. Apoi sunăm setBackground (explicată în pasul următor).

Ne concentram pe noi scor pe ecran și adăugați-o în lista de afișare. Pentru a actualiza poziția ballPlayer atașăm un eveniment MouseEvent.MOUSE_MOVE pe scenă.

updatePlayerBall (explicată la pasul 11) se va ocupa de acest MouseEvent. Apoi adăugăm ballPlayer în lista de afișare.

Cronometrul va fi folosit pentru afișarea timpului de joc. Adăugăm un ascultător TimerEvent.TIMER la ceasul nostru, care va declanșa Timpul de actualizare() (explicată la pasul 12) la fiecare 10 milisecunde.

În cele din urmă, adăugăm un MouseEvent.CLICK la etapa noastră. incepe jocul (explicată la pasul 13) va începe apoi jocul nostru.


Pasul 10: setBackground () Funcție

Această funcție adaugă un fond de gradient radial în lista de afișare. Pentru a desena un gradient pe Sprite, trebuie să definiți tipul de gradient, culorile pe care doriți să le utilizați, valorile alfa ale culorilor, rapoartele (acestea definesc distribuția culorilor) și metoda de răspândire.

Pentru mai multe informații, consultați acest Sfat rapid pe pante.

 funcția privată setBackground (): void var tip: String = "radial" var culori: Array = [0xffffff, 0xcccccc] var alphas: Array = [1, 1] var ratios: Array = [0, 255] = matricea nouă () matr.createGradientBox (stage.stageWidth, stage.stageHeight, Math.PI / 2, 0, 0) // SpreadMethod va defini modul în care este distribuit gradientul. Notă!!! Flash utilizează CONSTANTS pentru a reprezenta literalurile String var sprMethod: String = "pad" // Porniți Gradietn și treceți variabilele noastre la acesta sprite: Sprite = Sprite nou () // Salvează tastarea + crește performanța prin referință locală la un obiect Graphics var g: grafice = sprite.graphics g.beginGradientFill (tip, culori, alfa, rapoarte, matr, sprMethod) g.drawRect (0,0, stadium.stageWidth, stage.stageHeight) stage.addChild (sprite)

Pasul 11: funcția updatePlayerBall ()

Această funcție actualizează poziția ballPlayer în funcție de poziția mouse-ului.

 funcția privată updatePlayerBall (e: MouseEvent): void ballPlayer.x = mouseX ballPlayer.y = mouseY

Pasul 12: funcția updateTime ()

Calculăm timpul în câteva secunde și îl punem în caseta de text a noastră scor Sprite. Fiecare 5000ms (cinci secunde) adaugam o noua minge la joc.

 funcția privată updateTime (e: TimerEvent): void score.txtScore.text = String (((tmr.currentCount * tmr.delay) / 1000) .toFixed (2)); dacă ((tmr.currentCount * tmr.delay)% 5000 == 0) addBall (); 

Pasul 13: Funcția startGame ()

Jocul este pornit făcând clic pe scenă. Mai întâi eliminăm ascultătorul pentru clic pe scenă, astfel încât să nu putem începe timpul serverului de joc. Adăugăm trei bile la joc sunând la addBall () (explicată în etapa următoare) de trei ori. Începem timerul care ne va actualiza timpul de joc.

În final, adăugăm un eveniment ENTER_FRAME la etapa noastră. gameLoop () (explicată în pasul 15) va actualiza poziția bilelor noastre inamice.

 funcția privată startGame (e: MouseEvent): void stage.removeEventListener (MouseEvent.CLICK, startGame) addBall () addBall () addBall () tmr.start () stage.addEventListener (Event.ENTER_FRAME, gameLoop)

Pasul 14: funcția addBall ()

Mai întâi facem un nou exemplu al nostru Minge clasă. Poziționăm poziția minge la întâmplare pe scenă cu un alfa de 0 și adăugați-l în lista de afișare.

Apoi am adăugat alfa înapoi la 1. (Eu folosesc TweenMax, este inclus în fișierele sursă. De asemenea, puteți folosi motorul încorporat Flash tween.) Al doilea tween nu este într-adevăr o completare. Se așteaptă doar o secundă și onComplete funcția împinge minge în noi eballs matrice. În felul acesta gameLoop () (explicată în pasul următor) se poate ocupa de restul.

 Funcția privată addBall (): void var ball: Ball = noua minge (10, Math.random () * Math.PI * 2, 5) ball.x = Math.random () * stage.stageWidth ball.y = (minge, 0, alpha: 1) TweenMax.to (minge, 0, întârziere: 1, onComplete: funcția ( ): void eballs.push (minge)))

Pasul 15: Funcția gameLoop ()

Fiecare cadru va trece prin această funcție.

 funcția privată gameLoop (e: Event): void pentru (var i: uint = 0; i < eballs.length; i++)  for (var j:uint = i + 1; j < eballs.length; j++)  if (collision(eballs[i], eballs[j]))  doCollision(eballs[i], eballs[j])   if(collision(eballs[i], ballPlayer))  endOfGame() break  eballs[i].update() checkBounds(eballs[i])  

Începem prin iterarea prin toate bilele inamice ale noastre.

Al doilea for-loop verifică coliziunile dintre bilele inamice. Buclele încep de la "i + 1". În acest fel, nu verificăm dublu coliziunile.

Apoi verificăm dacă ballPlayer lovește mingea inamicului. Dacă da, jocul este terminat. Apoi actualizăm poziția mingii inamice.

Ne asigurăm că bilele rămân în ecranul de joc apelând funcția checkBounds () (explicat mai târziu).


Pasul 16: coliziune () Funcție

Această funcție verifică dacă o anumită pereche de bile se ciocnesc.

Mai întâi calculam distanța x și distanța y dintre cele două bile. Folosind teorema lui Pythagoras (vezi diagrama următoare), se calculează distanța absolută dintre ele. Dacă distanța este mai mică sau egală cu suma razei bilelor, avem o coliziune.

 (bile1: Ball, ball2: Ball): Boolean var xDist: Number = ball1.x - ball2.x var yDist: Number = ball1.y - ball2.y var Dist: Number = Math.sqrt (xDist * xDist + yDist * yDist) retur Dist <= ball1.radius + ball2.radius 

Pasul 17: Funcția doCollision ()

Această funcție va calcula noile viteze x și y ale bilelor în funcție de viteza și unghiul de coliziune. Atenție: matematică;)

Mai întâi se calculează distanța orizontală dintre cele două bile și apoi distanța verticală dintre bile. Cu aceste distanțe (și un pic mai mult trigonometrie) putem calcula unghiul dintre bile (vezi diagrama).

Apoi vom calcula ceea ce eu numesc mărime din fiecare minge. (Avem un vector xspeed și un vector yspeed, magnitudinea este suma vectorilor acestor.) Apoi, calculăm unghiul fiecărei bile (similar cu calculul unghiului anterior).

Apoi rotim noile x și y-viteze ale fiecărei mingi. Ceea ce facem de fapt este rotirea sistemului de coordonate. Prin rotirea axelor noastre avem o coliziune 1D. (Vezi diagrama următoare).

Newton spune că cantitatea totală de energie cinetică într-un sistem închis este constantă. Acum folosim aceste formule:

  • v1 = (u1 * (m1-m2) + 2 * m2 * u2) / (m1 + m2)
  • v2 = (u2 * (m2-m1) + 2 * m1 * u1) / (m1 + m2)

Unde:
v1 = final xSpeedBall 1
v2 = final xSpeedBall 2
m1 = bilă de masă 1
m2 = bilă de masă 2
u1 = bila inițială de viteză 1
u2 = bila inițială de viteză 2

Vitezele y nu se modifică, deoarece este o coliziune 1D.

Cu aceste formule putem calcula xSpeed și ySpeed din fiecare minge.

Acum, când avem noile viteze x și y în sistemul nostru de coordonate rotiți. Ultimul pas este de a transforma totul înapoi într-un sistem normal de coordonate. Folosim Math.PI / 2 deoarece unghiul dintre xSpeed și ySpeed trebuie să fie întotdeauna de 90 de grade (pi / 2 radiani).

 funcția privată doCollision (minge1: Ball, ball2: Ball): void var xDist: Număr = ball1.x - ball2.x var yDist: Number = ball1.y - ball2.y var collisionAngle: Number = Math.atan2 (yDist, xDist) var magBall1: Număr = Math.sqrt (minge1.xSpeed ​​* ball1.xSpeed ​​+ ball1.ySpeed ​​* ball1.ySpeed) var magBall2: Number = Math.sqrt (minge2.xSpeed ​​* ball2.xSpeed ​​+ ball2.ySpeed ​​* ball2. ySpeed) var unghiBal1: Număr = Math.atan2 (ball1.ySpeed, ball1.xSpeed) var angleBall2: Număr = Math.atan2 (ball2.ySpeed, ball2.xSpeed) var xSpeedBall1: Number = magBall1 * Math.cos (angleBall1- collisionAngle ) var ySpeedBall1: Număr = magBall1 * Math.sin (unghiBall1-collisionAngle) var xSpeedBall2: Number = magBall2 * Math.cos (angleBall2-collisionAngle) var ySpeedBall2: Number = magBall2 * Math.sin (finalBall2-collisionAngle) var finalxSpeedBall1: = (mingea1.mass-ball2.mass) * xSpeedBall1 + (minge2.mass + minge2.mass) * xSpeedBall2) / (minge1.mass + minge2.mass) var finalxSpeedBall2: Number = ((minge1.mass + ball1.mass) * xSpeedBall1 + (ball2.mass-ball1.mass) * xSpeedBall 2) / (minge1.mass + minge2.mass) var finalySpeedBall1: Numărul = ySpeedBall1 var finalySpeedBall2: Numărul = ySpeedBall2 ball1.xSpeed ​​= Math.cos (collisionAngle) * finalxSpeedBall1 + Math.cos (collisionAngle + Math.PI / 2) * finalySpeedBall1 ball1.ySpeed ​​= Math.sin (collisionAngle) * finalxSpeedBall1 + Math.sin (collisionAngle + Math.PI / 2) * finalySpeedBall1 ball2.xSpeed ​​= Math.cos (collisionAngle) * finalxSpeedBall2 + Math.cos (collisionAngle + Math.PI / 2) * finalySpeedBall2 ball2.ySpeed ​​= Math.sin (collisionAngle) * finalxSpeedBall2 + Math.sin (collisionAngle + Math.PI / 2) * finalySpeedBall2

Pentru a afla mai multe despre coliziunile elastice, aruncă o privire la hoomanr.com.


Pasul 18: Funcția endOfGame ()

Aceasta se execută atunci când jocul se termină.

 funcția privată endOfGame (): void tmr.stop () Mouse.show () stage.removeEventListener (MouseEvent.MOUSE_MOVE, updatePlayerBall) stage.removeEventListener (Event.ENTER_FRAME, gameLoop) în timp ce (eballs.length> 0) TweenMax.to (eBalls 0, 0.5, scaleX: 0, scaleY: 0, ease: Bounce.easeOut) eballs.splice (0,1) TweenMax.to (ballPlayer, 0.5, scaleX: 0, scaleY: ușurință: Bounce.easeOut)

În primul rând, oprim timerul. Arată mouse-ul din nou. Apoi eliminăm atât ascultătorii de evenimente MOUSE_MOVE, cât și ENTER_FRAME. În cele din urmă, facem toate bilele pe scena invizibile.


Pasul 19: Funcția checkBounds ()

Această funcție asigură faptul că bilele stau în interiorul ecranului de joc. Deci, dacă mingea atinge partea superioară sau inferioară, vom inversa ySpeed. dacă mingea lovește partea stângă sau cea dreaptă a ecranului, inversăm xSpeed. Utilizează o logică similară cu funcția de detectare a coliziunii cu bile pentru a verifica dacă marginile mingii ating o margine a ecranului.

 (ball.x + ball.radius)> stage.stageWidth) ball.x = stage.stageWidth - ball.radius ball.xSpeed ​​* = -1 dacă (( ball.x - ball.radius) < 0)  ball.x = 0 + ball.radius ball.xSpeed *= -1  if((ball.y + ball.radius) > stage.stageHeight) ball.y = stage.stageHeight - ball.radius ball.ySpeed ​​* = - 1 în cazul în care ((ball.y - ball.radius) < 0)  ball.y = 0 + ball.radius ball.ySpeed *= - 1  

Pasul 20: Clasa de aplicare completă

Am terminat clasa noastră de aplicații. Acum avem un joc de lucru!!!

 pachet import flash.display.Sprite; import flash.display.Graphics; importul flash.events.Event; import flash.events.TimerEvent; importul flash.events.MouseEvent; import flash.geom.Matrix; import flash.utils.Timer; import flash.ui.Mouse; import com.greensock.TweenMax; import com.greensock.easing. *; cererea de clasă publică extinde Sprite private var ballPlayer: Ball; private var eballs: Array; privat var tmr: Timer; scor privat var: Scor; funcția publică funcția (): void init ();  funcția privată init (): void ballPlayer = new PlayerBall (); eballs = Array nou (); tmr = timer nou (10); scor = scor nou (); stage.align = "TL"; stage.scaleMode = "nuScale"; Mouse.hide (); setBackground (); scorul.x = stadiul.stajului lățime / 2; scorul.y = stage.stageHeight / 2; stage.addChild (scor); starea.addEventListener (MouseEvent.MOUSE_MOVE, updatePlayerBall); stage.addChild (ballPlayer); tmr.addEventListener (TimerEvent.TIMER, updateTime); stage.addEventListener (MouseEvent.CLICK, startGame);  funcția privată setBackground (): void var type: String = "radial"; var culori: Array = [0xffffff, 0xcccccc]; var alphas: Array = [1,1]; rapoarte var: Array = [0,255]; var matr: Matrice = Matrice nouă (); matr.createGradientBox (stadiu.staj Lățime, stadiu.stageHeight, Math.PI / 2, 0, 0); // SpreadMethod va defini modul în care este distribuit gradientul. Notă!!! Flash utilizează CONSTANTS pentru a reprezenta literalurile String var sprMethod: String = "pad"; // Începeți Gradietn și treceți variabilele la el sprite sprite: Sprite = Sprite nou (); // Salvează tastarea + crește performanța prin referință locală la un obiect Graphics var g: Graphics = sprite.graphics; g.beginGradientFill (tip, culori, alfa, rapoarte, matr, sprMethod); g.drawRect (0,0, stage.stageWidth, stage.stageHeight); stage.addChild (sprite);  funcția privată updatePlayerBall (e: MouseEvent): void ballPlayer.x = mouseX; ballPlayer.y = mouseY;  funcția privată updateTime (e: TimerEvent): void score.txtScore.text = String (((tmr.currentCount * tmr.delay) / 1000) .toFixed (2)); dacă ((tmr.currentCount * tmr.delay)% 5000 == 0) addBall ();  funcția privată startGame (e: MouseEvent): void stage.removeEventListener (MouseEvent.CLICK, startGame); addBall (); addBall (); addBall (); tmr.start (); stage.addEventListener (Event.ENTER_FRAME, gameLoop);  funcția privată addBall (): void var ball: Ball = minge nouă (10, Math.random () * Math.PI * 2,5); ball.x = Math.random () * stage.stageWidth; minge.y = Math.random () * stage.stageHeight; ball.alpha = 0; stage.addChild (minge); TweenMax.to (minge, 0,5, alpha: 1); TweenMax.to (minge, 0, întârziere: 1, peComplete: function (): void eballs.push (ball));  funcția privată gameLoop (e: Event): void pentru (var i: uint = 0; i < eballs.length; i++)  for (var j:uint = i + 1; j < eballs.length; j++)  if (collision(eballs[i],eballs[j]))  doCollision(eballs[i], eballs[j]);   if (collision(eballs[i],ballPlayer))  endOfGame(); break;  eballs[i].update(); checkBounds(eballs[i]);   private function collision(ball1:Ball, ball2:Ball):Boolean  var xDist:Number = ball1.x - ball2.x; var yDist:Number = ball1.y - ball2.y; var Dist:Number = Math.sqrt(xDist * xDist + yDist * yDist); if (Dist <= ball1.radius + ball2.radius)  if (ball1.x < ball2.x)  ball1.x -= 2; ball2.x += 2;  else  ball1.x += 2; ball2.x -= 2;  if (ball1.y < ball2.y)  ball1.y -= 2; ball2.y += 2;  else  ball1.y += 2; ball2.y -= 2;   return Dist <= ball1.radius + ball2.radius;  private function doCollision(ball1:Ball, ball2:Ball):void  var xDist:Number = ball1.x - ball2.x; var yDist:Number = ball1.y - ball2.y; var collisionAngle:Number = Math.atan2(yDist,xDist); var magBall1:Number = Math.sqrt(ball1.xSpeed * ball1.xSpeed + ball1.ySpeed * ball1.ySpeed); var magBall2:Number = Math.sqrt(ball2.xSpeed * ball2.xSpeed + ball2.ySpeed * ball2.ySpeed); var angleBall1:Number = Math.atan2(ball1.ySpeed,ball1.xSpeed); var angleBall2:Number = Math.atan2(ball2.ySpeed,ball2.xSpeed); var xSpeedBall1:Number = magBall1 * Math.cos(angleBall1 - collisionAngle); var ySpeedBall1:Number = magBall1 * Math.sin(angleBall1 - collisionAngle); var xSpeedBall2:Number = magBall2 * Math.cos(angleBall2 - collisionAngle); var ySpeedBall2:Number = magBall2 * Math.sin(angleBall2 - collisionAngle); var finalxSpeedBall1:Number = ((ball1.mass-ball2.mass)*xSpeedBall1+(ball2.mass+ball2.mass)*xSpeedBall2)/(ball1.mass+ball2.mass); var finalxSpeedBall2:Number = ((ball1.mass+ball1.mass)*xSpeedBall1+(ball2.mass-ball1.mass)*xSpeedBall2)/(ball1.mass+ball2.mass); var finalySpeedBall1:Number = ySpeedBall1; var finalySpeedBall2:Number = ySpeedBall2; ball1.xSpeed = Math.cos(collisionAngle) * finalxSpeedBall1 + Math.cos(collisionAngle + Math.PI / 2) * finalySpeedBall1; ball1.ySpeed = Math.sin(collisionAngle) * finalxSpeedBall1 + Math.sin(collisionAngle + Math.PI / 2) * finalySpeedBall1; ball2.xSpeed = Math.cos(collisionAngle) * finalxSpeedBall2 + Math.cos(collisionAngle + Math.PI / 2) * finalySpeedBall2; ball2.ySpeed = Math.sin(collisionAngle) * finalxSpeedBall2 + Math.sin(collisionAngle + Math.PI / 2) * finalySpeedBall2;  private function endOfGame():void  tmr.stop(); Mouse.show(); stage.removeEventListener(MouseEvent.MOUSE_MOVE, updatePlayerBall); stage.removeEventListener(Event.ENTER_FRAME, gameLoop); while (eballs.length > 0) TweenMax.to (eballs [0], 0,5, scaleX: 0, scaleY: 0, usurinta: Bounce.easeOut); eballs.splice (0,1);  TweenMax.to (mingePlayer, 0,5, scaleX: 0, scaleY: 0, usurinta: Bounce.easeOut);  funcția privată checkBounds (ball: Ball): void if ((ball.x + ball.radius)> stage.stageWidth) ball.x = stage.stageWidth - ball.radius; ball.xSpeed ​​* = -1;  dacă ((ball.x - ball.radius) < 0)  ball.x = 0 + ball.radius; ball.xSpeed *= -1;  if ((ball.y + ball.radius) > stage.stageHeight) ball.y = stage.stageHeight - ball.radius; b.speed * = -1;  dacă ((ball.y - ball.radius) < 0)  ball.y = 0 + ball.radius; ball.ySpeed *= -1;    

Concluzie

Asta e pentru acest tutorial. Desigur, ai putea adăuga posibilitatea de a reporni jocul, dar asta nu ar trebui să fie prea greu. Acest exemplu de bază al coliziunilor elastice poate fi folosit pentru jocuri mai mari, cum ar fi un joc de biliard sau ceva asemănător.

Sper că ți-a plăcut acest tutorial, mulțumesc pentru lectură!

Cod