Lag et Tower Defense Game i AS3 Enemies og Basic AI

Hei Flash-utviklere, velkommen til den andre delen av min Tower Defense Game-opplæring. I første del utviklet vi den grunnleggende mekanismen for å skape tårn og få dem til å skyte mot museklikkpunktet. Men det er ikke det tårnene er for! I denne delen vil vi utvide spillet for å inkludere fiender, grunnleggende kunstig intelligens (AI) i tårn og noen flere spillelementer. Er du klar?


Endelig resultatforhåndsvisning

Dette er spillet vi skal lage i denne opplæringen:

Klikk på oransje sirkler for å plassere tårn. De røde sirkler er fiender, og tallet på hver representerer sine treffpunkter.


Trinn 1: Oppsummering

I den forrige opplæringen utviklet vi et spill som hadde plassholdere for tårnene. Vi kunne distribuere tårnene ved å klikke på disse plassholderne, og tårnene rettet mot musepekeren og skuddkulene mot det punktet hvor brukeren klikket.

Vi avsluttet med a Hoved klasse som hadde spillsløyfen og spilllogikken. Bortsett fra det hadde vi turret klasse som ikke hadde noe mye bortsett fra Oppdater funksjon som gjorde tårnet rotere.


Trinn 2: En egen kuleklasse

Vi har tidligere opprettet kulene i Hoved klasse og vedlagt en ENTER_FRAME lytter til å flytte den. Kulen hadde ikke nok egenskaper tidligere til å vurdere det å lage en egen klasse. Men i et slikt spill kan kuler ha mange varianter som fart, skade og så videre, så det er en god ide å trekke ut kulekoden og innkapslere den i en separat Kule klasse. La oss gjøre det.

Opprett en ny klasse som heter Kule, utvide Sprite klasse. Grunnkoden for denne klassen skal være:

 pakke import flash.display.Sprite; offentlig klasse Bullet utvider Sprite offentlig funksjon Bullet () 

Deretter setter vi koden for å tegne kuleteksten, hentet fra Hoved, i Kule. Som vi gjorde med turret klasse, oppretter vi en funksjon som heter tegne i Kule klasse:

 privat funksjonstegn (): void var g: Graphics = this.graphics; g.beginFill (0xEEEEEE); g.drawCircle (0, 0, 5); g.endFill (); 

Og vi kaller denne funksjonen fra Kule konstruktør:

 offentlig funksjon Bullet () draw (); 

Nå legger vi til noen egenskaper til kulen. Legg til fire variabler: hastighet, speed_x, speed_y og skader, før Kule konstruktør:

 privat var hastighet: tall; privat var speed_x: Number; privat var speed_y: tall; offentlig var skade: int;

Hva er disse variablene for?

  • hastighet: Denne variabelen lagrer kulehastigheten.
  • speed_x og speed_y: Disse lagrer henholdsvis x- og y-komponentene av hastigheten, slik at beregningen av å bryte hastigheten til komponentene ikke må gjøres igjen og igjen.
  • skader: Dette er mengden skade kulen kan gjøre mot en fiende. Vi holder denne variabelen offentlig, da vi vil kreve dette i vår spillsløyfe i Hoved klasse.

Vi initialiserer disse variablene i konstruktøren. Oppdater din Kule konstruktør:

 offentlig funksjon Bullet (vinkel: tall) speed = 5; skade = 1; speed_x = Math.cos (vinkel * Math.PI / 180) * hastighet; speed_y = Math.sin (vinkel * Math.PI / 180) * hastighet; tegne(); 

Legg merke til vinkel variabel vi mottar i konstruktøren. Dette er retningen (i grader) der kulen vil bevege seg. Vi bryter bare hastighet inn i sine x og y komponenter og lagre dem for fremtidig bruk.

