Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
Este tutorial lo guiará mediante la adición de mortíferos y certeros misiles guiados al arsenal de su próximo juego.
Vista previa del resultado final
Echemos un vistazo al resultado final para el que trabajaremos:
Paso 1: configure el documento FLA
Cree un nuevo conjunto de documentos de Flash para ActionScript 3.0. Usaré las dimensiones de 600x400 y una velocidad de cuadro de 30 FPS. Guarde el archivo con un nombre de su elección.



Paso 2: crea una clase de documento
Además del FLA, también necesitamos crear una clase de documento. Crea un nuevo archivo Actionscript y agrega este código:
package { import flash.display.Sprite; public class Main extends Sprite { public function Main() { } } }
Guarde este archivo en el mismo directorio que nuestro FLA. Nómbrelo Main.as.
Paso 3: Enlace la clase Main con el FLA
Para compilar el código de la clase Main, necesitamos vincularlo con la FLA. En el panel Propiedades de FLA, al lado Class, ingrese el nombre de la clase de documento, en este caso, Principal.

Luego, guarde los cambios en el FLA.
Paso 4: dibuja un misil
Necesitamos un gráfico de misiles que se muestre al disparar. Puede importar un mapa de bits o dibujar una forma allí mismo en Flash. Usaré una forma pequeña en este ejemplo.

Lo que es importante aquí es que tienes que hacer que el punto del misil se dirija hacia la derecha, ya que ese es el punto de origen de la rotación. Por lo tanto, 0 ° significa que apunta directamente hacia la derecha, -90 ° significa hacia arriba, 90 ° significa hacia abajo y 180 ° hacia la izquierda. Más adelante necesitaremos rotar el misil según su dirección.
Paso 5: Crea un MovieClip para el misil
Una vez que tenga el gráfico de misiles, selecciónelo y presione F8 para crear un Clip de película. Llámalo Missile ("Misil"), asegúrate de que el Punto de registro esté en el centro y marca la casilla "Exportar para ActionScript".



Terminará con un Misil MovieClip en la Biblioteca.

