En el tutorial anterior tuvimos un misil perseguidor persiguiendo un solo objetivo. Este tutorial te mostrará cómo convertir tus misiles guiados en misiles que buscan calor para múltiples objetivos.
Si no has leído el primer tutorial de Homing Missile, puedes descargar este archivo .zip, que contiene el código fuente con el que comenzaremos en este tutorial..
Echemos un vistazo al resultado final en el que trabajaremos:
El único clip de película en la biblioteca que deberemos cambiar es el Cañón, Ya que lo haremos apuntar al objetivo más cercano antes de disparar. Recuerda que 0 de rotación Significa que apunta a la derecha, así que haz el gráfico correspondiente.
Voy a reutilizar el targetX y objetivo variables para calcular la distancia del cañón desde el objetivo, así que las declararé al comienzo de la clase en lugar de dentro de la jugar un juego función, así como una nueva variable para almacenar la distancia calculada:
misil privado var: Misil = nuevo Misil (); velocidad de var privado: int = 15; cañón var privado: Cañón = cañón nuevo (); private var missileOut: Boolean = false; facilidad de var privado: int = 10; privada var target: Target = new Target (); piso var privado: int = 385; gravedad privada var: Número = 0.5; private var targetVY: Number = 0; // Velocidad vertical actual de la distancia var de private target: int; privado var targetX: int; privada var targetY: int;
Ahora el targetX y objetivo Las variables ya serán declaradas para el jugar un juego función:
función privada playGame (evento: Evento): void if (missileOut) if (missile.hitTestObject (target)) var explosion: Explosion = new Explosion (); addChild (explosión); explosion.x = missile.x; explosion.y = missile.y; removeChild (misil); missileOut = falso; else targetX = target.x - missile.x; targetY = target.y - missile.y; rotación de var: int = Math.atan2 (targetY, targetX) * 180 / Math.PI; if (Math.abs (rotación - missile.rotation)> 180) si (rotación> 0 y& missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 y rotación < 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 > piso) target.y = piso; targetVY = -18;
Anteriormente en el jugar un juego Para nuestra función, solo nos interesaba saber si el misil estaba fuera para ocuparse de su rotación y movimiento. Ahora primero debemos saber si el misil aún no se ha disparado y actualizar la rotación del cañón.
función privada playGame (evento: Evento): void if (! missileOut) targetX = target.x - cannon.x; targetY = target.y - cannon.y; cannon.rotation = Math.atan2 (targetY, targetX) * 180 / Math.PI; else if (missile.hitTestObject (target)) var explosion: Explosion = new Explosion (); addChild (explosión); explosion.x = missile.x; explosion.y = missile.y; removeChild (misil); missileOut = falso; else targetX = target.x - missile.x; targetY = target.y - missile.y; rotación de var: int = Math.atan2 (targetY, targetX) * 180 / Math.PI; if (Math.abs (rotación - missile.rotation)> 180) si (rotación> 0 y& missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 y rotación < 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 > piso) target.y = piso; targetVY = -18;
Ahora el cañón gira en relación a la posición del objetivo..
El cañón está girando, pero el misil sigue siendo disparado hacia arriba. Reemplace la rotación codificada por la ubicación actual del cañón en el momento en que se dispara el misil.
sesión de función privada (evento: MouseEvent): void if (! missileOut) addChild (missile); swapChildren (misil, cañón); // el misil saldrá por detrás del cañón missileOut = true; missile.x = cannon.x; missile.y = cannon.y; missile.rotation = cannon.rotation;
Ahora el misil se verá como si estuviera saliendo del cañón.
En este momento, el misil homing es un programa para perseguir un objetivo, pero ¿y si tenemos más objetivos? ¿Cómo decidirá a cuál ir después??
Primero, decidamos cuántos objetivos habrá, luego pondremos cada objetivo en un Array. En este ejemplo, voy a decir que hay 2 objetivos, y le daré a cada objetivo una posición aleatoria en la pantalla.
objetivo var privado: objetivo; piso var privado: int = 385; gravedad privada var: Número = 0.5; private var targetVY: Number = 0; // Velocidad vertical actual de la distancia var de private target: int; privado var targetX: int; privada var targetY: int; privado var numTargets: int = 2; objetivos var privados: Array = []; Función pública Main () addChild (cañón); cannon.x = 50; cannon.y = 380; addEventListener (Event.ENTER_FRAME, playGame); stage.addEventListener (MouseEvent.CLICK, disparar); para (var i: int = 0; i < numTargets; i++) target = new Target(); addChild(target); target.x = Math.random() * 600; target.y = Math.random() * 400; targets.push(target);
Ahora tenemos más de un objetivo en pantalla..
El misil sigue reconociendo la existencia de un solo objetivo. Lo arreglaremos a continuación.
Tenemos el misil buscando el objetivo variable, así que vamos a ver el objetivos
Array y ver cuál está más cerca. los objetivo La variable será la referencia más cercana al principio de la jugar un juego función.
función privada playGame (evento: Evento): void for (var i: int = 0; i < targets.length; i++) targetX = targets[i].x - missile.x; targetY = targets[i].y - missile.y; var dist:int = Math.sqrt(targetX * targetX + targetY * targetY);//the distance from one point to another in a 2D space. if (i == 0 || dist < distance) distance = dist; target = targets[i];
En este punto, el objetivo más cercano es el único que se mueve, pero el misil está reconociendo la existencia de ambos:
Es posible que hayas notado que mientras el misil busca el objetivo esperado, el cañón apunta al mismo objetivo, sin importar si está más cerca o más lejos que el otro. La distancia se establece en relación con la posición del misil, por lo que si no hay misiles en el escenario, necesitamos actualizar su posición para que coincida con el cañón para que siempre sepa cuál está más cerca..
función privada playGame (evento: Evento): void for (var i: int = 0; i < targets.length; i++) targetX = targets[i].x - missile.x; targetY = targets[i].y - missile.y; var dist:int = Math.sqrt(targetX * targetX + targetY * targetY); if (i == 0 || dist < distance) distance = dist; target = targets[i]; if (!missileOut) missile.x = cannon.x; missile.y = cannon.y; targetX = target.x - cannon.x; targetY = target.y - cannon.y; cannon.rotation = Math.atan2(targetY, targetX) * 180 / Math.PI;
Ahora el cañón siempre apuntará al objetivo más cercano..
Antes de disparar el misil, el cañón ya está apuntando al objetivo más cercano, y cambiará de dirección si se mueve más cerca del otro objetivo. Agreguemos un par de líneas para posicionar el cañón con el cursor del mouse.
función privada playGame (evento: Evento): void cannon.x = mouseX; cannon.y = mouseY;
Ahora puedes mover el cañón libremente..
Para hacer las cosas más dinámicas aquí, voy a reubicar un objetivo después de ser alcanzado por un misil, o Reemplázalo por uno nuevo., y dejar un Explosión instancia en su lugar.
if (missile.hitTestObject (target)) var explosion: Explosion = new Explosion (); addChild (explosión); explosion.x = missile.x; explosion.y = missile.y; removeChild (misil); missileOut = falso; explosión = nueva explosión (); addChild (explosión); explosion.x = target.x; explosion.y = target.y; explosion.scaleX = explosion.scaleY = 1.5; target.x = Math.random () * 600;
Esto es lo que obtendrás:
Hicimos múltiples objetivos, por lo que ahora podemos hacer varios misiles de la misma manera. La diferencia aquí es que todos los misiles deben seguir moviéndose en todo momento hasta que impacten, y en realidad vamos a eliminar aquellos que ya han explotado, por lo que necesitamos modificar algunas líneas de nuestro código para que esto funcione. Primero, necesitaremos un Array para los misiles..
misiles privados var: Array = [];
Entonces, necesitamos asegurarnos de que todos los misiles se comporten correctamente:
función privada playGame (evento: Evento): void cannon.x = mouseX; cannon.y = mouseY; para (var i: int = 0; i < targets.length; i++) targetX = targets[i].x - missile.x; targetY = targets[i].y - missile.y; var dist:int = Math.sqrt(targetX * targetX + targetY * targetY); if (i == 0 || dist < distance) distance = dist; target = targets[i]; if (!missileOut) missile.x = cannon.x; missile.y = cannon.y; targetX = target.x - cannon.x; targetY = target.y - cannon.y; cannon.rotation = Math.atan2(targetY, targetX) * 180 / Math.PI; else for (i = 0; i < missiles.length; i++)//each missile must keep moving missile = missiles[i]; if (missile.hitTestObject(target)) var explosion:Explosion = new Explosion(); addChild(explosion); explosion.x = missile.x; explosion.y = missile.y; removeChild(missile); missiles.splice(i, 1);//out of the Array if (missiles.length < 1)//only if no missiles are out at all missileOut = false; explosion= new Explosion(); addChild(explosion); explosion.x = target.x; explosion.y = target.y; explosion.scaleX = explosion.scaleY = 1.5; target.x = Math.random() * 600; else targetX = target.x - missile.x; targetY = target.y - missile.y; var rotation:int = Math.atan2(targetY, targetX) * 180 / Math.PI; if (Math.abs(rotation - missile.rotation) > 180) si (rotación> 0 y & missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 y rotación < 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 > piso) target.y = piso; targetVY = -18; sesión de función privada (evento: MouseEvent): void missile = new Missile (); missiles.push (missile); // en el Array addChild (missile); swapChildren (misil, cañón); // el misil saldrá por detrás del cañón missileOut = true; missile.x = cannon.x; missile.y = cannon.y; missile.rotation = cannon.rotation;
Ahora, cuando un objetivo es destruido, los misiles buscarán el próximo objetivo..
En este punto, todos los misiles persiguen al mismo objetivo. Para hacer que cada misil busque su propio objetivo, sería mejor crear una clase separada para los misiles en los que se determina el objetivo más cercano individualmente..
En este punto, ya entendió la idea principal de este tutorial, pero seamos sinceros, un enemigo no se moverá solo en función de la distancia que tenga usted o sus misiles. Puede utilizar otro indicador, como un punto de mira. Conviértalo en un clip de película y expórtelo a Actionscript.
Ahora será obvio para cualquiera a quién se dirige el objetivo. Sólo tiene que añadir una instancia de la Punto de mira Clip de pelicula.
var varilla privada: Punto de mira = nuevo Punto de cruz (); Función pública Main () addChild (cañón); cannon.x = 50; cannon.y = 380; addEventListener (Event.ENTER_FRAME, playGame); stage.addEventListener (MouseEvent.CLICK, disparar); para (var i: int = 0; i < numTargets; i++) target = new Target(); addChild(target); target.x = Math.random() * 600; target.y = Math.random() * 400; targets.push(target); addChild(crosshair);
Luego colóquelo en el objetivoposición como la última instrucción en el jugar un juego función.
targetVY + = gravedad; target.y + = targetVY; if (target.y> floor) target.y = floor; targetVY = -18; crosshair.x = target.x; punto de mira.y = target.y;
Obtendrás una cruz que marca la posición del objetivo más cercano.
¿Recuerdas lo que dije sobre los misiles? Lo mismo se aplica a los objetivos: se verán mejor en su propia clase con un conjunto de instrucciones propias. Este es solo un ejemplo rápido, pero en tu juego no recomiendo codificar todos los objetos en el Principal clase. Cuanto más complejo sea tu juego, menos cosas codificarás dentro de la Principal clase.
Los objetivos ya están en una matriz, que ya se está comprobando en un para bucle, así que voy a mover las instrucciones de rebote dentro de la para bucle, de modo que todos los objetivos, no importa cuántos, se moverán igual en todo momento.
función privada playGame (evento: Evento): void cannon.x = mouseX; cannon.y = mouseY; targetVY + = gravedad; para (var i: int = 0; i < targets.length; i++) targetX = targets[i].x - missile.x; targetY = targets[i].y - missile.y; var dist:int = Math.sqrt(targetX * targetX + targetY * targetY); if (i == 0 || dist < distance) distance = dist; target = targets[i]; targets[i].y += targetVY; if (targets[i].y > piso) objetivos [i] .y = piso; if (target.y> = floor) targetVY = -18; if (! missileOut) missile.x = cannon.x; missile.y = cannon.y; targetX = target.x - cannon.x; targetY = target.y - cannon.y; cannon.rotation = Math.atan2 (targetY, targetX) * 180 / Math.PI; else para (i = 0; i < missiles.length; i++) missile = missiles[i]; if (missile.hitTestObject(target)) var explosion:Explosion = new Explosion(); addChild(explosion); explosion.x = missile.x; explosion.y = missile.y; removeChild(missile); missiles.splice(i, 1); if (missiles.length < 1) missileOut = false; explosion= new Explosion(); addChild(explosion); explosion.x = target.x; explosion.y = target.y; explosion.scaleX = explosion.scaleY = 1.5; target.x = Math.random() * 600; else targetX = target.x - missile.x; targetY = target.y - missile.y; var rotation:int = Math.atan2(targetY, targetX) * 180 / Math.PI; if (Math.abs(rotation - missile.rotation) > 180) si (rotación> 0 y & missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 y rotación < 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; crosshair.x = target.x; crosshair.y = target.y;
Echar un vistazo:
Los misiles Homing, los misiles que buscan calor, ambos son un arma divertida y útil para tener en un juego de disparos o quizás algún otro tipo de aplicación. Este tutorial muestra un ejemplo de su uso y el algoritmo para hacerlo, pero para las mejores prácticas, se recomienda que tenga clases separadas para los misiles y los objetivos, a menos que su aplicación sea tan simple y breve como esta..
Espero que hayas encontrado este tutorial útil. Gracias por leer!