Det siste som gjenstår i Kule klassen er å ha en Oppdater funksjon som vil bli kalt fra spillsløyfen for å oppdatere (flytte) kulen. Legg til følgende funksjon på slutten av Kule klasse:

 offentlig funksjon oppdatering (): void x + = speed_x; y + = speed_y; 

Bingo! Vi er ferdige med vår Kule klasse.


Trinn 3: Oppdatering av hovedklassen

Vi flyttet mye kulekode fra Hoved klasse for seg selv Kule klasse, så mye kode forblir ubrukt i Hoved og mye må oppdateres.

Først sletter du createBullet () og moveBullet () funksjoner. Fjern også bullet_speed variabel.

Deretter går du til skyte funksjonen og oppdatere den med følgende kode:

 privat funksjonsspor (e: MouseEvent): tomrom for hver (var turret: Turret i tårn) var new_bullet: Bullet = new Bullet (turret.rotation); new_bullet.x = turret.x + Math.cos (turret.rotation * Math.PI / 180) * 25; new_bullet.y = turret.y + Math.sin (turret.rotation * Math.PI / 180) * 25; addChild (new_bullet); 

Vi bruker ikke lenger createBullet funksjon for å skape kule, bruk heller Kule konstruktør og passere tårnet rotasjon til det som er retningen for kulens bevegelse, og så trenger vi ikke å lagre den i kulen rotasjon eiendom som vi gjorde tidligere. Også vi legger ikke noen lytter til kulen da kulen vil bli oppdatert fra spillsløyfen neste.


Trinn 4: Lagre Bullet References

Nå som vi trenger å oppdatere kulene fra spillsløyfen, trenger vi en referanse om at de skal lagres et sted. Løsningen er den samme som for tårnene: opprett en ny Array oppkalt kuler og skyv kulene på den som de er opprettet.

Først erklærer du en matrise like under tårn array-erklæring:

 privat var ghost_turret: Turret; private vartårn: Array = []; private var kuler: Array = [];

Nå for å fylle denne gruppen. Vi gjør det når vi lager en ny kule - så i skyte funksjon. Legg til følgende like før du legger til punktet:

 var new_bullet: Bullet = ny Bullet (turret.rotation); new_bullet.x = turret.x + Math.cos (turret.rotation * Math.PI / 180) * 25; new_bullet.y = turret.y + Math.sin (turret.rotation * Math.PI / 180) * 25; bullets.push (new_bullet); addChild (new_bullet);

Trinn 5: Oppdater kulene

Akkurat som hvordan vi oppdaterer tårnene i spillsløyfen, vil vi også oppdatere kulene. Men denne gangen, i stedet for å bruke a for hver loop, vi bruker en grunnleggende til sløyfe. Før dette må vi legge til to variabler til toppen av spillsløyfen, slik at vi vet hvilke variabler som brukes i spillsløyfen, og kan sette dem fri for søppelsamling.

 var turret: Turret; var bullet: Bullet;

Gå videre og legg til følgende kode i slutten av spillsløyfen:

 for (var jeg: int = kuler. lengde - 1; i> = 0; i--) bullet = kuler [i]; hvis (! bullet) fortsetter; bullet.update (); 

Her krysser vi over alle kulene på scenen hver ramme og ringer deres Oppdater funksjon som gjør at de beveger seg. Vær oppmerksom på at vi gjentar det kuler array i omvendt. Hvorfor? Vi ser dette fremover.

Nå som vi har a turret variabel deklarert utenfor allerede, trenger vi ikke å deklarere det igjen inne i for hver loop av tårn. Endre det til:

 for hver (turret i tårnene) turret.update (); 

Til slutt legger vi til grensekontrolltilstanden; Dette var tidligere i kulen ENTER_FRAME men nå sjekker vi det i spillsløyfen:

 hvis (bullet.x < 0 || bullet.x > stage.stageWidth || bullet.y < 0 || bullet.y > stage.stageHeight) bullets.splice (jeg, 1); bullet.parent.removeChild (bullet); Fortsette; 

