Faceți un joc de apărare turn în AS3 dușmani și AI de bază

Hei Flash Developers, bine ai venit în a doua parte a tutorialului meu de joc Tower Defense. În prima parte, am dezvoltat mecanismul de bază de creare a turnuletelor și de a le face să tragă spre punctul de clic al mouse-ului. Dar nu pentru asta sunt pușcăriile! În această parte vom extinde jocul pentru a include și dușmani, inteligența artificială de bază (AI) în turreți și alte elemente de joc. Sunteți gata?


Rezultatul final al rezultatelor

Acesta este jocul pe care îl vom crea în acest tutorial:

Faceți clic pe cercurile portocalii pentru a plasa turle. Cercurile roșii sunt dușmani, iar numărul pe fiecare reprezintă punctele sale de lovit.


Pasul 1: Recapitulați

În tutorialul precedent am dezvoltat un joc care a avut locații pentru turrete. Am putea folosi turnulete făcând clic pe acei locași, iar turnurile au vizat indicatorul mouse-ului și au tras gloanțe spre punctul în care a făcut clic pe utilizator.

Am terminat cu a Principal clasa care avea loopul jocului și logica jocului. În afară de asta am avut turelă clasă care nu avea nimic altceva decât Actualizați funcția care a făcut turnul să se rotească.


Pasul 2: O clasă separată de bullet

Am creat anterior gloanțele în Principal clasă și atașat un ENTER_FRAME ascultător pentru ao muta. Glonțul nu avea suficiente proprietăți mai devreme pentru a considera că este o clasă separată. Dar într-un astfel de joc, gloanțele pot avea mai multe soiuri, cum ar fi viteza, deteriorarea și așa mai departe, deci este o idee bună să scoateți codul glonțului și să îl încapsulați într-o Glonţ clasă. S-o facem.

Creați o nouă clasă numită Glonţ, extinderea spiriduș clasă. Codul de bază pentru această clasă ar trebui să fie:

 pachet import flash.display.Sprite; clasa publică Bullet extinde Sprite funcția publică Bullet () 

Apoi am plasat codul pentru a desena graficul de glont, luat de la Principal, în Glonţ. Așa cum am făcut și cu turelă class, creăm o funcție numită a desena în Glonţ clasă:

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

Și numim această funcție din Glonţ constructor:

 funcția publică Bullet () draw (); 

Acum adăugăm câteva proprietăți bulletului. Adăugați patru variabile: viteză, speed_x, rapid și deteriora, inainte de Glonţ constructor:

 viteză privată var: număr; private var speed_x: Număr; private var speed_y: Număr; public var damage: int;

Care sunt aceste variabile pentru?

  • viteză: Această variabilă stochează viteza glonțului.
  • speed_x și rapid: Acestea stochează componentele x și y ale vitezei, respectiv, astfel încât calcularea ruperii vitezei în componentele sale nu trebuie făcută din nou și din nou.
  • deteriora: Aceasta este suma daunelor pe care glonțul o poate face unui inamic. Păstrăm această variabilă publică, așa cum o vom cere în jocul nostru de joc Principal clasă.

Inițializăm aceste variabile în constructor. Actualizați-vă Glonţ constructor:

 funcția publică Bullet (unghi: număr) speed = 5; daune = 1; speed_x = Math.cos (unghi * Math.PI / 180) * viteza; speed_y = Math.sin (unghi * Math.PI / 180) * viteza; a desena(); 

Observați unghi variabilă pe care o primim în constructor. Aceasta este direcția (în grade) în care glonțul se va mișca. Vom rupe doar viteză în componentele x și y și le cache pentru utilizare ulterioară.

Ultimul lucru care rămâne în Glonţ clasa este de a avea un Actualizați funcția care va fi apelată din bucla de joc pentru a actualiza (muta) gloanțele. Adăugați următoarea funcție la sfârșitul secțiunii Glonţ clasă:

 funcția publică (): void x + = speed_x; y + = viteza_y; 

