I den tidigare handledningen hade vi en homing missil jagar efter ett enda mål. Denna handledning visar dig hur du konverterar dina homing-missiler till värmsökande missiler för flera mål.
Om du inte har läst den första Homing Missile-handledningen kan du hämta den här .zip-filen, som innehåller källkoden vi börjar med i denna handledning.
Låt oss ta en titt på det slutliga resultatet vi ska arbeta för:
Den enda filmklippet i biblioteket vi behöver ändra är Kanon, eftersom vi kommer att rikta oss mot det närmaste målet innan vi skjuter. Kom ihåg att 0ш av rotation betyder att peka åt höger, så gör grafiken i enlighet med detta.
Jag ska återanvända targetX och targetY variabler för att beräkna avståndet från kanonen från målet, så jag förklarar dem i början av klassen istället för inuti spela spel funktion, samt en ny variabel för att lagra det beräknade avståndet:
Privat Var Missil: Missil = Ny Missil (); privat varhastighet: int = 15; privat var kanon: kanon = ny kanon (); private var missileOut: Boolean = false; privat var lätt: int = 10; privat var mål: Target = new Target (); privat varv: int = 385; privat var gravitation: Nummer = 0,5; private var targetVY: Number = 0; // Aktuell vertikal hastighet för målet privat var avstånd: int; privat var targetX: int; privat var targetY: int;
Nu den targetX och targetY variabler kommer redan att deklareras för spela spel fungera:
privat funktion playGame (händelse: händelse): void if (missileOut) if (missile.hitTestObject (target)) var explosion: Explosion = new Explosion (); addChild (explosion); explosion.x = missile.x; explosion.y = missile.y; removeChild (missil); missileOut = false; else targetX = target.x - missile.x; targetY = target.y - missile.y; var rotation: int = Math.atan2 (targetY, targetX) * 180 / Math.PI; om (Math.abs (rotation - missil.rotation)> 180) om (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 > våning) target.y = floor; targetVY = -18;
Tidigare i spela spel funktion vi var bara intresserade av att veta om missilen var ute för att ta hand om sin rotation och rörelse. Nu behöver vi först veta om missilen ännu inte har skott och uppdatera kanonens rotation.
privat funktion playGame (händelse: händelse): void if (! missileOut) targetX = target.x - cannon.x; targetY = target.y - cannon.y; cannon.rotation = Math.atan2 (targetY, targetX) * 180 / Math.PI; annat om (missile.hitTestObject (mål)) var explosion: Explosion = new Explosion (); addChild (explosion); explosion.x = missile.x; explosion.y = missile.y; removeChild (missil); missileOut = false; else targetX = target.x - missile.x; targetY = target.y - missile.y; var rotation: int = Math.atan2 (targetY, targetX) * 180 / Math.PI; om (Math.abs (rotation - missil.rotation)> 180) om (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 > våning) target.y = floor; targetVY = -18;
Nu kan kanonen rotera i förhållande till målets position.
Kanonen roterar, men missilen fortsätter att skjutas uppåt. Byt ut den hårdkodade rotationen med kanonens aktuella plats när missilen skjuts.
privat funktionsskott (händelse: MouseEvent): void if (! missileOut) addChild (missil); swapChildren (missil, kanon); // missil kommer ut från bakom kanon missileOut = true; missil.x = kanon.x; missile.y = cannon.y; missile.rotation = cannon.rotation;
Nu kommer missilen att se ut som om den faktiskt kommer ut ur kanonen.
Just nu är homing missilen ett program för att gå efter ett mål, men om vi har fler mål? Hur bestämmer den vilken man ska gå efter?
Låt oss först bestämma hur många mål som kommer att finnas, då lägger vi varje mål i en Array. I det här exemplet kommer jag att säga att det finns 2 mål, och jag ger varje mål ett slumpmässigt läge på skärmen.
privat var mål: Target; privat varv: int = 385; privat var gravitation: Nummer = 0,5; private var targetVY: Number = 0; // Aktuell vertikal hastighet för målet privat var avstånd: int; privat var targetX: int; privat var targetY: int; private var numTargets: int = 2; private var targets: Array = []; allmän funktion Main () addChild (kanon); kanon.x = 50; kanon.y = 380; addEventListener (Event.ENTER_FRAME, playGame); stage.addEventListener (MouseEvent.CLICK, skjuta); för (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 har vi mer än ett mål på skärmen.
Missilen bekräftar fortfarande existensen av ett mål. Vi fixar det nästa.
Vi har missilen som söker mål variabel, så låt oss kolla mål
Array och se vilken som är närmare. De mål variabel kommer att referera närmast i början av spela spel fungera.
privat funktion playGame (händelse: händelse): 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];
Vid denna punkt är det närmaste målet det enda som rör sig, men missilen erkänner förekomsten av båda:
Du kanske har märkt att medan missilen söker det förväntade målet, pekar kanonen fast vid samma mål, oavsett om det är närmare eller längre än det andra. Avståndet är inställt i förhållande till missilens position, så om det inte finns någon missil på scenen behöver vi uppdatera sin position för att matcha kanonen så att den alltid vet vilken som är närmare.
privat funktion playGame (händelse: händelse): 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 kan kanonen alltid rikta sig till närmaste mål.
Innan missilen är skuten pekar kanonen redan på närmaste mål och kommer att ändra riktning om den flyttas närmare det andra målet. Låt oss lägga till ett par rader för att placera kanonen med muspekaren.
privat funktion playGame (händelse: händelse): void cannon.x = mouseX; kanon.y = mouseY;
Nu kan du flytta kanonen fritt.
För att göra saker mer dynamiska här kommer jag att flytta ett mål efter att ha blivit träffad av en missil eller ersätt det med en ny, och lämna en Explosion exempel på platsen.
om (missile.hitTestObject (mål)) var explosion: Explosion = new Explosion (); addChild (explosion); explosion.x = missile.x; explosion.y = missile.y; removeChild (missil); missileOut = false; explosion = ny explosion (); addChild (explosion); explosion.x = target.x; explosion.y = target.y; explosion.scaleX = explosion.scaleY = 1.5; target.x = Math.random () * 600;
Så här får du:
Vi har gjort flera mål, så nu kan vi göra flera missiler på samma sätt. Skillnaden här är att alla missiler måste fortsätta att flytta hela tiden tills de träffar, och vi kommer faktiskt att ta bort de som redan har exploderat, så vi måste ändra några rader i vår kod för att detta ska fungera. Först behöver vi en array för missilerna.
private var missiler: Array = [];
Då måste vi se till att alla missiler beter sig korrekt:
privat funktion playGame (händelse: händelse): void cannon.x = mouseX; kanon.y = mouseY; för (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) om (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 > våning) target.y = floor; targetVY = -18; privatfunktionsskott (händelse: MouseEvent): void missile = new Missile (); missiler.push (missil); // i Array addChild (missil); swapChildren (missil, kanon); // missil kommer ut från bakom kanon missileOut = true; missil.x = kanon.x; missile.y = cannon.y; missile.rotation = cannon.rotation;
Nu när ett mål förstörs, kommer missilerna att söka nästa mål.
Vid denna tidpunkt jagar alla missiler efter samma mål. För att få varje missil att söka sitt eget mål är det bättre att skapa en separat klass för missilerna där du bestämmer närmaste mål individuellt.
Vid denna tidpunkt har du redan förstått huvudtanken i denna handledning, men låt oss möta det, en fiende kommer inte att flytta beroende bara på avståndet till dig eller dina missiler. Du kan använda en annan indikator, till exempel en crosshair. Gör det till en filmklipp och exportera den till Actionscript.
Nu kommer det att vara uppenbart för alla vilka mål som riktas mot. Lägg bara till en instans av hårkors Filmklipp.
privat var crosshair: Crosshair = new Crosshair (); allmän funktion Main () addChild (kanon); kanon.x = 50; kanon.y = 380; addEventListener (Event.ENTER_FRAME, playGame); stage.addEventListener (MouseEvent.CLICK, skjuta); för (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);
Placera sedan den på måls position som den sista instruktionen i spela spel fungera.
targetVY + = gravitation; target.y + = targetVY; om (target.y> våning) target.y = floor; targetVY = -18; crosshair.x = target.x; crosshair.y = target.y;
Du får en crosshair som markerar närmaste målposition.
Kom ihåg vad jag sa om missilerna? Detsamma gäller målen: De kommer att se bättre ut i sin egen klass med en uppsättning egna instruktioner. Detta är bara ett snabbt exempel, men i ditt spel rekommenderar jag inte att du kodar alla objekt i Huvudsaklig klass. Ju mer komplexa ditt spel är desto mindre saker du kodar inuti Huvudsaklig klass.
Målen är redan i en Array, som redan kontrolleras i en för slinga, så jag flyttar studsningsinstruktionerna inuti för slinga, så att alla mål, oavsett hur många, kommer att flytta på samma sätt hela tiden.
privat funktion playGame (händelse: händelse): void cannon.x = mouseX; kanon.y = mouseY; targetVY + = gravitation; för (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 > golv) mål [i] .y = golv; om (target.y> = floor) targetVY = -18; om (! 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; annat för (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) om (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;
Ta en titt:
Homing missiler, värmsökande missiler, båda är ett roligt och användbart vapen att ha runt i ett skjutspel eller kanske någon annan typ av app. Denna handledning visar ett exempel på dess användning och algoritmen för att göra det, men för bästa praxis rekommenderas att du har separata klasser för missilerna och målen, såvida inte din app är så enkel och kort som den här.
Jag hoppas att du har hittat denna handledning användbar. Tack för att du läser!