Vi kontrollerer om kulen er ute av scenens grense, og hvis så fjerner vi først sin referanse fra kuler array ved hjelp av skjøt funksjon, og fjern deretter kulen fra scenen og fortsett med neste iterasjon. Slik ser spillløkken ut:

 privat funksjon gameLoop (e: Event): void var turret: Turret; var bullet: Bullet; for hver (turret i tårnene) turret.update ();  for (var i: int = kuler.length - 1; i> = 0; i--) bullet = kuler [i]; hvis (! bullet) fortsetter; bullet.update (); 

Hvis du nå kjører spillet, bør du ha samme funksjonalitet som i del 1, med kode som er mye mer ren og organisert.


Trinn 6: Presentere fienden

Nå legger vi til et av de viktigste elementene i spillet: fienden. Første ting er å opprette en ny klasse som heter Fiende utvide Sprite klasse:

 pakke import flash.display.Sprite; offentlig klasse Enemy utvider Sprite offentlig funksjon Enemy () 

Nå legger vi noen egenskaper til klassen. Legg til dem før din Fiende konstruktør:

 privat var speed_x: Number; privat var speed_y: tall;

Vi initialiserer disse variablene i Fiende konstruktør:

 offentlig funksjon Enemy () speed_x = -1.5; speed_y = 0; 

Deretter lager vi tegne og Oppdater funksjoner for Fiende klasse. Disse er svært lik dem fra Kule. Legg til følgende kode:

 privat funksjonstegn (): void var g: Graphics = this.graphics; g.beginFill (0xff3333); g.drawCircle (0, 0, 15); g.endFill ();  offentlig funksjon oppdatering (): void x + = speed_x; y + = speed_y; 

Trinn 7: Timing av spillhendelsene

I vårt spill må vi ha mange hendelser som finner sted på bestemte tidspunkter eller gjentatte ganger med bestemte intervaller. Slike timing kan oppnås ved bruk av en tidsteller. Telleren er bare en variabel som økes etter hvert som tiden går i spillet. Det viktige her er når og av hvor mye beløp som skal øke telleren. Det er to måter der timing generelt er gjort i spill: Tidsbasert og Rammebasert.

Forskjellen er at enheten av trinn i tidsbasert spill er basert på sanntid (det vil si antall millisekunder som er gått), men i et rammebasert spill er stedsenheten basert på rammeenheter (dvs. antall rammer som er gått).

For vårt spill skal vi bruke en rammebasert teller. Vi har en teller som vi øker med en i spillsløyfen, som kjører hver ramme, og det vil i utgangspunktet gi oss antall rammer som har gått siden spillet startet. Gå videre og erklære en variabel etter de andre variabeldeklarasjonene i Hoved klasse:

 privat var ghost_turret: Turret; private vartårn: Array = []; private var kuler: Array = []; privat var global_time: tall = 0;

Vi øker denne variabelen i spillsløyfen øverst:

 global_time ++;

Nå basert på denne telleren kan vi gjøre ting som å skape fiender, som vi vil gjøre neste.


Trinn 8: La oss lage noen fiendene

Det vi vil gjøre nå, er å lage fiender på banen etter hvert to sekunder. Men vi har å gjøre med rammer her, husk? Så etter hvor mange rammer skal vi skape fiender? Vel, vårt spill kjører på 30 FPS, og øker dermed global_time teller 30 ganger hvert sekund. En enkel beregning forteller oss at 3 sekunder = 90 rammer.

På slutten av spillsløyfen legger du til følgende hvis blokkere:

 hvis (global_time% 90 == 0) 

Hva er den tilstanden om? Vi bruker modulo (%) operatøren, som gir resten av en divisjon - så global_time% 90 gir oss resten når global_time er delt med 90. Vi sjekker om resten er 0, som dette vil bare være tilfelle når global_time er et flertall av 90 - det vil si at tilstanden kommer tilbake ekte når global_time er lik 0, 90, 180 og så videre ... På denne måten oppnår vi en utløser hver 90 eller 3 sekunder.