Bingo! Am terminat cu noi Glonţ clasă.


Pasul 3: Actualizarea clasei principale

Am mutat o mulțime de cod de glonț Principal clasa proprie Glonţ clasa, astfel încât o mulțime de cod rămâne neutilizat în Principal și multe trebuie să fie actualizate.

Mai întâi, ștergeți createBullet () și moveBullet () funcții. De asemenea, eliminați viteza glontului variabil.

Apoi, mergeți la trage funcția și actualizați-l cu următorul cod:

 funcția privată (e: MouseEvent): void pentru fiecare (var turret: turret în turreți) var new_bullet: Bullet = Bullet nou (turret.rotation); new_bullet.x = turret.x + Math.cos (turret.ro * Math.PI / 180) * 25; new_bullet.y = turret.y + Math.sin (turret.ro * Math.PI / 180) * 25; addChild (new_bullet); 

Nu mai folosim createBullet funcția de a crea glont mai degrabă utilizați Glonţ constructorul și să treacă turela rotație la care este direcția mișcării glonțului și nu avem nevoie să-l depozităm în gloanțe rotație proprietate așa cum am făcut-o mai devreme. De asemenea, nu atasem nici un ascultător la glonț, deoarece glonțul va fi actualizat din buclele de joc următoare.


Pasul 4: Salvarea referințelor bulletului

Acum că trebuie să actualizăm gloanțele din bucla de joc, avem nevoie de o referință a acestora pentru a fi stocată undeva. Soluția este aceeași ca și pentru turnulete: creați un nou mulțime numit gloanțe și împingeți gloanțele pe el în timp ce sunt create.

Mai întâi declarați o matrice imediat sub turnulete matrice declarație:

 privat Var ghost_turret: Turret; private var turrets: Array = []; buletine private var: Array = [];

Acum, pentru a popula această matrice. Facem acest lucru ori de câte ori creăm un nou glonț - deci, în trage funcţie. Adăugați următoarele înainte de a adăuga un glonț în scenă:

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

Pasul 5: Actualizați gloanțele

La fel ca modul în care actualizăm turletele cu bucla de joc, vom actualiza și gloanțele. Dar de data aceasta, în loc să folosești a pentru fiecare buclă, vom folosi o bază pentru buclă. Înainte de aceasta, trebuie să adăugăm două variabile în partea superioară a buclei de joc, astfel încât să știm care sunt variabilele folosite în cadrul jocului și pot fi libere pentru colectarea gunoiului.

 var turret: turret; var bullet: Bullet;

Mergeți mai departe și adăugați următorul cod la sfârșitul jocului:

 pentru (var i: int = bullets.length - 1; i> = 0; i -) bullet = ghilimele [i]; dacă (! bullet) continuați; bullet.update (); 

Aici traversăm peste toate gloanțele de pe scenă fiecare cadru și îi sunăm Actualizați funcție care le face să se miște. Rețineți că vom itera gloanțe array în sens invers. De ce? Vom vedea asta înainte.

Acum că avem a turelă variabila declarată afară deja, nu este nevoie să o declanșăm din nou înăuntru pentru fiecare buclă de turle. Modificați-l la:

 pentru fiecare (turelă în turle) turret.update (); 

În final, adăugăm condiția de verificare a limitei; acest lucru a fost anterior în glonț ENTER_FRAME dar acum o verificam in bucla de joc:

 dacă (bullet.x < 0 || bullet.x > stage.stageWidth || bullet.y < 0 || bullet.y > stage.stageHeight) bullets.splice (i, 1); bullet.parent.removeChild (glonț); continua; 

Verificăm dacă glonțul se află în afara limitei scenei și, dacă este cazul, eliminăm mai întâi referința din gloanțe folosind matricea lipitură apoi îndepărtați glonțul din scenă și continuați cu următoarea iterație. Acesta este modul în care ar trebui să arate bucla dvs. de joc:

 funcția privată gameLoop (e: Eveniment): void var turret: Turret; var bullet: Bullet; pentru fiecare (turelă în turle) turret.update ();  pentru (var i: int = bullets.length - 1; i> = 0; i -) bullet = ghilimele [i]; dacă (! bullet) continuați; bullet.update (); 

