Jouer avec des collisions élastiques

Dans ce didacticiel, nous allons créer un jeu dont l'objectif est d'empêcher la collision d'autres objets avec votre curseur. Nous n'utiliserons pas la fonction intégrée de Flash hitTestObject () les méthodes; à la place, nous écrirons nos propres routines de détection de collision.

Tutoriel republié

Toutes les quelques semaines, nous revoyons certains des articles préférés de nos lecteurs tout au long de l'histoire du site. Ce tutoriel a été publié pour la première fois en février 2011.


Aperçu du résultat final

Jetons un coup d'œil au résultat final sur lequel nous allons travailler:


Étape 1: Commencez

Créer un nouveau fichier Flash (ActionScript 3.0)

Définissez les dimensions de la scène sur 500x500px et FPS sur 32.


Étape 2: La classe de balle

Cette classe contiendra toutes les données relatives à une balle. Une balle a _Masse, une _rayon, un _xSpeed et un _ySpeed. Nous allons donc faire une propriété pour chacun. Dans le constructeur, nous passons la masse, l'angle et la vitesse de la balle. Comme la classe sera liée à un objet d’affichage, nous pouvons récupérer le rayon de notre balle en divisant la largeur de l’objet d’affichage par 2. Le _xSpeed et _ySpeed peut être calculé en utilisant des fonctions simples sinus et cosinus.

 package import flash.display.Stage import flash.display.Sprite import flash.events.Event classe publique Ball boule Sprite private var _radius: Number = 0 private var _mass: Number = 0 private var _xSpeed: Number = 0 private var _ySpeed : Number = 0 fonction publique Ball (masse: Number = 10.0, angle: Number = Math.PI, vitesse: Number = 10.0): void this.mass = masse this._radius = this.width / 2 this.xSpeed ​​= speed * Math.sin (angle) this.ySpeed ​​= speed * Math.cos (angle)

Pour plus d'informations sur ces fonctions trigonométriques Math.sin () et Math.cos (), voir cette astuce..


Étape 3: Fournir des Getters et des Setters

Dans notre classe Ball, nous fournissons des getters et des setters pour nos propriétés..

 fonction publique get radius (): Number return this._radius ensemble de fonctions publiques mass (masse: Number): void this._mass = masse fonction publique get mass (): Number nombre de this._mass ensemble de fonctions publiques xSpeed (xSpeed: Number): void this._xSpeed ​​= xSpeed fonction publique get xSpeed ​​(): Number retour this._xSpeed ensemble de fonctions publiques ySpeed ​​(ySpeed: Number): void ceci._ySpeed ​​= ySpeed fonction publique get ySpeed (): Number return this._ySpeed

Étape 4: Fonction de mise à jour

Cette fonction met à jour les propriétés x et y de notre balle en fonction de la _xSpeed et _ySpeed. Nous allons implémenter cette fonction dans notre Ballon classe.

 fonction publique update (): void this.x + = _xSpeed ​​this.y + = _ySpeed

Étape 5: Le cours terminé

Nous finirons notre Ballon classe dans cette étape.

 package import flash.display.Stage import flash.display.Sprite import flash.events.Event classe publique Ball boule Sprite private var _radius: Number = 0 private var _mass: Number = 0 private var _xSpeed: Number = 0 private var _ySpeed : Number = 0 fonction publique Ball (masse: Number = 10.0, angle: Number = Math.PI, vitesse: Number = 10.0): void this.mass = masse this._radius = this.width / 2 this.xSpeed ​​= speed * Math.sin (angle) this.ySpeed ​​= speed * Math.cos (angle) fonction publique get radius (): Number return this._radius ensemble de fonctions public mass (masse: Number): void this._mass = masse fonction publique get masse (): Number return this._mass fonction publique set xSpeed ​​(xSpeed: Number): void this._xSpeed ​​= xSpeed fonction publique get xSpeed ​​(): Number retour this._xSpeed fonction publique définir ySpeed ​​(ySpeed: Number): void this._ySpeed ​​= ySpeed fonction publique get ySpeed ​​(): Number retourner this._ySpeed fonction publique update (): void this.x + = _xSpeed ​​this.y + = _ySpeed 

Étape 6: Afficher les objets pour notre classe de balle