Si tiene una instancia de Misiles en el escenario, elimínela. Vamos a agregar el Misil MovieClip por código.
Paso 6: apuntar
Lo primero que debe saber un misil de orientación es dónde se encuentra el objetivo. Primero vamos a establecer la rotación del misil según la posición del cursor del mouse. Trabajemos con el evento enterFrame para una actualización de rotación constante.
Agregue una instancia de Missile al escenario, la colocaré en el centro (300, 200). Luego calcule la distancia desde el misil al cursor del mouse (lo estoy almacenando en las variables targetX y targetY). Finalmente, el ángulo del misil será la arcotangente de ambos puntos (targetX, targetY). El resultado que obtendrás será en radianes, pero la rotación funciona en grados, por lo que tendrás que hacer la conversión multiplicando por 180 / Pi. (Para ver por qué, consulte este artículo).
import flash.events.Event; public class Main extends Sprite { private var missile:Missile = new Missile(); public function Main() { addChild(missile); missile.x = 300; missile.y = 200; addEventListener(Event.ENTER_FRAME, playGame); } private function playGame(event:Event):void { var targetX:int = mouseX - missile.x; var targetY:int = mouseY - missile.y; missile.rotation = Math.atan2(targetY, targetX) * 180 / Math.PI; } }
(¿No estás seguro de qué es Math.atan2
()? Mira este artículo sobre trigonometría.
Si Publicas (Ctrl + Enter) el documento en este punto, debería obtener algo como esto:
Mueva su mouse cerca del misil para verlo girar.
Paso 7: buscar
Tenemos la rotación, ahora necesitamos el movimiento. El misil tiene que buscar el objetivo, sin importar si es un objetivo constante o en movimiento. Lo que haremos es calcular el movimiento de acuerdo con la rotación actual del misil. Establezcamos un valor para la velocidad y hagamos la persecución de misiles después del cursor del mouse.
Incluiremos un par de nuevas variables para calcular la velocidad (vx, vy). Cuando el misil apunta hacia la derecha, su ángulo es inferior a 90 ° y superior a -90 °, por lo que siempre es menor que el valor absoluto de 90 °. Cuando está apuntando hacia la izquierda, su ángulo tiene un valor absoluto superior a 90 °. Esto determinará vx de acuerdo con la velocidad, entonces vy será la diferencia de velocidad y vx.
private var speed:int = 10; public function Main() { addChild(missile); missile.x = 300; missile.y = 200; addEventListener(Event.ENTER_FRAME, playGame); } private function playGame(event:Event):void { var targetX:int = mouseX - missile.x; var targetY:int = mouseY - missile.y; missile.rotation = Math.atan2(targetY, targetX) * 180 / Math.PI; //Velocity in x is relative to the angle, when it's 90° or -90°, vx should be 0. var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90; var vy:Number;//Velocity in y is the difference of speed and vx. if (missile.rotation < 0) vy = -speed + Math.abs(vx);//Going upwards. else vy = speed - Math.abs(vx);//Going downwards. missile.x += vx; missile.y += vy; }
Obtendrás un misil persiguiendo tu cursor.
Puede usar una velocidad diferente si lo desea.
Paso 8: Crea un lanzador de misiles
Los misiles no salen de la nada, se disparan desde los lanzadores de misiles. Hagamos un MovieClip que represente un cañón (usaré un rectángulo simple) y asígnele el nombre Cannon. Voy a agregar una instancia de Cannon por código, así que voy a mantener el escenario vacío.

Paso 9: Disparar
Ahora, en lugar de agregar un misil, solo voy a agregar un cañón, y se agregará un misil en la posición del cañón cuando haga clic en el escenario. Agregaremos un booleano para verificar si el misil se ha disparado, y también una nueva función para disparar después del clic.
import flash.events.MouseEvent; public class Main extends Sprite { private var missile:Missile = new Missile(); private var speed:int = 10; private var cannon:Cannon = new Cannon(); private var missileOut:Boolean = false;//Has the missile been shot? public function Main() { addChild(cannon); cannon.x = 50; cannon.y = 380; addEventListener(Event.ENTER_FRAME, playGame); stage.addEventListener(MouseEvent.CLICK, shoot); } private function playGame(event:Event):void { if (missileOut) { var targetX:int = mouseX - missile.x; var targetY:int = mouseY - missile.y; missile.rotation = Math.atan2(targetY, targetX) * 180 / Math.PI; var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90; var vy:Number; if (missile.rotation < 0) vy = -speed + Math.abs(vx); else vy = speed - Math.abs(vx); missile.x += vx; missile.y += vy; } } private function shoot(event:MouseEvent):void { if (!missileOut) { addChild(missile); swapChildren(missile, cannon);//missile will come out from behind cannon missileOut = true; missile.x = cannon.x; missile.y = cannon.y; } }
Esto es lo que obtendrás:
Esto no se ve bien Tenemos que hacer que el cañón gire también o forzar al misil a ir hacia arriba inmediatamente después de recibir el disparo. Como la opción n. ° 1 es el enfoque más fácil, tomaremos la opción n. ° 2.
Paso 10: menos precisión para una mejor apariencia
Si el cañón es vertical, esperaríamos que el misil se lanzara hacia arriba y luego se encaminara hacia su objetivo. El enfoque que usaré para lograr esto es dar al misil un ángulo inicial de -90 ° (apuntando hacia arriba), y girar suavemente para seguir el curso del cursor del mouse. Agregaremos una variable ease para determinar la suavidad o nitidez de la rotación. Luego crearemos otra variable para hacer un seguimiento de la rotación real que apunta directamente al objetivo, mientras que la rotación del misil cambiará de acuerdo con ease que establezcamos (ease = 1 se comportará como antes, cualquier cosa más alta hará un giro más suave )
Como la mitad de los valores de rotación son negativos, en algunos casos tendremos que calcularlos contra 360 para obtener la diferencia real entre el ángulo objetivo y la rotación del misil.
private var ease:int = 10; public function Main() { addChild(cannon); cannon.x = 50; cannon.y = 380; addEventListener(Event.ENTER_FRAME, playGame); stage.addEventListener(MouseEvent.CLICK, shoot); } private function playGame(event:Event):void { if (missileOut) { var targetX:int = mouseX - missile.x; var targetY:int = mouseY - missile.y; var rotation:int = Math.atan2(targetY, targetX) * 180 / Math.PI; if (Math.abs(rotation - missile.rotation) > 180) { if (rotation > 0 && missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotation < 0) missile.rotation += (360 - rotation + missile.rotation) / ease; } else if (rotation < missile.rotation) missile.rotation -= Math.abs(missile.rotation - rotation) / ease; else missile.rotation += Math.abs(rotation - missile.rotation) / ease; var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90; var vy:Number; if (missile.rotation < 0) vy = -speed + Math.abs(vx); else vy = speed - Math.abs(vx); missile.x += vx; missile.y += vy; } } private function shoot(event:MouseEvent):void { if (!missileOut) { addChild(missile); swapChildren(missile, cannon);//missile will come out from behind cannon missileOut = true; missile.x = cannon.x; missile.y = cannon.y; missile.rotation = -90;//missile will start pointing upwards } }
Echale un vistazo:
Observe lo que sucede cuando saca su mouse del SWF, y cómo esto es diferente del ejemplo anterior.
Paso 11: Impactos de misiles, explosiones de misiles
Además del Clip Missile, necesitamos una animación de explosión. En mi caso, haré un MovieClip por separado con una simple interpolación de un círculo que se expande. Lo estoy exportando como Explosion. Presione O para seleccionar la Herramienta Oval, y mantenga presionada la tecla Mayús mientras dibuja el óvalo para obtener un círculo.



Para un efecto visual más agradable, pondré el círculo dentro de otro clip de película propio y le daré un filtro Bevel para obtener un color más oscuro en la parte inferior y un color más claro en la parte superior. A continuación, iré al cuadro 10 y presionaré F6 para crear un Keyframe, luego haré clic derecho entre el fotograma 1 y 10 y crearé un Tween clásico. De vuelta en el cuadro 10, presione Q para seleccionar la herramienta Transformación libre y ampliar el círculo.



Luego, cree otro Classic Tween para el cuadro 20, agregaré un efecto de filtro Blur.



Finalmente, haz que desaparezca en un último Tween clásico en el fotograma 30 con un efecto de color Alpha yendo a 0.

Paso 12: limpiar el escenario
La animación de explosión debe eliminarse después de que termine, o se repetirá indefinidamente. Agregue una nueva capa y presione F6 en el último cuadro, luego presione F9 para abrir el panel Actions y agregue este código:
stop();<br />parent.removeChild(this);
Esto hará que la instancia de Explosion se elimine después de que la animación haya terminado.



Paso 13: Explotar
Ahora cuando el misil se encuentra con el cursor, lo
reemplazaremos con una instancia de Explosión. Solo necesitamos agregar
un nuevo condicional en la función playGame()
.
private function playGame(event:Event):void { if (missileOut) { if (missile.hitTestPoint(mouseX, mouseY)) { var explosion:Explosion = new Explosion(); addChild(explosion); explosion.x = missile.x; explosion.y = missile.y; removeChild(missile); missileOut = false; } else { var targetX:int = mouseX - missile.x; var targetY:int = mouseY - missile.y; var rotation:int = Math.atan2(targetY, targetX) * 180 / Math.PI; if (Math.abs(rotation - missile.rotation) > 180) { if (rotation > 0 && missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotation < 0) missile.rotation += (360 - rotation + missile.rotation) / ease; } else if (rotation < missile.rotation) missile.rotation -= Math.abs(missile.rotation - rotation) / ease; else missile.rotation += Math.abs(rotation - missile.rotation) / ease; var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90; var vy:Number; if (missile.rotation < 0) vy = -speed + Math.abs(vx); else vy = speed - Math.abs(vx); missile.x += vx; missile.y += vy; } } }
Echale un vistazo:
Paso 14: algo más para explotar
Perseguir el cursor del mouse fue entretenido, pero no tiene sentido en un juego; necesitamos hacer un objetivo Voy a dibujar un grupo de círculos para formar un clip Target (Objetivo).

Paso 15: dispara al objetivo
Ahora agregaremos una instancia Target para que el misil tenga un objetivo más tangible. Reemplazaremos cualquier referencia del cursor del mouse por la posición del objetivo. Además, no probaremos un punto de golpe, sino un objeto.
private var target:Target = new Target(); public function Main() { addChild(cannon); cannon.x = 50; cannon.y = 380; addEventListener(Event.ENTER_FRAME, playGame); stage.addEventListener(MouseEvent.CLICK, shoot);addChild(target); target.x = 550; target.y = 50; } private function playGame(event:Event):void { if (missileOut) { if (missile.hitTestObject(target)) { var explosion:Explosion = new Explosion(); addChild(explosion); explosion.x = missile.x; explosion.y = missile.y; removeChild(missile); missileOut = false; } else { var targetX:int = target.x - missile.x; var targetY:int = target.y - missile.y; var rotation:int = Math.atan2(targetY, targetX) * 180 / Math.PI; if (Math.abs(rotation - missile.rotation) > 180) { if (rotation > 0 && missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotation < 0) missile.rotation += (360 - rotation + missile.rotation) / ease; } else if (rotation < missile.rotation) missile.rotation -= Math.abs(missile.rotation - rotation) / ease; else missile.rotation += Math.abs(rotation - missile.rotation) / ease; var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90; var vy:Number; if (missile.rotation < 0) vy = -speed + Math.abs(vx); else vy = speed - Math.abs(vx); missile.x += vx; missile.y += vy; } } } private function shoot(event:MouseEvent):void { if (!missileOut) { addChild(missile); swapChildren(missile, cannon); //missile will come out from behind cannon missileOut = true; missile.x = cannon.x; missile.y = cannon.y; missile.rotation = -90;//missile will start pointing upwards } }
El método
hitTestObject()
solo busca una superposición entre los cuadros
delimitadores de los dos objetos (es decir, los cuadros azules que
aparecen cuando hace clic en una instancia del objeto en el escenario),
así que tenga cuidado con eso; no es una detección de colisión perfecta para píxeles. Sin embargo, hace bien el trabajo aquí.
Puede intentar colocar el objetivo en diferentes lugares, así como en el cañón.
Paso 16: objetivo en movimiento
Ya vimos que el misil perseguirá un objetivo en movimiento, como el cursor del mouse, así que ahora hagamos que la instancia Target se mueva un poco.
Esto no es física realista, solo voy a hacer que el objetivo rebote verticalmente. Elegiré un punto de referencia como el nivel del suelo y agregaré un valor de gravedad para afectar al objetivo. Y para hacerlo más dinámico, aumentaré la velocidad del misil a 15.
private var floor:int = 385; private var gravity:Number = 0.5; private var targetVY:Number = 0;//Current vertical velocity of the target public function Main() { addChild(cannon); cannon.x = 50; cannon.y = 380; addEventListener(Event.ENTER_FRAME, playGame); stage.addEventListener(MouseEvent.CLICK, shoot);addChild(target); target.x = 550; target.y = 50; } private function playGame(event:Event):void { if (missileOut) { if (missile.hitTestObject(target)) { var explosion:Explosion = new Explosion(); addChild(explosion); explosion.x = missile.x; explosion.y = missile.y; removeChild(missile); missileOut = false; } else { var targetX:int = target.x - missile.x; var targetY:int = target.y - missile.y; var rotation:int = Math.atan2(targetY, targetX) * 180 / Math.PI; if (Math.abs(rotation - missile.rotation) > 180) { if (rotation > 0 && missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotation < 0) missile.rotation += (360 - rotation + missile.rotation) / ease; } else if (rotation < missile.rotation) missile.rotation -= Math.abs(missile.rotation - rotation) / ease; else missile.rotation += Math.abs(rotation - missile.rotation) / ease; var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90; var vy:Number; if (missile.rotation < 0) vy = -speed + Math.abs(vx); else vy = speed - Math.abs(vx); missile.x += vx; missile.y += vy; } } targetVY += gravity; target.y += targetVY; if (target.y > floor) { target.y = floor; targetVY = -18; } }
Si publicas esto ahora, debería obtener un objetivo en movimiento.
Conclusión
Ya sea que desee un misil de orientación preciso o prefiera una animación sin problemas, puede obtener ambos resultados según este ejemplo. Ahora tienes una nueva arma para agregar en tu arsenal, tal vez podrías intentar hacer un juego similar a Worms, o incluso usar el algoritmo en algo que no sea un misil, como un extraño mosquito que sigue a tu personaje.
Espero que hayas encontrado este tutorial útil. ¡Gracias por leer!