Dacă rulați acum jocul, trebuie să aveți aceeași funcționalitate ca în Partea 1, cu un cod mult mai curat și mai organizat.


Pasul 6: Prezentarea dușmanului

Acum adăugăm unul dintre cele mai importante elemente ale jocului: Enemy. Primul lucru este să creați o nouă clasă numită Dusman extinderea spiriduș clasă:

 pachet import flash.display.Sprite; clasa publică Enemy extinde Sprite funcția publică Enemy () 

Acum adăugăm câteva proprietăți la clasă. Adăugați-le înainte de dvs. Dusman constructor:

 private var speed_x: Număr; private var speed_y: Număr;

Inițializăm aceste variabile în Dusman constructor:

 funcția publică Enemy () speed_x = -1.5; speed_y = 0; 

Apoi vom crea a desena și Actualizați funcții pentru Dusman clasă. Acestea sunt foarte asemănătoare cu cele de la Glonţ. Adăugați următorul cod:

 funcția privată (): void var g: Graphics = this.graphics; g.beginFill (0xff3333); g.drawCircle (0, 0, 15); g.endFill ();  actualizarea funcției publice (): void x + = speed_x; y + = viteza_y; 

Pasul 7: Calendarul evenimentelor din joc

În jocul nostru trebuie să avem multe evenimente care au loc în anumite momente sau în mod repetat, la anumite intervale. Astfel de timp poate fi realizat folosind un contor de timp. Contorul este doar o variabilă care crește odată cu trecerea timpului în joc. Lucrul important aici este atunci când și cu câte cantități trebuie să creștem contorul. Există două moduri în care sincronizarea se face, în general, în jocuri: bazată pe timp și bazată pe cadre.

Diferența este că unitatea de pas în joc bazată pe timp se bazează pe timpul real (adică numărul de milisecunde trecut), dar într-un joc bazat pe cadru, unitatea de pas este bazată pe unități de cadru (adică numărul de cadre trecute).

Pentru jocul nostru vom folosi un contor bazat pe cadre. Vom avea un contor pe care îl vom majora cu unul în jocul de joc, care rulează fiecare cadru, și astfel ne va da numărul de cadre care au trecut de la începerea jocului. Mergeți mai departe și declarați o variabilă după celelalte declarații de variabile din Principal clasă:

 privat Var ghost_turret: Turret; private var turrets: Array = []; buletine private var: Array = []; privat var global_time: număr = 0;

Am incrementat această variabilă în bucla de joc din partea de sus:

 global_time ++;

Acum, pe baza acestui contor, putem face lucruri cum ar fi crearea de inamici, pe care o vom face în continuare.


Pasul 8: Să creăm niște dușmani

Ceea ce vrem să facem acum este să creăm dușmani pe teren după fiecare două secunde. Dar avem de-a face cu cadre aici, îți amintești? Deci, după câte rame trebuie să creăm dușmani? Ei bine, jocul nostru rulează la 30 FPS, crescând astfel global_time contra 30 de ori pe secundă. Un calcul simplu ne spune că 3 secunde = 90 de cadre.

La sfârșitul jocului adăugați următoarele dacă bloc:

 dacă (global_time% 90 == 0) 

Despre ce este această condiție? Folosim operatorul modulo (%), care dă restul unei diviziuni - așa global_time% 90 ne dă restul când global_time este împărțit prin 90. Verificăm dacă restul este 0, deoarece acest lucru se va întâmpla numai atunci când global_time este un multiplu de 90 - adică, condiția revine Adevărat cand global_time este egală 0, 90, 180 și așa mai departe ... În acest fel, realizăm un declanșator la fiecare 90 de cadre sau 3 secunde.

