Bli varmere Smart mål med varme-søkende missiler

I den forrige opplæringen hadde vi et homing missil jakt etter et enkelt mål. Denne opplæringen vil vise deg hvordan du konverterer dine homing-missiler til varmesøkende missiler for flere mål.

Hvis du ikke har lest den første Homing Missile-opplæringen, kan du laste ned denne .zip-filen, som inneholder kildekoden vi skal begynne med på denne opplæringen.


Endelig resultatforhåndsvisning

La oss se på det endelige resultatet vi vil jobbe for:


Trinn 1: Endre kanongrafikken

Den eneste filmklippet i biblioteket vi må endre er Kanon, siden vi vil gjøre det sikte mot nærmeste mål før du skyter. Husk at 0ш av rotasjon betyr å peke til høyre, så gjør grafikken tilsvarende.


Trinn 2: Erklære distansvariabler for kanonen

Jeg skal gjenbruke targetX og targetY variabler for å beregne avstanden til kanonen fra målet, så jeg vil deklare dem i begynnelsen av klassen i stedet for inne i spill funksjon, samt en ny variabel for å lagre den beregnede avstanden:

 private var missil: missil = ny missil (); privat varhastighet: int = 15; privat var kanon: kanon = ny kanon (); private var missileOut: Boolean = false; privat var lett: int = 10; privat varemål: Mål = nytt mål (); privat var gulv: int = 385; privat var tyngdekraften: tall = 0,5; private var targetVY: Number = 0; // Nåværende vertikal hastighet av målet private var avstand: int; private var targetX: int; private var targetY: int;

targetX og targetY variabler vil allerede bli erklært for spill funksjon:

 privat funksjon playGame (event: Event): void if (missileOut) if (missile.hitTestObject (target)) var eksplosjon: Explosion = new Explosion (); addChild (eksplosjon); eksplosjon.x = missil.x; eksplosjon.y = missil.y; removeChild (missil); missileOut = false;  else targetX = target.x - missile.x; targetY = target.y - missile.y; var rotasjon: int = Math.atan2 (targetY, targetX) * 180 / Math.PI; hvis (Math.abs (rotasjon - missil.rotasjon)> 180) hvis (rotasjon> 0 && missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotasjon < 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 > gulv) target.y = gulv; targetVY = -18; 

Trinn 3: Gjør kanonpunktet mot målet

Tidligere i spill funksjon vi var bare interessert i å vite om raketten var ute for å ta vare på rotasjon og bevegelse. Nå trenger vi først å vite om missilet ikke er blitt skutt, og oppdatere kanonens rotasjon.

 privat funksjon 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 eksplosjon: Eksplosjon = ny eksplosjon (); addChild (eksplosjon); eksplosjon.x = missil.x; eksplosjon.y = missil.y; removeChild (missil); missileOut = false;  else targetX = target.x - missile.x; targetY = target.y - missile.y; var rotasjon: int = Math.atan2 (targetY, targetX) * 180 / Math.PI; hvis (Math.abs (rotasjon - missil.rotasjon)> 180) hvis (rotasjon> 0 && missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotasjon < 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 > gulv) target.y = gulv; targetVY = -18; 

Nå kan kanonen rotere i forhold til målets posisjon.


Trinn 4: Match missilens rotasjon med kanonens.

Kanonen roterer, men missilen fortsetter å bli skutt oppover. Bytt den hardkodede rotasjonen med kanonens nåværende posisjon i det øyeblikket missilet blir skutt.

 privatfunksjonsskyting (event: MouseEvent): void if (! missileOut) addChild (missil); swapChildren (missil, kanon); // missil kommer ut bakfra kanon missileOut = true; missile.x = cannon.x; missile.y = cannon.y; missile.rotation = cannon.rotation; 

Nå vil raketten se ut som det faktisk kommer ut av kanonen.


Trinn 5: Mer enn ett mål

For øyeblikket er homing missilen et program for å gå etter et mål, men hva om vi har flere mål? Hvordan bestemmer den hvilken som skal gå etter?

Først, la oss bestemme hvor mange mål det vil være, så legger vi hvert mål i et Array. I dette eksemplet skal jeg si at det er 2 mål, og jeg vil gi hvert mål en tilfeldig posisjon på skjermen.

 privat varemål: Mål; privat var gulv: int = 385; privat var tyngdekraften: tall = 0,5; private var targetVY: Number = 0; // Nåværende vertikal hastighet av målet private var avstand: int; private var targetX: int; private var targetY: int; private var numTargets: int = 2; private var mål: Array = []; offentlig funksjon Main () addChild (kanon); kanon.x = 50; kanon.y = 380; addEventListener (Event.ENTER_FRAME, playGame); stage.addEventListener (MouseEvent.CLICK, shoot); for (var jeg: int = 0; i < numTargets; i++)  target = new Target(); addChild(target); target.x = Math.random() * 600; target.y = Math.random() * 400; targets.push(target);  

Nå har vi mer enn ett mål på skjermen.

Missilet anerkjenner fortsatt bare eksistensen av ett mål. Vi løser det neste.


Trinn 6: Søk nærmeste mål

Vi har raketten som søker mål variabel, så la oss sjekke mål Array og se hvilken som er nærmere. De mål variabel vil referere nærmest i begynnelsen av spill funksjon.

 privatfunksjon 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];  

På dette punktet er det nærmeste målet det eneste som beveger seg, men missilet erkjenner eksistensen av begge:


Trinn 7: Fix kanons mål