Før vi lager fienden, erklærer vi en annen gruppe som heter fiender like under tårn og kuler array. Dette vil bli brukt til å lagre referanser til fiender på scenen.

 privat var ghost_turret: Turret; private vartårn: Array = []; private var kuler: Array = []; private var fiender: Array = []; privat var global_time: tall = 0;

Erklære også en fiende variabel øverst på spillsløyfen:

 global_time ++; var turret: Turret; var bullet: Bullet; var fiende: Fiende;

Til slutt legg til følgende kode inne i hvis blokkere vi opprettet tidligere:

 fiende = ny fiende (); fiende.x = 410; enemy.y = 30 + Math.random () * 370; enemies.push (fiende); addChild (fiende);

Her lager vi en ny fiende, plasserer den tilfeldig på høyre side av scenen, skyver den i fiender array og legg det til scenen.


Trinn 9: Oppdatere fiendene

Akkurat som vi oppdaterer kulene i spillsløyfen, oppdaterer vi fiender. Sett følgende kode under tårnet for hver løkke:

 for (var j: int = enemies.length - 1; j> = 0; j--) fiende = fiender [j]; enemy.update (); hvis (fiende.x < 0)  enemies.splice(j, 1); enemy.parent.removeChild(enemy); continue;  

På samme måte som vi gjorde en grensekontroll for kuler, sjekker vi også på fiender. Men for fiender kontrollerer vi bare om de gikk ut av venstre side av scenen, da de bare beveger seg rett til venstre. Du bør se fiender kommer fra høyre hvis du kjører spillet nå.


Trinn 10: Gi fiendene litt helse

Hver fiende har noe liv / helse, og det vil også vår. Vi vil også vise den gjenværende helsen på fiender. Kan deklarere noen variabler i Fiende klasse for helse ting:

 privat var health_txt: TextField; privat var helse: int; privat var speed_x: Number; privat var speed_y: tall;

Vi initialiserer Helse variabel i konstruktøren neste. Legg til følgende i Fiende konstruktør:

 helse = 2;

Nå initialiserer vi hivtekstvariabelen til å vise på sentrum av fienden. Vi gjør det i tegne funksjon:

 health_txt = nytt TextField (); health_txt.height = 20; health_txt.width = 15; health_txt.textColor = 0xffffff; health_txt.x = -5; health_txt.y = -8; health_txt.text = helse + ""; addChild (health_txt);

Alt vi gjør er å lage en ny Tekstfelt, sett fargen sin, plasser den og sett teksten til gjeldende verdi av Helse Til slutt legger vi til en funksjon for å oppdatere fiendens helse:

 offentlig funksjon oppdateringHelse (mengde: int): int helse + = mengde; health_txt.text = helse + ""; returnere helse; 

Funksjonen aksepterer et heltall for å legge til helsen, oppdaterer helseteksten, og returnerer den endelige helsen. Vi kaller denne funksjonen fra vår spillsløyfe for å oppdatere hver fiendens helse og oppdage om den fortsatt er i live.


Trinn 11: Skyt mot fiendene.

Først kan vi endre vår skyte fungere litt. Erstatt eksisterende skyte fungere med følgende:

 privat funksjon skyte (turret: Turret, fiende: Enemy): void varvinkel: Nummer = Math.atan2 (fiende.y - turret.y, fiende.x - turret.x) / Math.PI * 180; turret.rotasjon = vinkel; var new_bullet: Bullet = ny Bullet (vinkel); new_bullet.x = turret.x + Math.cos (turret.rotation * Math.PI / 180) * 25; new_bullet.y = turret.y + Math.sin (turret.rotation * Math.PI / 180) * 25; bullets.push (new_bullet); addChild (new_bullet); 