Înainte de a crea dușmanul, declarăm o altă matrice numită inamici chiar sub turnulete și gloanțe matrice. Acest lucru va fi folosit pentru a stoca referințe la inamici pe scenă.

 privat Var ghost_turret: Turret; private var turrets: Array = []; buletine private var: Array = []; private vrăjmașii var: Array = []; privat var global_time: număr = 0;

De asemenea, declarați un dusman variabilă în partea de sus a jocului:

 global_time ++; var turret: turret; var bullet: Bullet; var inamic: Inamic;

În final, adăugați următorul cod în interiorul dacă bloc pe care l-am creat mai devreme:

 inamic = nou Enemy (); enemy.x = 410; enemy.y = 30 + Math.random () * 370; enemies.push (inamic); addChild (inamic);

Aici creăm un nou inamic, poziționează-l la întâmplare în dreptul scenei, împingeți-l în inamici și adăugați-o pe scenă.


Pasul 9: Actualizarea dușmanilor

La fel cum actualizăm gloanțele în jocul de joc, actualizăm dușmanii. Puneți următorul cod sub turelă pentru fiecare buclă:

 pentru (var j: int = enemies.length - 1; j> = 0; j--) enemy = inamici [j]; enemy.update (); dacă (enemy.x < 0)  enemies.splice(j, 1); enemy.parent.removeChild(enemy); continue;  

Ca și cum am făcut o verificare a granițelor pentru gloanțe, verificăm și dușmanii. Dar pentru dușmani, verificăm doar dacă au ieșit din stânga scenei, deoarece se mișcă de la dreapta la stânga. Ar trebui să vadă dușmani venind din dreapta dacă conduci jocul acum.


Pasul 10: Dați dușmanilor o sănătate

Fiecare inamic are o viață / sănătate și așa va fi și al nostru. Vom arăta și sănătatea rămasă pe dușmani. Permite declararea unor variabile în Dusman clasa pentru sănătate:

 privat var health_txt: TextField; private var health: int; private var speed_x: Număr; private var speed_y: Număr;

Inițializăm sănătate variabilă în constructorul următor. Adăugați următoarele la Dusman constructor:

 sănătate = 2;

Acum inițializăm variabila textului de sănătate pentru a arăta în centrul inamicului. Facem acest lucru în a desena funcţie:

 health_txt = TextField nou (); health_txt.height = 20; health_txt.width = 15; health_txt.textColor = 0xffffff; health_txt.x = -5; health_txt.y = -8; health_txt.text = sănătate + ""; addChild (health_txt);

Tot ce facem este să creați un nou TextField, setați culoarea, poziționați-o și setați textul acesteia la valoarea curentă de sănătate În cele din urmă adăugăm o funcție de actualizare a sănătății inamicului:

 funcția publică funcția updateHealth (suma: int): int health + = suma; health_txt.text = sănătate + ""; returnează sănătatea; 

Funcția acceptă un număr întreg pentru adăugarea la sănătate, actualizează textul de sănătate și returnează sănătatea finală. Vom numi această funcție din bucla de joc pentru a actualiza sănătatea inamicului și pentru a afla dacă este încă în viață.


Pasul 11: Împușcarea dușmanilor.

Mai întâi vă permitem să ne modificăm trage funcționează puțin. Înlocuiți existența trage funcția cu următoarele:

 funcția privată (turelă: turelă, inamic: inamic): void var unghi: număr = Math.atan2 (inamic.y - turret.y, enemy.x - turret.x) / Math.PI * 180; turret.rotation = unghi; var new_bullet: Bullet = Bullet nou (unghi); new_bullet.x = turret.x + Math.cos (turret.ro * Math.PI / 180) * 25; new_bullet.y = turret.y + Math.sin (turret.ro * Math.PI / 180) * 25; bullets.push (new_bullet); addChild (new_bullet); 

trage funcția acceptă acum doi parametri. Prima este o referire la o turelă care va face focul; a doua este o referire la un dușman spre care va trage.

