Jugando con colisiones elásticas

En este tutorial crearemos un juego en el que el objetivo es evitar que otros objetos colisionen con el cursor. No usaremos el flash incorporado. hitTestObject () metodos En cambio, escribiremos nuestras propias rutinas de detección de colisiones..

Tutorial republicado

Cada pocas semanas, revisamos algunas de las publicaciones favoritas de nuestros lectores de toda la historia del sitio. Este tutorial fue publicado por primera vez en febrero de 2011..


Vista previa del resultado final

Echemos un vistazo al resultado final en el que trabajaremos:


Paso 1: Comience

Crear un nuevo archivo Flash (ActionScript 3.0)

Establezca las dimensiones del escenario en 500x500px y FPS en 32.


Paso 2: La clase de pelota

Esta clase contendrá todos los datos relacionados con una bola. Una pelota tiene una _masa, una _radio, un _xvelocidad y un _y Velocidad. Así que haremos una propiedad para cada uno. En el constructor pasamos la masa, el ángulo y la velocidad de la pelota. Debido a que la clase se vinculará a un objeto de visualización, podemos recuperar el radio de nuestra bola dividiendo el ancho del objeto de visualización por 2. La _xvelocidad y _y Velocidad Se puede calcular utilizando funciones simples de seno y coseno..

 package import flash.display.Stage import flash.display.Sprite import flash.events.Event public class Ball se extiende Sprite private var _radius: Number = 0 private var _mass: Number = 0 private var _xSpeed: Number = 0 private var _ySpeed : Número = 0 función pública Bola (masa: Número = 10.0, ángulo: Número = Matemáticas.PI, velocidad: Número = 10.0): void this.mass = masa this._radius = this.width / 2 this.xSpeed ​​= speed * Math.sin (angle) this.ySpeed ​​= speed * Math.cos (angle)

Para obtener más información sobre estas funciones trigonométricas Math.sin () y Math.cos (), consulte este Consejo rápido..


Paso 3: Proporcionar recolectores y setters

En nuestra clase de pelota, proporcionamos captadores y setters para nuestras propiedades..

 función pública obtener radio (): número return this._radius conjunto de funciones públicas masa (masa: Número): void this._mass = mass función pública obtener masa (): número return this._mass conjunto de funciones públicas xSpeed (xSpeed: Number): void this._xSpeed ​​= xSpeed función pública get xSpeed ​​(): Number return this._xSpeed función pública set ySpeed ​​(ySpeed: Number): void this._ySpeed ​​= ySpeed función pública get ySpeed (): Número return this._ySpeed

Paso 4: Actualizar la función

Esta función actualiza las propiedades x e y de nuestra bola de acuerdo con la _xvelocidad y _y Velocidad. Implementaremos esta función en nuestra Bola clase.

 actualización de la función pública (): void this.x + = _xSpeed ​​this.y + = _ySpeed

Paso 5: La clase completada

Terminaremos nuestro Bola clase en este paso.

 package import flash.display.Stage import flash.display.Sprite import flash.events.Event public class Ball se extiende Sprite private var _radius: Number = 0 private var _mass: Number = 0 private var _xSpeed: Number = 0 private var _ySpeed : Número = 0 función pública Bola (masa: Número = 10.0, ángulo: Número = Matemáticas.PI, velocidad: Número = 10.0): void this.mass = masa this._radius = this.width / 2 this.xSpeed ​​= speed * Math.sin (angle) this.ySpeed ​​= speed * Math.cos (angle) public function get radius (): Number return this._radius mass de conjunto de funciones públicas (mass: Number): void this._mass = mass public function get mass (): Number return this._mass public function set xSpeed ​​(xSpeed: Number): void this._xSpeed ​​= xSpeed public function get xSpeed ​​(): Number return this._xSpeed public function establecer ySpeed ​​(ySpeed: Number): void this._ySpeed ​​= ySpeed función pública obtener ySpeed ​​(): Number return this._ySpeed función pública update (): void this.x + = _xSpeed ​​this.y + = _ySpeed 

Paso 6: Mostrar objetos para nuestra clase de pelota

En los archivos de origen, incluí una FLA de inicio que contiene todos los elementos de biblioteca que necesita. Puedes dibujarlos tú mismo si quieres, por supuesto. Asegúrese de que su FLA tenga los siguientes objetos de visualización:

(Nota del editor: ese es un error tipográfico: "ennemyball" debería decir "enemyball").


Paso 7: Vinculando nuestros objetos de la biblioteca

los Bola clase que acabamos de crear tiene que estar vinculada a la bola enemiga Sprite en la biblioteca.

los jugador de futbol Sprite debe tener Bola como clase base y PlayerBall como clase.

los Puntuación clip de película debe tener una Puntuación clase.


Paso 8: La clase de aplicación (Clase de documento)