De skyte funksjonen aksepterer nå to parametere. Den første er en referanse til et tårn som vil gjøre skytingen; den andre er en referanse til en fiende mot hvilken den vil skyte.

Den nye koden her ligner den som er til stede i turret klassens Oppdater funksjon, men i stedet for musens posisjon bruker vi nå fiendens cordinates. Så nå kan du fjerne all koden fra Oppdater funksjon av turret klasse.

Nå hvordan får man tårnene til å skyte mot fiender? Vel logikken er enkel for vårt spill. Vi gjør alle tårnene skyte den første fienden i fiender array. Hva? La oss sette noen kode og deretter prøve å forstå. Legg opp følgende linjer i slutten av for hver sløyfe som brukes til å oppdatere tårnene:

 for hver (turret i tårnene) turret.update (); for hver (fiende i fiender) skyte (tårn, fiende); gå i stykker; 

For hver turret oppdaterer vi nå den, og deretter er det igjen fiender array, skyte den første fienden i gruppen og bryte fra løkken. Så i det vesentlige skyter hvert tårn den tidligste opprettede fienden som den alltid er i begynnelsen av matrisen. Prøv å kjøre spillet og du bør se tårn som skyter fiender.

Men vent, hva er den kule strømmen flyter? Ser ut som de skyter for fort. Kan se hvorfor.


Trinn 12: Tårn skyter for fort

Som vi vet går spillsløyfen hver ramme, det vil si 30 ganger i sekundet, slik at skytingserklæringen vi legger til i forrige trinn, blir kalt på hastigheten på vår spillsløyfe, og dermed ser vi en strøm av kuler som flyter. Ser ut som vi trenger en tidsplanmekanisme inne i tårnene også. Bytt til turret klasse og legg til følgende kode:

 privat var local_time: tall = 0; privat var reload_time: int;
  1. lokal tid: Våre teller er kalt lokal tid i motsetning til global_time i Hoved klasse. Dette er av to grunner: først fordi denne variabelen er lokal til turret klasse; For det andre fordi det ikke alltid går frem som vår global_time variabel - den vil nullstille mange ganger i løpet av spillet.
  2. reload_time: Dette er tiden som tårnet trenger for å laste på igjen etter å ha tatt et kule. I utgangspunktet er det tidsforskjellen mellom to punktskudd med et tårn. Husk at alle tidsenheter i vårt spill er i form av rammer.

Øke lokal tid variabel i Oppdater funksjon og initialiser reload_time i konstruktøren:

 offentlig funksjon oppdatering (): void local_time ++; 
 offentlig funksjon Turret () reload_time = 30; tegne(); 

Deretter legger du til følgende to funksjoner på slutten av turret klasse:

 offentlig funksjon erReady (): Boolean return local_time> reload_time;  tilbakestilling av offentlig funksjon (): void local_time = 0; 

er klar returnerer sant bare når gjeldende lokal tid er større enn reload_time, det vil si når tårnet har lastet på nytt. Og tilbakestille funksjonen tilbakestilles ganske enkelt lokal tid variabel, for å starte den på nytt.

Nå tilbake i Hoved klassen, endre skytekoden i spillsløyfen vi la til i forrige trinn til følgende:

 for hver (turret i tårnene) turret.update (); hvis (! turret.isReady ()) fortsetter; for hver (fiende i fiender) skyte (tårn, fiende); turret.reset (); gå i stykker; 

Så hvis tårnet ikke er klart nå (er klar() avkastning falsk), fortsetter vi med neste iterasjon av turretløkken. Du vil se at tårnene brenner i et intervall på 30 bilder eller 1 sekund nå. Kul!


Trinn 13: Begrens tårnet

Fortsatt noe ikke riktig. Tårnene skyter mot fiender, uavhengig av avstanden mellom dem. Det som mangler her er område av et tårn. Hvert tårn bør ha sitt eget utvalg innenfor som det kan skyte en fiende. Legg til en annen variabel til turret klassen kalles område og sett den til 120 inne i konstruktøren:

 privat var reload_time: int; privat var local_time: tall = 0; privat var utvalg: int;
 offentlig funksjon Turret () reload_time = 30; område = 120; tegne(); 