Noul cod este similar cu cel prezent în turelă clasa lui Actualizați funcția, dar în loc de poziția mouse-ului, folosim acum coordonatele dușmanului. Deci, acum puteți să eliminați tot codul din Actualizați funcția turelă clasă.

Acum cum să faci turlele să tragă la inamici? Ei bine, logica este simplă pentru jocul nostru. Noi facem toate turnurile să împușcă primul inamic în inamici matrice. Ce? Să punem niște cod și să încercăm să înțelegem. Adăugați următoarele linii la sfârșitul secțiunii pentru fiecare buclă pentru a actualiza turletele:

 pentru fiecare (turelă în turle) turret.update (); pentru fiecare (dușman în dușmani) trage (turelă, inamic); pauză; 

Pentru fiecare turelă actualizăm acum, apoi iterați inamici array, trage primul dușman în matrice și se rupe din bucla. Deci, în mod esențial, fiecare turelă împușcă cel mai devreme inamic creat așa cum este întotdeauna la începutul matricei. Încercați să rulați jocul și ar trebui să vedeți turnulete care să împuște dușmanii.

Dar așteptați, care este fluxul bullet care curge? Se pare că trag prea repede. Să vedem de ce.


Pasul 12: Turretele fac focuri prea rapide

După cum știm, bucla de joc rulează fiecare cadru, adică de 30 de ori pe secundă în cazul nostru, așa că declarația de fotografiere pe care am adăugat-o în pasul anterior este apelată la viteza jocului nostru și, prin urmare, vedem un flux de gloanțe care curge. Se pare că avem nevoie și de un mecanism de sincronizare în interiorul turretului. Treceți la turelă clasă și adăugați următorul cod:

 privat var local_time: Număr = 0; privat var reload_time: int;
  1. ora locala: Numărătoarele noastre sunt numite ora locala În contrast cu global_time în Principal clasă. Acest lucru este din două motive: în primul rând, deoarece această variabilă este locală la turelă clasă; în al doilea rând, pentru că nu merge întotdeauna ca și noi global_time variabilă - se va reseta de mai multe ori pe parcursul jocului.
  2. timp de reîncărcare: Acesta este timpul necesar pentru reîncărcarea turelei după fotografierea unei gloanțe. Practic este diferența de timp dintre două lunete de glonț de o turelă. Amintiți-vă că toate unitățile de timp din jocul nostru sunt în termeni de cadre.

Creșteți valoarea ora locala variabilă în Actualizați funcționează și inițializează timp de reîncărcare în constructor:

 funcția publică (): void local_time ++; 
 funcția publică funcția Turret () reload_time = 30; a desena(); 

Apoi adăugați următoarele două funcții la sfârșitul secțiunii turelă clasă:

 funcția publică esteReady (): Boolean return local_time> reload_time;  funcția publică resetată (): void local_time = 0; 

este gata returnează adevărat numai atunci când curentul ora locala este mai mare decât timp de reîncărcare, adică când turela a fost reîncărcată. Si restabili funcția reinițializează pur și simplu ora locala , pentru a porni din nou încărcarea.

Acum, înapoi în Principal clasă, modificați codul de înregistrare în bucla de joc pe care am adăugat-o în etapa anterioară la următoarele:

 pentru fiecare (turelă în turle) turret.update (); dacă (! turret.isReady ()) continuă; pentru fiecare (dușman în dușmani) trage (turelă, inamic); turret.reset (); pauză; 

Deci, dacă acum turnuletul nu este gata (este gata() se intoarce fals), vom continua cu următoarea iterație a buclei de turelă. Veți vedea că turnurile se declanșează la un interval de 30 de cadre sau o secundă acum. Rece!


Pasul 13: Limitați gama de turre

Încă ceva nu este corect. Turnuletele trag la dușmani, indiferent de distanța dintre ele. Ceea ce lipsește aici este gamă de o turelă. Fiecare turelă ar trebui să aibă propria gamă în care să poată împușca un inamic. Adăugați o altă variabilă la turelă clasa numită gamă și puneți-o la dispoziție 120 în interiorul constructorului:

 privat var reload_time: int; privat var local_time: Număr = 0; gama privată var: int;
 funcția publică funcția Turret () reload_time = 30; interval = 120; a desena(); 