los Solicitud La clase contendrá toda la lógica del juego. Importamos todas las clases que necesitamos. Como puedes ver estaremos usando TweenMax.

A continuación definimos nuestras variables de campo. La primera variable de campo es la jugador de pelota.

Porque la clase base de nuestra jugador de futbol Sprite es Bola podemos almacenar esta clase en el jugador de pelota variable. Esto facilita la verificación posterior de colisiones entre los jugador de pelota y las bolas enemigas.

La segunda variable de campo es una matriz que contendrá todas nuestras bolas enemigas. La tercera variable es el temporizador que se utilizará para realizar el bucle principal del juego. El cuarto y último campo es una instancia de nuestro Puntuación objeto de biblioteca que se utilizará para mostrar el tiempo de juego transcurrido. En el constructor lo llamamos en eso() Función que explicaré en el siguiente paso..

 package import flash.display.Sprite import flash.display.Graphics import flash.events.Event import flash.evils.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 La aplicación extiende Sprite private var ballPlayer: Ball private var eballs: Array private var tmr: Timer private var puntuación: Score public function Función (): void init ( )

No olvides vincular la clase de documento.!.


Paso 9: La función init ()

Echa un vistazo a este código:

 función privada 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 (Timer) .TIMER, updateTime) stage.addEventListener (MouseEvent.CLICK, startGame)

En las primeras cuatro líneas inicializamos nuestras variables de campo..

A continuación, nos aseguramos de que nuestro escenario esté alineado con la esquina superior izquierda y no se escala..

Ocultamos el cursor del mouse. Nuestro cursor será reemplazado por el jugador de futbol Duende. A continuación llamamos al Definir fondo función (explicada en el siguiente paso).

Centramos nuestro Puntuación en la pantalla y agregarlo a la lista de visualización. Para actualizar la posición de jugador de pelota adjuntamos un evento MouseEvent.MOUSE_MOVE al escenario.

los updatePlayerBall La función (explicada en el paso 11) manejará este MouseEvent. A continuación agregamos el jugador de pelota a la lista de visualización.

El temporizador se utilizará para mostrar el tiempo del juego. Adjuntamos un oyente TimerEvent.TIMER a nuestro temporizador, que activará el tiempo de actualizacion() Función (explicada en el Paso 12) cada 10 milisegundos.

Finalmente, agregamos un MouseEvent.CLICK a nuestro escenario. los empezar juego La función (explicada en el paso 13) iniciará nuestro juego..


Paso 10: Función setBackground ()

Esta función agrega un fondo de degradado radial a la lista de visualización. Para dibujar un degradado en un Sprite, debe definir el tipo de degradado, los colores que desea utilizar, los valores alfa de los colores, las relaciones (que definen la distribución de los colores) y el método de dispersión..

Para obtener más información, consulte este Consejo rápido sobre gradientes..

 función privada setBackground (): void var type: String = "radial" var colors: 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 definirá cómo se extiende el gradiente. ¡¡¡Nota!!! Flash usa CONSTANTS para representar los literales de cadena var sprMethod: String = "pad" // Inicie Gradietn y pase nuestras variables a él var sprite: Sprite = new Sprite () // Guardar escritura + aumente el rendimiento a través de una referencia local a un objeto Graphics var g: Gráficos = sprite.graphics g.beginGradientFill (tipo, colores, alfas, relaciones, matr, método de método) g.drawRect (0,0, stage.stageWidth, stage.stageHeight) stage.addChild (sprite)

Paso 11: Función updatePlayerBall ()

Esta función actualiza la posición de jugador de pelota Según la posición de tu ratón..

 función privada updatePlayerBall (e: MouseEvent): void ballPlayer.x = mouseX ballPlayer.y = mouseY

Paso 12: Función updateTime ()

Calculamos el tiempo en segundos y lo colocamos dentro del cuadro de texto de nuestro Puntuación Duende. Cada 5000 ms (cinco segundos) añadimos una nueva bola al juego..

 función privada updateTime (e: TimerEvent): void score.txtScore.text = String (((tmr.currentCount * tmr.delay) / 1000) .toFixed (2)); if ((tmr.currentCount * tmr.delay)% 5000 == 0) addBall (); 

Paso 13: Función startGame ()

El juego se inicia haciendo clic en el escenario. Primero eliminamos el oyente para el clic de escenario, de modo que no podamos iniciar el servidor varias veces. Añadimos tres bolas al juego llamando al addBall () Función (explicada en el siguiente paso) tres veces. Comenzamos nuestro temporizador que actualizará nuestro tiempo de juego..

Finalmente agregamos un evento ENTER_FRAME a nuestro escenario. los gameLoop () La función (explicada en el Paso 15) actualizará la posición de nuestras bolas enemigas.

 función privada startGame (e: MouseEvent): void stage.removeEventListener (MouseEvent.CLICK, startGame) addBall () addBall () addBall () tmr.start () stage.addEventListener (Event.ENTER_FRAME, gameLoop)