Legg også til en funksjon som heter canShoot på slutten av klassen:

 offentlig funksjon canShoot (fiende: fiende): boolsk var dx: tall = fiende.x - x; var dy: Nummer = fiende.y - y; hvis (Math.sqrt (dx * dx + dy * dy) <= range) return true; else return false; 

Hver tårn kan bare skyte en fiende når den oppfyller visse kriterier - for eksempel kan du la turret skyte bare røde fiender med mindre enn halvparten av livet og ikke mer enn 30 px unna. All slik logikk for å avgjøre om tårnet er i stand til å skyte en fiende eller ikke, vil gå inn i canShoot funksjon, som returnerer ekte eller falsk i henhold til logikken.

Vår logikk er enkel. Hvis fienden er innenfor rekkevidde retur ekte; ellers returnere falsk. Så når avstanden mellom tårnet og fienden (Math.sqrt (dx * dx + dy * dy)) er mindre enn eller lik område, det kommer tilbake ekte. Litt mer endring i skyteseksjonen av spillsløyfen:

 for hver (turret i tårnene) turret.update (); hvis (! turret.isReady ()) fortsetter; for hver (fiende i fiender) hvis (turret.canShoot (fiende)) skyte (tårn, fiende); turret.reset (); gå i stykker; 

Nå bare hvis fienden er innenfor tårnet, vil tårnet skyte.


Trinn 14: Kollisjonsdeteksjon

En svært viktig del av hvert spill er kollisjonsdeteksjonen. I vårt spill kollisjonskontroll gjøres mellom kuler og fiender. Vi legger til kollisjonsdeteksjonskoden inne i for hver loop som oppdaterer kulene i spillsløyfen.

Logikken er enkel. For hver kule vi krysser fiender array og sjekk om det er en kollisjon mellom dem. I så fall fjerner vi kulen, oppdaterer fiendens helse og bryter ut av løkken for å sjekke andre fiender. La oss legge til en kode:

 for (i = bullets.length - 1; i> = 0; i--) bullet = bullets [i]; // Hvis kulen ikke er definert, fortsett med neste iterasjon hvis (! bullet) fortsetter; bullet.update (); hvis (bullet.x < 0 || bullet.x > stage.stageWidth || bullet.y < 0 || bullet.y > stage.stageHeight) bullets.splice (jeg, 1); bullet.parent.removeChild (bullet); Fortsette;  for (var k: int = enemies.length - 1; k> = 0; k--) fiende = fiender [k]; hvis (bullet.hitTestObject (fiende)) bullets.splice (jeg, 1); bullet.parent.removeChild (bullet); hvis (fiende.updateHealth (-1) == 0) enemies.splice (k, 1); enemy.parent.removeChild (fiende);  gå i stykker; 

Vi bruker ActionScript hitTestObject funksjon for å sjekke for kollisjon mellom kulen og fienden. Hvis kollisjonen oppstår, blir kula fjernet på samme måte som når den forlater scenen. Fiendens helse blir da oppdatert ved hjelp av updateHealth metode, som kule's skader eiendommen er bestått. Hvis updateHealth funksjonen returnerer et helt tall mindre enn eller lik 0, Dette betyr at fienden er død og så fjerner vi den på samme måte som kulen.

Og vår kollisjon gjenkjenning er gjort!


Trinn 15: Hvorfor reversere "For" Loops?

Husk at vi krysser fiender og kuler omvendt i vår spillsløyfe. La oss forstå hvorfor. La oss anta at vi brukte en stigende til sløyfe. Vi er på indeksen i = 3 og vi fjerner en kule fra arrayet. Ved fjerning av varen på posisjon 3, dens plass er fylt av elementet da på posisjon 4. Så nå varen tidligere på posisjon 4 er på 3. Etter iterasjonen Jeg øker med 1 og blir 4 og så gjenstand på posisjon 4 er sjekket.