Adăugați, de asemenea, o funcție numită canShoot la sfârșitul clasei:

 funcția publică canShoot (inamic: Enemy): Boolean var dx: Number = enemy.x - x; var dy: Număr = inamic.y - y; dacă (Math.sqrt (dx * dx + dy * dy) <= range) return true; else return false; 

Fiecare turelă poate să tragă un dușman numai atunci când îndeplinește anumite criterii - de exemplu, ați putea lăsa turela să tragă doar dușmani roșii cu mai puțin de jumătate din viață și nu mai mult de 30px distanță. Toată această logică pentru a determina dacă turela este capabilă să tragă un dușman sau nu va intra în canShoot funcție, care se întoarce Adevărat sau fals conform logicii.

Logica noastră este simplă. Dacă inamicul se află în intervalul de întoarcere Adevărat; altfel returnează falsul. Deci, atunci când distanța dintre turelă și inamic (Math.sqrt (dx * dx + dy * dy)) este mai mică sau egală cu gamă, se întoarce Adevărat. Un pic mai multă modificare în secțiunea de film a jocului:

 pentru fiecare (turelă în turle) turret.update (); dacă (! turret.isReady ()) continuă; pentru fiecare (inamic in dusmani) if (turret.canShoot (inamic)) trage (turela, inamic); turret.reset (); pauză; 

Acum numai dacă dușmanul se află în raza de acțiune a turelei, va trage turela.


Pasul 14: Detectarea coliziunilor

O parte foarte importantă a fiecărui joc este detecția coliziunilor. În joc, verificarea coliziunii se face între gloanțe și dușmani. Vom adăuga codul de detectare a coliziunii în interiorul pentru fiecare buclă care actualizează gloanțele în bucla de joc.

Logica este simplă. Pentru fiecare glonț traversăm inamici și verificați dacă există o coliziune între ele. Dacă da, eliminăm glontul, actualizăm sănătatea inamicului și ieșim din bucla pentru a verifica alți dușmani. Să adăugăm un cod:

 pentru (i = bullets.length - 1; i> = 0; i -) bullet = gloanțe [i]; // dacă nu este definită gluma, continuați cu următoarea iterație dacă (! bullet) continuați; bullet.update (); dacă (bullet.x < 0 || bullet.x > stage.stageWidth || bullet.y < 0 || bullet.y > stage.stageHeight) bullets.splice (i, 1); bullet.parent.removeChild (glonț); continua;  pentru (var k: int = enemies.length - 1; k> = 0; k--) enemy = inamici [k]; dacă (bullet.hitTestObject (inamic)) bullets.splice (i, 1); bullet.parent.removeChild (glonț); dacă (inamic.updateHealth (-1) == 0) enemies.splice (k, 1); enemy.parent.removeChild (inamic);  pauză; 

Folosim ActionScript hitTestObject pentru a verifica coliziunea dintre glonț și inamic. Dacă se produce ciocnirea, glonțul este îndepărtat în același mod ca atunci când părăsește etapa. Sănătatea inamicului este apoi actualizată folosind updateHealth metodă, la care glonţ„s deteriora proprietatea este trecută. În cazul în care updateHealth funcția returnează un număr mai mic sau egal cu 0, aceasta înseamnă că dușmanul este mort și așa îl eliminăm în același mod ca și glonțul.

Și detectarea coliziunilor noastre sa terminat!


Pasul 15: De ce să inversați buclele "For"?

Amintiți-vă că traversăm dușmanii și gloanțele înapoi în bucla noastră de joc. Să înțelegem de ce. Să presupunem că am folosit un ascendent pentru buclă. Suntem pe index i = 3 și eliminăm un glonț din matrice. La îndepărtarea elementului în poziție 3, spațiul său este umplut de articol apoi în poziție 4. Deci, acum elementul anterior în poziție 4 este la 3. După repetare eu incremente de 1 și devine 4 și așa mai departe la poziție 4 este bifat.