Du har kanskje lagt merke til at mens missilet søker det forventede målet, peker kanonen fast på samme mål, uansett om det er nærmere eller lenger enn det andre. Avstanden er satt i forhold til missilens posisjon, så hvis det ikke er noen missil på scenen, må vi oppdatere sin posisjon for å matche kanonen slik at den alltid vet hvilken som er nærmere.

 privatfunksjon 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; 

Nå kan kanonen alltid sikte mot nærmeste mål.


Trinn 8: Flytt kanonen

Før missilet blir skutt, peker kanonen allerede på nærmeste mål, og vil endre retning hvis den flyttes nærmere det andre målet. La oss legge til et par linjer for å plassere kanonen med musemarkøren.

 privatfunksjon playGame (event: Event): void cannon.x = mouseX; cannon.y = mouseY;

Nå kan du flytte kanonen fritt.


Trinn 9: Target Hit, Target Destroyed

For å gjøre ting mer dynamisk her, skal jeg flytte et mål etter å ha blitt rammet av et missil, eller erstatt den med en ny, og la en Eksplosjon eksempel på stedet.

 hvis (missile.hitTestObject (mål)) var eksplosjon: Eksplosjon = ny eksplosjon (); addChild (eksplosjon); eksplosjon.x = missil.x; eksplosjon.y = missil.y; removeChild (missil); missileOut = false; eksplosjon = ny eksplosjon (); addChild (eksplosjon); eksplosjon.x = target.x; eksplosjon.y = target.y; eksplosjon.scaleX = eksplosjon.scaleY = 1,5; target.x = Math.random () * 600; 

Dette er hva du får:


Trinn 10: Flere missiler

Vi har gjort flere mål, så nå kan vi lage flere raketter på samme måte. Forskjellen her er at alle missiler må fortsette å bevege seg til de treffer, og vi skal faktisk fjerne dem som allerede har eksplodert, så vi må endre noen få linjer av koden vår for at dette skal fungere. Først må vi ha en array for missiler.

 private varrakiler: Array = [];

Da må vi sørge for at alle missiler oppfører seg riktig:

 privatfunksjon playGame (event: Event): void cannon.x = mouseX; cannon.y = mouseY; for (var jeg: 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) hvis (rotasjon> 0 && missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotasjon < 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 > gulv) target.y = gulv; targetVY = -18;  privatfunksjonsskyting (event: MouseEvent): void missile = new Missile (); missiler.push (missil); // i Array addChild (missil); swapChildren (missil, kanon); // missil kommer ut bakfra kanon missileOut = true; missile.x = cannon.x; missile.y = cannon.y; missile.rotation = cannon.rotation; 

Nå når et mål er ødelagt, vil missilene søke det neste målet.

På dette punktet jager alle missiler etter det samme målet. For å få hvert missil å søke sitt eget mål, ville det være bedre å lage en egen klasse for missiler der du bestemmer nærmeste mål individuelt.


Trinn 11: Gjør en crosshair

På dette punktet har du allerede forstått hovedideen til denne opplæringen, men la oss innse det, en fiende vil ikke bevege seg avhengig av avstanden til deg eller dine missiler. Du kan bruke en annen indikator, for eksempel et tverrhår. Gjør det til en filmklipp og eksporter den til Actionscript.


Trinn 12: Bruk korset

Nå vil det være åpenbart for alle som målet er rettet mot. Bare legg til en forekomst av Crosshair Filmklipp.

 privat var crosshair: crosshair = new crosshair (); offentlig funksjon Main () addChild (kanon); kanon.x = 50; kanon.y = 380; addEventListener (Event.ENTER_FRAME, playGame); stage.addEventListener (MouseEvent.CLICK, shoot); for (var jeg: 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); 

Legg deretter den på målposisjon som siste instruksjon i spill funksjon.

 targetVY + = tyngdekraften; target.y + = targetVY; hvis (target.y> etasje) target.y = floor; targetVY = -18;  crosshair.x = target.x; crosshair.y = target.y; 

Du får krysshår som markerer nærmeste målposisjon.


Trinn 13: Flytt alle mål

Husk hva jeg sa om missiler? Det samme gjelder målene: De vil se bedre ut i sin egen klasse med et sett med egne instruksjoner. Dette er bare et raskt eksempel, men i spillet anbefaler jeg ikke å kode alle objekter i Hoved klasse. Jo mer komplisert spillet ditt er, desto mindre ting vil du kode inne i Hoved klasse.

Målene er allerede i et Array, som allerede blir sjekket i a til loop, så jeg vil flytte studsebeskrivelsene inni til sløyfe, slik at alle målene, uansett hvor mange, vil flytte det samme til enhver tid.

 privatfunksjon playGame (event: Event): void cannon.x = mouseX; cannon.y = mouseY; targetVY + = tyngdekraften; for (var jeg: 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 > gulv) mål [i] .y = gulv;  hvis (target.y> = gulv) targetVY = -18; hvis (! 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;  ellers 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) hvis (rotasjon> 0 && missile.rotation < 0) missile.rotation -= (360 - rotation + missile.rotation) / ease; else if (missile.rotation > 0 && rotasjon < 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; 

Ta en titt:


Konklusjon

Homing missiler, varme søken missiler, begge er et morsomt og nyttig våpen å ha rundt i et skytespill eller kanskje en annen type app. Denne opplæringen viser et eksempel på bruk og algoritmen for å gjøre det, men for beste praksis anbefales det at du har separate klasser for missiler og mål, med mindre appen din er så enkel og kort som denne.

Jeg håper du har funnet denne opplæringen nyttig. Takk for at du leste!