Paso 14: Función addBall ()

Primero hacemos una nueva instancia de nuestro Bola clase. Posicionamos el bola Al azar en el escenario con un alfa de 0 y agréguelo a la lista de visualización.

A continuación, volvemos a interpolar el alfa a 1. (Yo uso TweenMax, está incluido en los archivos de origen. También puede usar el motor de interpolación Flash incorporado). La segunda interpolación no es realmente una interpolación. Solo espera un segundo y el onComplete función empuja el bola en nuestro eballs formación. De esta manera el gameLoop () La función (explicada en el siguiente paso) puede manejar el resto..

 función privada 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 (ball) TweenMax.to (ball, 0.5, alpha: 1) TweenMax.to (ball, 0, delay: 1, onComplete: function ( ): void eballs.push (ball))

Paso 15: Función gameLoop ()

Cada fotograma pasará por esta función..

 función privada gameLoop (e: Event): void for (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])  

Comenzamos por iterar a través de todas nuestras bolas enemigas.

El segundo for-loop comprueba las colisiones entre las bolas enemigas. El bucle comienza en 'i + 1'. De esta manera no revisamos las colisiones..

A continuación comprobamos si el jugador de pelota golpea la bola enemiga. Si es así, el juego está terminado. Luego actualizamos la posición de nuestra bola enemiga..

Nos aseguramos de que las bolas permanezcan en la pantalla del juego llamando a la función checkBounds () (explicado más adelante).


Paso 16: Función de colisión ()

Esta función verifica si algún par de bolas dado está chocando.

Primero calculamos la distancia x y la distancia y entre las dos bolas. Usando el Teorema de Pitágoras (ver el siguiente diagrama) calculamos la distancia absoluta entre ellos. Si la distancia es menor o igual a la suma de los radios de las bolas, tenemos una colisión..

 función privada colision (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) return Dist <= ball1.radius + ball2.radius 

Paso 17: Función doCollision ()

Esta función calculará las nuevas velocidades x e y de las bolas según la velocidad y el ángulo de la colisión. Advertencia: matemáticas;)

Primero calculamos la distancia horizontal entre las dos bolas y luego la distancia vertical entre las bolas. Con estas distancias (y un poco más de trigonometría) podemos calcular el ángulo entre las bolas (ver diagrama).

A continuación calculamos lo que llamo el magnitud de cada bola. (Tenemos un vector de velocidad x y un vector de velocidad y; la magnitud es la suma vectorial de esos). Luego calculamos el ángulo de cada bola (similar al cálculo del ángulo anterior).

A continuación rotamos las nuevas velocidades x e y de cada bola. Lo que realmente estamos haciendo es rotar el sistema de coordenadas. Al rotar nuestros ejes tenemos una colisión 1D. (Ver el siguiente diagrama).

Newton dice que la cantidad total de energía cinética en un sistema cerrado es constante. Ahora usamos estas fórmulas:

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

dónde:
v1 = xSpeedBall final 1
v2 = xSpeedBall final 2
m1 = bola de masa 1
m2 = bola de masa 2
u1 = bola de velocidad inicial 1
u2 = bola de velocidad inicial 2

Las velocidades y no cambian ya que es una colisión 1D.

Con estas fórmulas podemos calcular el xSpeed y ySpeed de cada bola.

Ahora tenemos las nuevas velocidades x e y en nuestro sistema de coordenadas rotado. El último paso es convertir todo de nuevo a un sistema de coordenadas normal. Usamos Matemáticas.PI / 2 porque el angulo entre xSpeed y ySpeed Siempre debe ser de 90 grados (pi / 2 radianes).

 función privada 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-collision) ) var ySpeedBall1: Number = magBall1 * Math.sin (angleBall1-collisionAngle) var xSpeedBall2: Number = magBall2 * Math.cos (angleBall2-collisionAngle) var ySpeedBall2: Number = magBall2 * Math.sin (angleBall2) colecciones de artículos = ((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) * xSpeedBall 2) / (ball1.mass + ball2.mass) var finalySpeedBall1: Number = ySpeedBall1 var finalySpeedBall2: Number = ySpeedBall2 ball1.xSpeed ​​= Math.cos (collisionAngle) * finalxSpeedBall1 + Math.cos (collisionAngle + +) finalySpeedBall1 ball1.ySpeed ​​= Math.sin (collisionAngle) * finalxSpeedBall1 + Math.sin (collisionAngle + Math.PI / 2) * finalySpeedBall1 ball2.xSpeed ​​= Math. / 2) * finalySpeedBall2 ball2.ySpeed ​​= Math.sin (collisionAngle) * finalxSpeedBall2 + Math.sin (collisionAngle + Math.PI / 2) * finalySpeedBall2

