In de vorige tutorial hadden we een homing raket die achter een enkel doel aan zat. Deze zelfstudie laat je zien hoe je je vluchtende raketten omzet in hittezoekende raketten voor meerdere doelen.
Als je de eerste zelfstudie over de zelfstudie niet hebt gelezen, kun je dit .zip-bestand downloaden, dat de broncode bevat waarmee we beginnen in deze zelfstudie..
Laten we eens kijken naar het eindresultaat waar we naartoe zullen werken:
De enige filmclip in de bibliotheek die we moeten wijzigen, is de Kanon, omdat we ervoor zorgen dat het op het dichtstbijzijnde doel gericht is voordat je schiet. Onthoud dat 0 van omwenteling betekent naar rechts wijzen, dus maak de afbeelding overeenkomstig.
Ik ga het opnieuw gebruiken TargetX en targetY variabelen om de afstand van het kanon tot het doel te berekenen, dus ik verklaar ze aan het begin van de klas in plaats van in de spel spelen functie, evenals een nieuwe variabele om de berekende afstand op te slaan:
particuliere var-raket: Missile = new Missile (); privé var snelheid: int = 15; privé var-kanon: kanon = nieuw kanon (); private var missileOut: Boolean = false; privé var gemak: int = 10; privé var-doel: doel = nieuw doel (); privé var verdieping: int = 385; private var gravity: Number = 0.5; private var targetVY: Number = 0; // Huidige verticale snelheid van de privépriv afstand van het doel: int; private var targetX: int; private var targetY: int;
Nu de TargetX en targetY variabelen zijn al gedeclareerd voor de spel spelen functie:
private function playGame (event: Event): void if (missileOut) if (missile.hitTestObject (target)) var explosion: Explosion = new Explosion (); addChild (explosie); explosion.x = raket.x; explosion.y = missile.y; removeChild (raket); missileOut = false; else targetX = target.x - missile.x; targetY = target.y - missile.y; var rotatie: int = Math.atan2 (targetY, targetX) * 180 / Math.PI; if (Math.abs (rotation - raket.rotatie)> 180) if (rotatie> 0 && raket.rotatie < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotatie < 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 > vloer) target.y = verdieping; targetVY = -18;
Eerder in de spel spelen functie waren we alleen geïnteresseerd in het weten of de raket erop uit was om te zorgen voor de rotatie en beweging. Nu moeten we eerst weten of de raket nog niet is neergeschoten en de rotatie van het kanon bijwerken.
private function 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 (target)) var explosion: Explosion = new Explosion (); addChild (explosie); explosion.x = raket.x; explosion.y = missile.y; removeChild (raket); missileOut = false; else targetX = target.x - missile.x; targetY = target.y - missile.y; var rotatie: int = Math.atan2 (targetY, targetX) * 180 / Math.PI; if (Math.abs (rotation - raket.rotatie)> 180) if (rotatie> 0 && raket.rotatie < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotatie < 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 > vloer) target.y = verdieping; targetVY = -18;
Nu draait het kanon ten opzichte van de positie van het doelwit.
Het kanon draait, maar de raket wordt steeds naar boven geschoten. Vervang de hardgecodeerde rotatie door de huidige locatie van het kanon op het moment dat de raket wordt neergeschoten.
privéfunctie shoot (event: MouseEvent): void if (! missileOut) addChild (raket); swapChildren (raket, kanon); // raket zal van achter kanon komen missileOut = true; missile.x = cannon.x; missile.y = cannon.y; raket.rotatie = kanon.rotatie;
Nu zal de raket eruit zien alsof hij daadwerkelijk uit het kanon komt.
Op dit moment is de homing raket een programma dat achter één doel aan moet, maar wat als we meer doelen hebben? Hoe zal het beslissen welke te volgen?
Laten we eerst bepalen hoeveel doelen er zullen zijn, dan zullen we elk doel in een array plaatsen. In dit voorbeeld ga ik zeggen dat er 2 doelen zijn en ik geef elk doel een willekeurige positie op het scherm.
privé var-doel: doel; privé var verdieping: int = 385; private var gravity: Number = 0.5; private var targetVY: Number = 0; // Huidige verticale snelheid van de privépriv afstand van het doel: int; private var targetX: int; private var targetY: int; private var numTargets: int = 2; privé var-doelen: Array = []; public function Main () addChild (cannon); cannon.x = 50; cannon.y = 380; addEventListener (Event.ENTER_FRAME, playGame); stage.addEventListener (MouseEvent.CLICK, schieten); for (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);
Nu hebben we meer dan één doel op het scherm.
De raket erkent nog steeds slechts het bestaan van één doelwit. We zullen het volgende oplossen.
We hebben de raket op zoek naar de doelwit variabele, dus laten we de doelen
Matrix en zie welke dichterbij is. De doelwit variabele verwijst naar het dichtst bij het begin van de spel spelen functie.
private function 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];
Op dit punt is het dichtstbijzijnde doelwit de enige die beweegt, maar de raket erkent het bestaan van beide:
Je hebt misschien gemerkt dat terwijl de raket naar het verwachte doel zoekt, het kanon vastzit en naar hetzelfde doelwit wijst, ongeacht of het dichterbij of verder weg is dan het andere. De afstand wordt ingesteld in verhouding tot de positie van de raket, dus als er geen raket op het podium is, moeten we zijn positie bijwerken zodat deze overeenkomt met de kanonnen zodat altijd weet welke dichterbij is.
private function 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;
Nu zal het kanon altijd op het dichtstbijzijnde doel richten.
Voordat de raket wordt neergeschoten, wijst het kanon al naar het dichtstbijzijnde doelwit en zal het van richting veranderen als het dichter bij het andere doelwit komt. Laten we een paar regels toevoegen om het kanon met de muisaanwijzer te positioneren.
private function playGame (event: Event): void cannon.x = mouseX; cannon.y = mouseY;
Nu kun je het kanon vrij bewegen.
Om dingen hier dynamischer te maken, ga ik een doelwit verplaatsen nadat het door een raket is geraakt, of vervang deze door een nieuwe, en verlaat een Explosie bijvoorbeeld op zijn plaats.
if (missile.hitTestObject (target)) var explosion: Explosion = new Explosion (); addChild (explosie); explosion.x = raket.x; explosion.y = missile.y; removeChild (raket); missileOut = false; explosie = nieuwe explosie (); addChild (explosie); explosion.x = target.x; explosion.y = target.y; explosion.scaleX = explosion.scaleY = 1.5; target.x = Math.random () * 600;
Dit is wat je krijgt:
We hebben meerdere doelen gemaakt, dus nu kunnen we meerdere raketten op dezelfde manier maken. Het verschil hier is dat alle raketten te allen tijde in beweging moeten blijven totdat ze raken, en we gaan die die al geëxplodeerd zijn verwijderen, dus we moeten enkele regels van onze code aanpassen om dit te laten werken. Ten eerste hebben we een array nodig voor de raketten.
particuliere var-raketten: Array = [];
Vervolgens moeten we ervoor zorgen dat alle raketten zich goed gedragen:
private function playGame (event: Event): void cannon.x = mouseX; cannon.y = mouseY; 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; 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 (rotatie> 0 && raket.rotatie < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotatie < 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 > vloer) target.y = verdieping; targetVY = -18; privéfunctie shoot (event: MouseEvent): void missile = new Missile (); missiles.push (raket); // in de array addChild (raket); swapChildren (raket, kanon); // raket zal van achter kanon komen missileOut = true; missile.x = cannon.x; missile.y = cannon.y; raket.rotatie = kanon.rotatie;
Wanneer een doelwit nu wordt vernietigd, zullen de raketten het volgende doelwit zoeken.
Op dit punt jagen alle raketten hetzelfde doel na. Om ervoor te zorgen dat elke raket zijn eigen doelwit zoekt, is het beter om een afzonderlijke klasse te maken voor de raketten waarin u het dichtstbijzijnde doel individueel bepaalt.
Op dit punt heb je het hoofdidee van deze tutorial al begrepen, maar laten we eerlijk zijn, een vijand zal niet bewegen alleen afhankelijk van de afstand tot jou of je raketten. U kunt een andere indicator gebruiken, zoals een draadkruis. Maak er een filmclip van en exporteer deze naar Actionscript.
Nu zal het voor iedereen duidelijk zijn naar welk doelwit wordt gestreefd. Voeg gewoon een exemplaar toe van de crosshair Filmclip.
private var crosshair: Crosshair = new Crosshair (); public function Main () addChild (cannon); cannon.x = 50; cannon.y = 380; addEventListener (Event.ENTER_FRAME, playGame); stage.addEventListener (MouseEvent.CLICK, schieten); for (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);
Plaats het dan op de doelwitpositie als de laatste instructie in de spel spelen functie.
targetVY + = zwaartekracht; target.y + = targetVY; if (target.y> floor) target.y = floor; targetVY = -18; crosshair.x = target.x; crosshair.y = target.y;
U krijgt een vizier dat de positie van het dichtstbijzijnde doelwit markeert.
Weet je nog wat ik zei over de raketten? Hetzelfde geldt voor de doelen: ze zien er in hun eigen klas beter uit met een eigen reeks instructies. Dit is slechts een kort voorbeeld, maar in je spel raad ik je aan om alle objecten in de game niet te coderen Hoofd klasse. Hoe complexer je spel is, hoe minder dingen je in de code zult coderen Hoofd klasse.
De doelen bevinden zich al in een array, die al in a wordt gecontroleerd voor loop, dus ik verplaats de stuiterende instructies in de voor loop, zodat alle doelen, ongeacht het aantal, op elk moment hetzelfde bewegen.
private function playGame (event: Event): void cannon.x = mouseX; cannon.y = mouseY; targetVY + = zwaartekracht; 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]; targets[i].y += targetVY; if (targets[i].y > vloer) doelen [i] .y = vloer; 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 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 (rotatie> 0 && raket.rotatie < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotatie < 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;
Kijk eens:
Homingraketten, hittezoekende raketten, beide zijn een leuk en nuttig wapen om rond te hebben in een schietspel of misschien een ander type app. Deze tutorial toont een voorbeeld van het gebruik en het algoritme om het te maken, maar voor best practices is het aanbevolen dat je aparte klassen hebt voor de raketten en de doelen, tenzij je app zo simpel en kort is als deze.
Ik hoop dat je deze tutorial nuttig hebt gevonden. Bedankt voor het lezen!