Hopa, vezi ce sa întâmplat acum? Tocmai am pierdut articolul acum în poziție 3 care s-au mutat înapoi ca rezultat al îmbinării. Și așa vom folosi o inversă pentru care elimină această problemă. Puteți vedea de ce.


Pasul 16: Afișarea gamei turretului

Să adăugăm câteva lucruri suplimentare pentru a face jocul să arate bine. Vom adăuga funcționalități pentru a afișa o rază a turelei atunci când mouse-ul este plutind pe el. Treceți la turelă și adăugați câteva variabile la ea:

 gama privată var: int; privat var reload_time: int; privat var local_time: Număr = 0; privat var corp: Sprite; privat var_circle: Sprite;

Actualizați ulterior a desena funcționează la următoarele:

 funcția privată (): void range_circle = Sprite nou (); g = range_circle.graphics; g.beginFill (0x00D700); g.drawCircle (0, 0, interval); g.endFill (); range_circle.alpha = 0.2; range_circle.visible = false; addChild (range_circle); corp = Sprite nou (); var g: Grafica = grafica corporala; g.beginFill (0xD7D700); g.drawCircle (0, 0, 20); g.beginFill (0x800000); g.drawRect (0, -5, 25, 10); g.endFill (); addChild (corp); 

Spargem graficele turelei în două părți: corpul și graficul intervalului. Facem acest lucru pentru a da o comandă diferitelor părți ale turelei. Aici avem nevoie de range_circle pentru a fi în spatele corpului turelei, așa că o adăugăm mai întâi la scenă. În cele din urmă, adăugăm doi ascultători de mouse pentru a comuta graficul de domeniu:

 funcția privată onMouseOver (e: MouseEvent): void range_circle.visible = true;  funcția privată onMouseOut (e: MouseEvent): void range_circle.visible = false; 

Acum atașați ascultătorii la evenimentele respective la sfârșitul constructorului:

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

Dacă rulați jocul și încercați să desfășurați o turelă, veți vedea o pâlpâire atunci când se deplasează pe locurile de substituție. De ce este asta?


Vedeți pâlpâirea?

Pasul 17: Înlăturarea pâlpâirii

Amintiți-vă că am setat mouseEnabled proprietate a turelei fantomă la fals? Am făcut-o pentru că turela fantomă capta evenimentele mouse-ului venind între mouse și substituent. Aceeași situație a sosit din nou, deoarece turela are acum doi copii - corpul său și sprite - care captează evenimentele mouse-ului între.

Soluția este aceeași. Le putem stabili individul mouseEnabled proprietăți pentru fals. Dar o soluție mai bună este de a seta turela ghost mouseChildren proprietate la fals. Ceea ce face acest lucru este să restricționăm toți copiii turelei fantomă de la recepția evenimentelor mouse-ului. Neat, nu? Mergeți și puneți-o la dispoziție fals în Principal constructor:

 ghost_turret = noua turela (); ghost_turret.alpha = 0.5; ghost_turret.mouseEnabled = false; ghost_turret.mouseChildren = false; ghost_turret.visible = false; addChild (ghost_turret);

Problema rezolvata.

Pasul 18: Ce urmează?

Am putea extinde acest demo pentru a include caracteristici mult mai avansate și transforma-l într-un joc care poate fi jucat. Unele dintre acestea ar putea fi:

  1. O logică mai bună a AI pentru selectarea și împușcarea dușmanilor.
  2. Diferite tipuri de turnulete, gloanțe și dușmani în joc.
  3. Căi inamice complexe în loc de linii drepte.

Să vedem ce puteți face de la acest demo de bază. Voi fi bucuros să aud despre jocurile de apărare din turn și comentariile sau sugestiile dvs. pentru serii.

Cod