Dans le précédent tutoriel, nous avions un missile à tête chercheuse poursuivant après une seule cible. Ce tutoriel vous montrera comment convertir vos missiles à tête chercheuse en missiles à recherche de chaleur pour plusieurs cibles..
Si vous n'avez pas lu le premier tutoriel sur les missiles Homing, vous pouvez télécharger ce fichier .zip, qui contient le code source avec lequel nous allons commencer par ce tutoriel..
Jetons un coup d'œil au résultat final sur lequel nous allons travailler:
Le seul clip de la bibliothèque que nous devrons changer est le Canon, puisque nous allons le faire viser la cible la plus proche avant de tirer. Rappelez-vous que 0ш de rotation signifie pointant vers la droite, alors faites le graphique en conséquence.
Je vais réutiliser le targetX et cibleY variables pour calculer la distance entre le canon et la cible, donc je les déclare au début de la classe au lieu d’être à l’intérieur du playGame fonction, ainsi qu’une nouvelle variable pour stocker la distance calculée:
missile var privé: Missile = new Missile (); vitesse de la variable privée: int = 15; private var cannon: Cannon = new Cannon (); private var missileOut: Boolean = false; var var privé: int = 10; private var target: Target = new Target (); étage de var privé: int = 385; gravité privée var: nombre = 0,5; private var targetVY: Number = 0; // Vitesse verticale actuelle de la cible private var distance: int; var privé targetX: int; variable privée cibleY: int;
Maintenant le targetX et cibleY les variables seront déjà déclarées pour la playGame une fonction:
fonction privée playGame (event: Event): void if (missileOut) if (missile.hitTestObject (cible)) var explosion: Explosion = new Explosion (); addChild (explosion); explosion.x = missile.x; explosion.y = missile.y; enleverChild (missile); missileOut = false; else targetX = target.x - missile.x; cibleY = cible.y - missile.y; rotation de var: 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 > sol) cible.y = sol; targetVY = -18;
Auparavant dans le playGame fonction, nous voulions seulement savoir si le missile était prêt à prendre en charge sa rotation et son mouvement. Maintenant, nous devons d’abord savoir si le missile n’a pas encore été tiré et mettre à jour la rotation du canon..
fonction privée playGame (event: Event): 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 (cible)) explosion var: Explosion = nouvelle Explosion (); addChild (explosion); explosion.x = missile.x; explosion.y = missile.y; enleverChild (missile); missileOut = false; else targetX = target.x - missile.x; cibleY = cible.y - missile.y; rotation de var: 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 > sol) cible.y = sol; targetVY = -18;
Maintenant, le canon tourne par rapport à la position de la cible.
Le canon tourne, mais le missile continue à être tiré vers le haut. Remplacer la rotation codée en dur par la position actuelle du canon au moment où le missile est en cours de tir.
fonction privée shoot (événement: MouseEvent): void if (! missileOut) addChild (missile); swapChildren (missile, canon); // missile sortira de derrière canon missileOut = true; missile.x = cannon.x; missile.y = canon.y; missile.rotation = cannon.rotation;
Maintenant, le missile aura l’air de sortir du canon..
À l'heure actuelle, le missile à tête chercheuse a pour programme de viser une cible, mais si nous avions plus de cibles? Comment va-t-il décider lequel aller après?
Commençons par décider du nombre de cibles, puis plaçons chaque cible dans un tableau. Dans cet exemple, je vais dire qu'il y a 2 cibles, et je vais donner à chaque cible une position aléatoire sur l'écran.
private var target: cible; étage de var privé: int = 385; gravité privée var: nombre = 0,5; private var targetVY: Number = 0; // Vitesse verticale actuelle de la cible private var distance: int; var privé targetX: int; variable privée cibleY: int; var privé numTargets: int = 2; cibles var privées: Array = []; fonction publique Main () addChild (canon); canon.x = 50; canon.y = 380; addEventListener (Event.ENTER_FRAME, playGame); stage.addEventListener (MouseEvent.CLICK, shoot); pour (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);
Maintenant, nous avons plus d'une cible à l'écran.
Le missile ne reconnaît toujours que l'existence d'une cible. Nous allons résoudre ce problème.
Nous avons le missile cherchant le cible variable, alors vérifions la des cibles
Array et voir lequel est le plus proche. le cible variable sera référençant le plus proche au début de la playGame une fonction.
fonction privée playGame (event: Event): 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];
À ce stade, la cible la plus proche est la seule qui se déplace, mais le missile reconnaît l'existence des deux:
Vous avez peut-être remarqué que, même si le missile cherche la cible attendue, le canon est bloqué en direction de la même cible, peu importe si elle est plus proche ou plus éloignée que l'autre. La distance est définie par rapport à la position du missile, donc s'il n'y a pas de missile sur scène, nous devons mettre à jour sa position pour qu'elle corresponde à celle du canon afin qu'il sache toujours lequel est le plus proche..
fonction privée playGame (event: Event): 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;
Maintenant, le canon visera toujours la cible la plus proche.
Avant que le missile ne soit tiré, le canon pointe déjà vers la cible la plus proche et changera de direction s'il est rapproché de l'autre cible. Ajoutons quelques lignes pour positionner le canon avec le curseur de la souris.
fonction privée playGame (event: Event): void cannon.x = mouseX; cannon.y = mouseY;
Maintenant, vous pouvez déplacer le canon librement.
Pour rendre les choses plus dynamiques ici, je vais déplacer une cible après avoir été touché par un missile, ou le remplacer par un nouveau, et laisser un Explosion exemple à sa place.
if (missile.hitTestObject (cible)) explosion var: Explosion = nouvelle Explosion (); addChild (explosion); explosion.x = missile.x; explosion.y = missile.y; enleverChild (missile); missileOut = false; explosion = nouvelle explosion (); addChild (explosion); explosion.x = target.x; explosion.y = cible.y; explosion.scaleX = explosion.scaleY = 1,5; target.x = Math.random () * 600;
Voici ce que vous obtiendrez:
Nous avons créé plusieurs cibles, nous pouvons donc maintenant créer plusieurs missiles de la même manière. La différence ici est que tous les missiles doivent rester en mouvement jusqu'à leur frappe. Nous allons supprimer ceux qui ont déjà explosé. Nous devons donc modifier quelques lignes de notre code pour que cela fonctionne. Tout d'abord, nous aurons besoin d'un tableau pour les missiles.
missiles var privés: Array = [];
Ensuite, nous devons nous assurer que tous les missiles se comportent correctement:
fonction privée playGame (event: Event): void cannon.x = mouseX; cannon.y = mouseY; pour (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) 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 > sol) cible.y = sol; targetVY = -18; fonction privée shoot (événement: MouseEvent): void missile = new Missile (); missiles.push (missile); // dans le tableau addChild (missile); swapChildren (missile, canon); // missile sortira de derrière canon missileOut = true; missile.x = cannon.x; missile.y = canon.y; missile.rotation = cannon.rotation;
Maintenant, quand une cible est détruite, les missiles vont chercher la prochaine cible.
À ce stade, tous les missiles poursuivent la même cible. Pour que chaque missile cherche sa propre cible, il serait préférable de créer une classe distincte pour les missiles dans lesquels vous déterminez individuellement la cible la plus proche..
À ce stade, vous avez déjà compris l’idée principale de ce didacticiel, mais avouons-le, un ennemi ne se déplacera pas en fonction de sa distance par rapport à vous ou à vos missiles. Vous pouvez utiliser un autre indicateur, tel qu'un réticule. Faites-en un clip et exportez-le vers Actionscript.
Désormais, il sera évident pour quiconque que la cible est visée. Ajoutez simplement une instance de Réticule Clip du film.
réticule de var privé: Crosshair = new Crosshair (); fonction publique Main () addChild (canon); canon.x = 50; canon.y = 380; addEventListener (Event.ENTER_FRAME, playGame); stage.addEventListener (MouseEvent.CLICK, shoot); pour (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);
Puis placez-le sur le cibleLa position de la dernière instruction de la playGame une fonction.
targetVY + = gravité; target.y + = targetVY; if (target.y> floor) target.y = floor; targetVY = -18; réticule.x = cible.x; réticule.y = cible.y;
Vous obtiendrez un réticule indiquant la position de la cible la plus proche..
Tu te souviens de ce que j'ai dit à propos des missiles? Il en va de même pour les cibles: elles auront une meilleure apparence dans leur propre classe avec leurs propres instructions. Ceci est juste un exemple rapide, mais dans votre jeu, je ne recommande pas de coder tous les objets du Principale classe. Plus votre jeu est complexe, moins vous coderez de contenu dans le Principale classe.
Les cibles sont déjà dans un tableau, qui est déjà vérifié dans un pour boucle, donc je vais déplacer les instructions de rebond à l'intérieur de la pour boucle, de sorte que toutes les cibles, peu importe le nombre, bougeront toujours de la même manière.
fonction privée playGame (event: Event): void cannon.x = mouseX; cannon.y = mouseY; targetVY + = gravité; pour (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 > sol) cibles [i] .y = sol; if (target.y> = floor) targetVY = -18; si (! missileOut) missile.x = cannon.x; missile.y = canon.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++) 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) 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; crosshair.x = target.x; crosshair.y = target.y;
Regarde:
Les missiles Homing, les missiles thermo-chercheurs sont des armes amusantes et utiles à utiliser dans les jeux de tir ou dans d'autres types d'applications. Ce didacticiel présente un exemple d'utilisation et l'algorithme permettant de le créer. Toutefois, il est recommandé de définir des classes distinctes pour les missiles et les cibles, sauf si votre application est aussi simple et courte que celle-ci..
J'espère que vous avez trouvé ce tutoriel utile. Merci d'avoir lu!