Dans les fichiers source, j'ai inclus un fichier FLA de démarrage contenant tous les éléments de bibliothèque dont vous avez besoin. Vous pouvez les dessiner vous-même si vous voulez, bien sûr. Assurez-vous que votre FLA a les objets d'affichage suivants:

(Note: c'est une faute de frappe: "ennemyball" devrait dire "ennemisball".)


Étape 7: Lier nos objets de bibliothèque

le Ballon la classe que nous venons de créer doit être liée à la balle ennemie Sprite dans la bibliothèque.

le joueur Sprite doit avoir Ballon comme classe de base et PlayerBall comme classe.

le But clip doit avoir un But classe.


Étape 8: La classe d'application (classe de document)

le Application La classe contiendra toute la logique du jeu. Nous importons toutes les classes dont nous avons besoin. Comme vous pouvez le constater, nous utiliserons TweenMax.

Ensuite, nous définissons nos variables de champ. La première variable de champ est la ballPlayer.

Parce que la classe de base de notre joueur Sprite est Ballon nous pouvons stocker cette classe dans le ballPlayer variable. Cela facilite par la suite la vérification des collisions entre les ballPlayer et les balles ennemies.

La deuxième variable de champ est un tableau qui contiendra toutes nos balles ennemies. La troisième variable est la minuterie qui sera utilisée pour exécuter la boucle de jeu principale. Le quatrième et dernier champ est une instance de notre But objet de bibliothèque qui sera utilisé pour afficher le temps de jeu écoulé. Dans le constructeur, nous appelons le init () fonction que je vais expliquer dans la prochaine étape.

 package 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 import com.greensock.TweenMax import com.greensock.easing. * public class Application extension Sprite bal var var privé Joueur: Balle var privée: Array var var tmr: Minuteur var var: Score public function Application (): void init ( )

N'oubliez pas de lier la classe de document!.


Étape 9: La fonction init ()

Jetez un oeil à ce code:

 fonction privée init (): void ballPlayer = new PlayerBall () eballs = new Array () tmr = new Timer (10) score = new Score () stage.align = "TL" stage.scaleMode = "noScale" Mouse.hide () setBackground () score.x = stage.stageWidth / 2 score.y = stage.stageHeight / 2 stage.addChild (score) stage.addEventListener (MouseEvent.MOUSE_MOVE, updatePlayerBall) stage.addChild (ballPlayer) tmr.addEventListener (TimerEvent) .TIMER, updateTime) stage.addEventListener (MouseEvent.CLICK, startGame)

Dans les quatre premières lignes, nous initialisons nos variables de champ.

Ensuite, nous nous assurons que notre scène est alignée sur le coin supérieur gauche et ne redimensionne pas.