Para encontrar más información sobre colisiones elásticas, eche un vistazo a hoomanr.com.


Paso 18: Función endOfGame ()

Esto se ejecuta cuando el juego termina.

 función privada endOfGame (): void tmr.stop () Mouse.show () stage.removeEventListener (MouseEvent.MOUSE_MOVE, updatePlayerBall) stage.removeEventListener (Event.ENTER_FRAME, gameLoop) while (eballs.length> 0) Tweeneen (eballs [0], 0.5, scaleX: 0, scaleY: 0, facilidad: Bounce.easeOut) eballs.splice (0,1) TweenMax.to (ballPlayer, 0.5, scaleX: 0, scaleY: 0, facilidad: Bounce.easeOut)

En primer lugar todos paramos el temporizador. Mostramos el ratón de nuevo. A continuación, eliminamos los escuchas de eventos MOUSE_MOVE y ENTER_FRAME. Finalmente hacemos invisibles todas las bolas en el escenario..


Paso 19: Función checkBounds ()

Esta función asegura que las bolas permanezcan dentro de la pantalla del juego. Así que si la bola golpea el lado superior o inferior, revertimos el ySpeed. Si la bola golpea el lado izquierdo o derecho de la pantalla, revertimos la xSpeed. Utiliza una lógica similar a la función de detección de colisión de la bola para comprobar si los bordes de la bola golpean un borde de la pantalla.

 Función privada 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  

Paso 20: La clase de aplicación completa

Hemos completado nuestra clase de aplicación. Ahora tenemos un juego de trabajo.!!!

 paquete import flash.display.Sprite; importar flash.display.Graphics; import flash.events.Event; import flash.events.TimerEvent; import flash.events.MouseEvent; importar flash.geom.Matrix; import flash.utils.Timer; importar flash.ui.Mouse; import com.greensock.TweenMax; import com.greensock.easing. *; Aplicación pública de clase extiende Sprite private var ballPlayer: Ball; var eballs privados: Array; privado var tmr: temporizador; puntaje de var privado: puntaje; Aplicación de función pública (): void init ();  función privada init (): void ballPlayer = new PlayerBall (); eballs = new Array (); tmr = nuevo temporizador (10); puntuación = nueva puntuación (); stage.align = "TL"; stage.scaleMode = "noScale"; Mouse.hide (); Definir fondo(); score.x = stage.stageWidth / 2; score.y = stage.stageHeight / 2; stage.addChild (puntuación); stage.addEventListener (MouseEvent.MOUSE_MOVE, updatePlayerBall); stage.addChild (ballPlayer); tmr.addEventListener (TimerEvent.TIMER, updateTime); stage.addEventListener (MouseEvent.CLICK, startGame);  función privada setBackground (): void var type: String = "radial"; var colors: 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 definirá cómo se extiende el degradado. ¡¡¡Nota!!! Flash usa CONSTANTS para representar literales de cadena var sprMethod: String = "pad"; // Inicia Gradietn y pasale nuestras variables var sprite: Sprite = new Sprite (); // Guardar la escritura y aumentar el rendimiento mediante la referencia local a un objeto Graphics var g: Graphics = sprite.graphics; g.beginGradientFill (tipo, colores, alfas, relaciones, matr, método de ejecución); g.drawRect (0,0, stage.stageWidth, stage.stageHeight); stage.addChild (sprite);  función privada updatePlayerBall (e: MouseEvent): void ballPlayer.x = mouseX; ballPlayer.y = mouseY;  función privada updateTime (e: TimerEvent): void score.txtScore.text = String ((((tmr.currentCount * tmr.delay) / 1000) .toFixed (2)); if ((tmr.currentCount * tmr.delay)% 5000 == 0) addBall ();  función privada startGame (e: MouseEvent): void stage.removeEventListener (MouseEvent.CLICK, startGame); addBall (); addBall (); addBall (); tmr.start (); stage.addEventListener (Event.ENTER_FRAME, gameLoop);  función privada 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 (pelota); TweenMax.to (bola, 0.5, alfa: 1); TweenMax.to (ball, 0, delay: 1, onComplete: function (): void eballs.push (ball));  función privada gameLoop (e: Event): void for (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, facilidad: Bounce.easeOut); eballs.splice (0,1);  TweenMax.to (ballPlayer, 0.5, scaleX: 0, scaleY: 0, ease: Bounce.easeOut);  función privada 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;    

Conclusión

Eso es todo para este tutorial. Por supuesto, podría agregar la posibilidad de reiniciar el juego, pero eso no debería ser demasiado difícil. Este ejemplo básico de colisiones elásticas puede usarse para juegos más grandes como un juego de billar o similar..

Espero que te haya gustado este tutorial, gracias por leerlo.!