Hopp, ser du hva som skjedde akkurat nå? Vi savnet bare varen nå på posisjon 3 som skiftet tilbake som følge av spleising. Og så bruker vi en omvendt til sløyfe som fjerner dette problemet. Du kan se hvorfor.


Trinn 16: Viser tårnets rekkevidde

La oss legge til noen ekstra ting for å få spillet til å se bra ut. Vi legger til funksjonalitet for å vise et tårnspekter når musen er svevet på den. Bytt til turret klasse og legg til noen variabler til det:

 privat var utvalg: int; privat var reload_time: int; privat var local_time: tall = 0; privat var kropp: Sprite; private var range_circle: Sprite;

Neste oppdatering av tegne funksjon til følgende:

 privat funksjonstegn (): void range_circle = new Sprite (); g = range_circle.graphics; g.beginFill (0x00D700); g.drawCircle (0, 0, område); g.endFill (); range_circle.alpha = 0.2; range_circle.visible = false; addChild (range_circle); body = new Sprite (); var g: Graphics = body.graphics; g.beginFill (0xD7D700); g.drawCircle (0, 0, 20); g.beginFill (0x800000); g.drawRect (0, -5, 25, 10); g.endFill (); addChild (legeme); 

Vi bryter tårnens grafikk inn i to deler: kroppen og rekkeviddegrafen. Vi gjør dette for å bestille på de forskjellige delene av tårnet. Her krever vi range_circle å ligge bak tårnets kropp, og så legger vi først til scenen. Til slutt legger vi til to muselyttere for å veksle rekkeviddegrafen:

 privat funksjon onMouseOver (e: MouseEvent): void range_circle.visible = true;  privat funksjon onMouseOut (e: MouseEvent): void range_circle.visible = false; 

Fest nå lytterne til de respektive hendelsene på slutten av konstruktøren:

 body.addEventListener (MouseEvent.MOUSE_OVER, onMouseOver); body.addEventListener (MouseEvent.MOUSE_OUT, onMouseOut);

Hvis du kjører spillet og prøver å distribuere et tårn, vil du se en flimring når du svinger på plassholdere. Hvorfor det?


Se flimmer?

Trinn 17: Fjerne flimmer

Husk at vi setter mouseEnabled egenskapen til spøkelseturret til falsk? Vi gjorde det fordi, spøkelseturret var å fange musebegivenheter ved å komme inn mellom musen og stedholderen. Den samme situasjonen har kommet igjen da tårnet selv har to barn nå - sin kropp og rekkevidde sprite - som fanger musen hendelsene i mellom.

Løsningen er den samme. Vi kan sette deres individuelle mouseEnabled egenskaper til falsk. Men en bedre løsning er å sette spøkelseturret mouseChildren eiendom til falsk. Hva dette gjør er å begrense alle spøkelseturretens barn fra å motta museventyr. Ryddig, va? Gå videre og sett den til falsk i Hoved konstruktør:

 ghost_turret = new Turret (); ghost_turret.alpha = 0.5; ghost_turret.mouseEnabled = false; ghost_turret.mouseChildren = false; ghost_turret.visible = false; addChild (ghost_turret);

Problemet løst.

Trinn 18: Hva neste?

Vi kan utvide denne demonstrasjonen for å inkludere mye mer avanserte funksjoner og gjøre det til et spillbart spill. Noen av disse kan være:

  1. Bedre AI logikk for å velge og skyte fiender.
  2. Ulike typer tårn, kuler og fiender i spillet.
  3. Komplekse fiendens stier i stedet for rette linjer.

La oss se hva du kan komme med fra denne grunnleggende demo. Jeg vil gjerne høre om deg tårnforsvarsspill, og dine kommentarer eller forslag til serien.