Nous cachons le curseur de la souris. Notre curseur sera remplacé par le joueur Lutin. Ensuite nous appelons le setBackground fonction (expliquée à l'étape suivante).

Nous centrons notre But sur l'écran et l'ajouter à la liste d'affichage. Pour mettre à jour la position de ballPlayer nous attachons un événement MouseEvent.MOUSE_MOVE à la scène.

le updatePlayerBall function (expliqué à l'étape 11) gérera cet événement MouseEvent. Ensuite, nous ajoutons le ballPlayer à la liste d'affichage.

La minuterie sera utilisée pour afficher le temps de jeu. Nous attachons un écouteur TimerEvent.TIMER à notre minuterie, ce qui déclenchera la temps de mise à jour() fonction (expliquée à l'étape 12) toutes les 10 millisecondes.

Enfin, nous ajoutons un MouseEvent.CLICK à notre scène. le démarrer jeu la fonction (expliquée à l'étape 13) va alors commencer notre jeu.


Étape 10: Fonction setBackground ()

Cette fonction ajoute un arrière-plan dégradé radial à la liste d'affichage. Pour dessiner un dégradé sur un Sprite, vous devez définir le type de dégradé, les couleurs que vous souhaitez utiliser, les valeurs alpha des couleurs, les rapports (ceux-ci définissent la répartition des couleurs) et la méthode d'étalement..

Pour plus d'informations, consultez cette astuce sur les dégradés..

 fonction privée setBackground (): void type de var: String = "radial" var couleurs: Array = [0xffffff, 0xcccccc] var alphas: Array = [1, 1] var ratios: Array = [0, 255] var matr: Matrix = new Matrix () matr.createGradientBox (stage.stageWidth, stage.stageHeight, Math.PI / 2, 0, 0) // SpreadMethod définira comment le dégradé est étendu. Remarque!!! Flash utilise CONSTANTS pour représenter les littéraux de chaîne var sprMethod: String = "pad" // Démarrez Gradietn et transmettez-lui nos variables. Var sprite: Sprite = new Sprite () // Enregistrer le typage + augmenter les performances via une référence locale à un objet Graphics var g: Graphics = sprite.graphics g.beginGradientFill (type, couleurs, alphas, ratios, matr, méthode de spr) g.drawRect (0,0, stage.stageWidth, stage.stageHeight) stage.addChild (sprite)

Étape 11: Fonction updatePlayerBall ()

Cette fonction met à jour la position de ballPlayer selon la position de votre souris.

 fonction privée updatePlayerBall (e: MouseEvent): void ballPlayer.x = mouseX ballPlayer.y = mouseY

Étape 12: Fonction updateTime ()

Nous calculons le temps en secondes et le plaçons dans la zone de texte de notre But Lutin. Toutes les 5000 ms (cinq secondes), nous ajoutons une nouvelle balle au jeu..

 fonction privée updateTime (e: TimerEvent): void score.txtScore.text = String (((tmr.currentCount * tmr.delay) / 1000) .toFixed (2)); if ((tmr.currentCount * tmr.delay)% 5000 == 0) addBall (); 

Étape 13: Fonction startGame ()

Le jeu est démarré en cliquant sur la scène. Nous supprimons d’abord l’auditeur pour le clic de scène, de sorte que nous ne puissions pas démarrer le jeu plusieurs fois. Nous ajoutons trois balles au jeu en appelant le addBall () fonction (expliquée à l'étape suivante) trois fois. Nous commençons notre minuterie qui mettra à jour notre temps de jeu.

Enfin, nous ajoutons un événement ENTER_FRAME à notre scène. le gameLoop () fonction (expliquée à l'étape 15) mettra à jour la position de nos balles ennemies.

 fonction privée startGame (e: MouseEvent): void stage.removeEventListener (MouseEvent.CLICK, startGame) addBall () addBall () addBall () tmr.start () stage.addEventListener (Event.ENTER_FRAME, gameLoop)

Étape 14: Fonction addBall ()

Nous faisons d’abord une nouvelle instance de notre Ballon classe. Nous positionnons le ballon au hasard sur la scène avec un alpha de 0 et l'ajouter à la liste d'affichage.

Ensuite, nous interpolons l'alpha sur 1. (J'utilise TweenMax, il est inclus dans les fichiers source. Vous pouvez également utiliser le moteur d'interpolation Flash intégré.) La seconde interpolation n'est pas vraiment une interpolation. Il attend juste une seconde et le onComplete la fonction pousse le ballon dans notre balles tableau. De cette façon le gameLoop () la fonction (expliquée à l'étape suivante) peut gérer le reste.

 fonction privée addBall (): void var ball: Ball = nouveau Ball (10, Math.random () * Math.PI * 2, 5) ball.x = Math.random () * stage.stageWidth ball.y = Math .random () * stage.stageHeight ball.alpha = 0 stage.addChild (ball) TweenMax.to (ball, 0.5, alpha: 1) TweenMax.to (ball, 0, retard: 1, onComplete: fonction ( ): void eballs.push (ball))

Étape 15: Fonction gameLoop ()

Chaque image passera par cette fonction.

 fonction privée gameLoop (e: Event): void pour (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])  

Nous commençons par parcourir toutes nos boules ennemies.

La seconde boucle vérifie les collisions entre les balles ennemies. La boucle commence à 'i + 1'. De cette façon, nous ne vérifions pas les collisions.

Ensuite, nous vérifions si le ballPlayer frappe la balle ennemie. Si c'est le cas, le jeu est terminé. Ensuite, nous mettons à jour la position de notre balle ennemie.

Nous nous assurons que les balles restent dans l'écran de jeu en appelant la fonction checkBounds () (expliqué plus tard).


Étape 16: Fonction collision ()

Cette fonction vérifie si une paire de balles donnée entrent en collision.

Nous calculons d’abord la distance x et la distance y entre les deux balles. En utilisant le théorème de Pythagore (voir le diagramme suivant), nous calculons la distance absolue entre eux. Si la distance est inférieure ou égale à la somme des rayons des billes, il y a collision.

 collision de fonction privée (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) retourne Dist <= ball1.radius + ball2.radius 

Étape 17: Fonction doCollision ()

Cette fonction calculera les nouvelles vitesses x et y des billes en fonction de la vitesse et de l'angle de la collision. Attention: maths;)

Nous calculons d’abord la distance horizontale entre les deux boules, puis la distance verticale entre les boules. Avec ces distances (et un peu plus de trigonométrie), nous pouvons calculer l'angle entre les billes (voir diagramme).

Ensuite, nous calculons ce que j'appelle le ordre de grandeur de chaque balle. (Nous avons un vecteur xspeed et un vecteur yspeed; la magnitude est la somme vectorielle de ceux-ci.) Ensuite, nous calculons l'angle de chaque balle (similaire au calcul de l'angle précédent).

Nous tournons ensuite les nouvelles vitesses x et y de chaque balle. En réalité, nous faisons pivoter le système de coordonnées. En tournant nos axes, nous avons une collision 1D. (Voir le schéma suivant).

Newton dit que la quantité totale d'énergie cinétique dans un système fermé est constante. Maintenant, nous utilisons ces formules:

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

où:
v1 = xSpeedBall final 1
v2 = xSpeedBall final 2
m1 = boule de masse 1
m2 = boule de masse 2
u1 = balle de vitesse initiale 1
u2 = balle de vitesse initiale 2

Les vitesses y ne changent pas puisqu'il s'agit d'une collision 1D.

Avec ces formules, nous pouvons calculer le xSpeed et ySpeed de chaque balle.

Maintenant, nous avons les nouvelles vitesses x et y dans notre système de coordonnées en rotation. La dernière étape consiste à tout reconvertir en un système de coordonnées normal. Nous utilisons Math.PI / 2 parce que l'angle entre xSpeed et ySpeed doit toujours être à 90 degrés (pi / 2 radians).

 fonction privée 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: Nombre = magBall2 * Math.sin (angleBall2-collisionAngle) var finalxSpeedBall1: Numéro = ((ball1.mass-ball2.mass) * xSpeedBall1 + (ball2.mass + ball2.mass) * xSpeedBall2) / (ball1.mass + ball2.mass) var finalxSpeedBall2: Nombre = ((ball1.mass + ball1.mass) * xSpeedBall1 + (ball2.mass-ball1.mass) * xSpeedBall 2) / (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

Pour en savoir plus sur les collisions élastiques, consultez hoomanr.com.


Étape 18: Fonction endOfGame ()

Ceci est exécuté quand le jeu se termine.

 fonction privée endOfGame (): void tmr.stop () Mouse.show () stage.removeEventListener (MouseEvent.MOUSE_MOVE, updatePlayerBall) stage.removeEventListener (Event.ENTER_FRAME, gameLoop) tandis que (eballs.length> 0) TweenMax.to (eballs [0], 0.5, scaleX: 0, scaleY: 0, facilité: Bounce.easeOut) eballs.splice (0,1) TweenMax.to (ballPlayer, 0.5, scaleX: 0, scaleY: 0, facilité: Bounce.easeOut)

Tout d’abord, nous arrêtons le chronomètre. Nous montrons la souris à nouveau. Ensuite, nous supprimons les écouteurs d'événements MOUSE_MOVE et ENTER_FRAME. Enfin, nous faisons toutes les balles sur la scène invisible.


Étape 19: Fonction checkBounds ()

Cette fonction permet de s'assurer que les balles restent dans l'écran de jeu. Donc, si la balle frappe la partie supérieure ou inférieure, nous inversons la ySpeed. si la balle frappe le côté gauche ou droit de l'écran, nous inversons la xSpeed. Il utilise une logique similaire à la fonction de détection de collision de billes pour vérifier si les bords de la balle touchent un bord de l'écran..

 fonction privée checkBounds (ball: Ball): void if ((ball.x + ball.radius)> stage.stageWidth) ball.x = stage.stageWidth - ball.radius ball.xSpeed ​​* = -1 if (( 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 if ((ball.y - ball.radius) < 0)  ball.y = 0 + ball.radius ball.ySpeed *= - 1  

Étape 20: La classe d'application complète

Nous avons terminé notre classe d'application. Nous avons maintenant un jeu de travail!!!

 package 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; import com.greensock.TweenMax; importer com.greensock.easing. *; application de classe publique étend Sprite private var ballPlayer: Ball; variables privées: Array; private var tmr: Minuterie; score var privé: Score; fonction publique Application (): void init ();  fonction privée init (): void ballPlayer = new PlayerBall (); eballs = new Array (); tmr = nouvelle minuterie (10); score = nouveau score (); stage.align = "TL"; stage.scaleMode = "noScale"; Mouse.hide (); setBackground (); score.x = stage.stageWidth / 2; score.y = stage.stageHeight / 2; stage.addChild (score); stage.addEventListener (MouseEvent.MOUSE_MOVE, updatePlayerBall); stage.addChild (ballPlayer); tmr.addEventListener (TimerEvent.TIMER, updateTime); stage.addEventListener (MouseEvent.CLICK, startGame);  fonction privée setBackground (): void var type: String = "radial"; couleurs var: Array = [0xffffff, 0xcccccc]; var alphas: Array = [1,1]; rapports var: tableau = [0,255]; var matr: Matrix = new Matrix (); matr.createGradientBox (stage.stageWidth, stage.stageHeight, Math.PI / 2, 0, 0); // SpreadMethod définira comment le dégradé est étendu. Remarque!!! Flash utilise CONSTANTS pour représenter les littéraux de chaîne var sprMethod: String = "pad"; // Démarrer le Gradietn et lui passer nos variables var sprite: Sprite = new Sprite (); // Enregistrer la saisie + augmenter les performances via une référence locale à un objet Graphics var g: Graphics = sprite.graphics; g.beginGradientFill (type, couleurs, alphas, rapports, matr, sprMethod); g.drawRect (0,0, stage.stageWidth, stage.stageHeight); stage.addChild (sprite);  fonction privée updatePlayerBall (e: MouseEvent): void ballPlayer.x = mouseX; ballPlayer.y = mouseY;  fonction privée updateTime (e: TimerEvent): void score.txtScore.text = String (((tmr.currentCount * tmr.delay) / 1000) .toFixed (2)); if ((tmr.currentCount * tmr.delay)% 5000 == 0) addBall ();  fonction privée startGame (e: MouseEvent): void stage.removeEventListener (MouseEvent.CLICK, startGame); addBall (); addBall (); addBall (); tmr.start (); stage.addEventListener (Event.ENTER_FRAME, gameLoop);  fonction privée addBall (): void var ball: Ball = new Ball (10, Math.random () * Math.PI * 2,5); ball.x = Math.random () * stage.stageWidth; ball.y = Math.random () * stage.stageHeight; ball.alpha = 0; stage.addChild (balle); TweenMax.to (boule, 0,5, alpha: 1); TweenMax.to (ball, 0, delay: 1, onComplete: function (): void eballs.push (ball));  fonction privée gameLoop (e: Event): void pour (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, facilité: Bounce.easeOut); eballs.splice (0,1);  TweenMax.to (ballPlayer, 0.5, scaleX: 0, scaleY: 0, facilité: Bounce.easeOut);  fonction privée checkBounds (ball: Ball): void if ((ball.x + ball.radius)> stage.stageWidth) ball.x = stage.stageWidth - ball.radius; ball.xSpeed ​​* = -1;  if ((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;  if ((ball.y - ball.radius) < 0)  ball.y = 0 + ball.radius; ball.ySpeed *= -1;    

Conclusion

Voilà pour ce tutoriel. Bien sûr, vous pouvez ajouter la possibilité de redémarrer le jeu, mais cela ne devrait pas être trop difficile. Cet exemple de base de collisions élastiques peut être utilisé pour des jeux plus importants, comme un jeu de billard ou similaire..

J'espère que vous avez aimé ce tutoriel, merci d'avoir lu!