Portarea Jocuri ActionScript în iOS cu SDK Corona Partea 3

Acest tutorial va arunca o privire asupra portării unui joc Flash / Flex pe SDK-ul Corona. În mod specific, vom porta de la ActionScript la Lua, cu obiectivul final de a juca jocuri de tip Flash numai pe iPhone. Pe lângă demonstrarea limbajului și a diferențelor API, această serie de tutori va explica și restricțiile hardware, cum ar fi dimensiunea ecranului și lipsa butoanelor fizice pe iPhone.

Adăugarea dușmanilor

Acum vom începe să lucrăm cu inamicul nostru: "de / pixelate / flixelprimer / Alien.as". Ca întotdeauna, sintaxa devine mai întâi convertită.

Când ați terminat cu asta, adăugați declarerea modulului și înfășurați toate funcțiile din interiorul lui Alien ().

 (x, y) -: void (x, y) - [Embed (sursă = "? /? /? /? /assets/png/Alien.png" super (x, y, ImgAlien) viteza.x = -200 actualizare funcție () -: void velocity.y = Math.cos (x / 50) * 50 super.update

Străinul funcționează foarte asemănător cu glonțul nostru. Creează o imagine, își stabilește x și y
coordonează și îi dă o viteză. Deci, ne vom apropia de ea în același mod. Primele două linii din interiorul funcției pot fi înlocuite cu aproape același cod ca și cel folosit pentru glonț. De data aceasta vom folosi o imagine.

 (x, y) -: void local Alien = display.newImage ("Alien.png") Alien.x = x Alien.y = actualizare funcție () -: void ? sfârșitul final

Acum, când avem imaginea încărcată și setată, hai să o mutăm spre stânga. Din nou, vom crea ceva de genul codului de actualizare () al glonțului. Lăsați vechile linii din update () comentate.

 modul (functie?, pachet.see) Functie Alien (x, y) -: void? function update () -: void daca Alien atunci daca (Alien.x> 0 - Alien.contentWidth) apoi Alien.x = Alien.x - 2 end end? codul comentat? sfârșitul runtime: addEventListener ("enterFrame", actualizare) sfârșit

Acum, hai să facem o funcție kill () și să-i facem pe Alien să se întoarcă un Alien.

 modul (functie?, pachet.see) Functie Alien (x, y) -: void? actualizare funcție () -: void? end Alien: kill () Alien.parent: elimina (Alien) Alien = capăt nil Runtime: addEventListener ("enterFrame", update)

Acum putem ucide () pe străinul nostru dacă x este pe ecranul din stânga. De asemenea, putem adăuga o funcție nouă () ca o convenție.

 (x, y) -: void local Alien = display.newImage ("Alien.png") Alien.x = x Alien.y = actualizare funcție () -: void dacă Alien apoi dacă (Alien.x> 0 - Alien.contentWidth), apoi Alien.x = Alien.x - 2 alt Alien: kill () sfârșitul sfârșitul sfârșitul funcției Alien: kill () Alien.parent: null end Runtime: addEventListener ("enterFrame", update) retur Alien end functie noua (x, y) retur Alien (x, y) end

Utilizarea cronometrelor pentru a controla străinii

Crearea străinului era destul de ușoară. Acum trebuie să începem să le adăugăm la joc prin PlayState.

Mai întâi, importați modulul în PlayState.lua.

 Modulele locale (=, ship.seeall) nava locală = necesită ("Ship") local Bullet = necesită ("Bullet") local Alien = necesită ("Alien"

Acum trebuie să setăm un cronometru. Codul original a avut o variabila _spawnInterval care a fost utilizata pentru a seta _spawnTimer. De fiecare data cand _spawnTimer a ajuns la 0, ar fi resetat la valoarea _spawnInterval._spawnInterval ar fi apoi scazut cu .1, rezultand ca extratereștrii sa se nasca mai repede.

Pentru a începe, dezarhivați declerațiile de proprietate _spawnInterval și _spawnTimer în create ().

 function create () -: void - declaratii variabile PlayState._inGame = true PlayState._background = nil PlayState._ship = nil --PlayState._aliens = nil PlayState._bullets = nil --PlayState._scoreText = nil --PlayState. _gameOverText = nil PlayState._spawnTimer = nil PlayState._spawnInterval = nil --PlayState.SoundExplosionShip = nil --PlayState.SoundExplosionAlien = nil PlayState.SoundBullet = zero? Sfârșit

Acum, în sarcini variabile, setați _spawnTimer la 0 și _spawnInterval la 2.5. De asemenea, adăugați un apel pentru a resetaSpawnTimer (). Vom crea această funcție într-o secundă.

 funcția create () -: void? - misiuni variabile PlayState._background = display.newRect (0, 0, display.contentWidth, display.contentHeight) PlayState._background: setFillColor (171, 204, 125) PlayState._ship = Ship.new () PlayState._shoot = false PlayState._bullets = display.newGroup () PlayState.SoundBullet = media.newEventSound ("Bullet.caf") PlayState._spawnTimer = 0 PlayState._spawnInterval = 2.5 ResetSpawnTimer () Sfârșit

Acum găsiți funcția comentată resetSpawnTimer (). Va arăta așa.

 resetareSpawnTimer () -: void _spawnTimer = _spawnInterval _spawnInterval = _spawnInterval * 0,95 dacă (_spawnInterval < 0.1) then _spawnInterval = 0.1 end end

Destul de uimitor, este exact ceea ce avem nevoie. Trebuie doar să facem proprietățile variabilelor PlayState. În acest fel, funcția va ști ce înseamnă _spawnInterval și _spawnTimer despre care vorbim.

 resetSpawnTimer () -: void PlayState._spawnTimer = PlayState._spawnInterval PlayState._spawnInterval = PlayState._spawnInterval * 0.95 dacă (PlayState._spawnInterval < 0.1) then PlayState._spawnInterval = 0.1 end end

Acum trebuie să adăugăm un cod pentru actualizare (). În codul original, jocul a creat străinilor chiar dacă jocul sa terminat și nava a murit. Pentru a face același lucru, să punem codul nostru de manipulare străin în afara locului unde verificăm dacă jocul sa terminat.

 () PlayState._spawnTimer = PlayState._spawnTimer - (30/1000) dacă (PlayState._spawnTimer < 0) then spawnAlien() resetSpawnTimer() end if PlayState._inGame then? end end

Acest cod funcționează la fel ca și codul sursă. Acesta scade timpul de 1 cadru de la _spawnTimer. Apoi verifică dacă _spawnTimer este mai mic decât zero. Dacă este, resetează temporizatorul și declanșează un nou străin.

Un alt grup de afișare

Înainte de a putea da naștere oricărui străin, avem nevoie de un grup de afișare pentru a le adăuga. La fel ca și bulinele, să dezinstalați decalarea _aliens și să le atribuiți unui nou grup de afișare.

 () -: void - declarații variabile PlayState._inGame = true PlayState._background = nil PlayState._ship = nil PlayState._aliens = nil PlayState._bullets = nil --PlayState._scoreText = nil --PlayState._gameOverText = nils PlayState._spawnTimer = nil PlayState._spawnInterval = 2.5 --PlayState.SoundExplosionShip = nil --PlayState.SoundExplosionAlien = nil PlayState.SoundBullet = nil - asignări variabile PlayState._background = display.newRect (0, 0, display.contentWidth, display.contentHeight) PlayState._background: setFillColor (171, 204, 125) PlayState._ship = Ship.new () PlayState._shoot = fals PlayState._aliens = display.newGroup () PlayState._bullets = display.newGroup () PlayState. SoundBullet = media.newEventSound ("Bullet.caf") PlayState._spawnTimer = 0 PlayState._spawnInterval = 2.5 resetSpawnTimer ()? Sfârșit

Acum găsiți funcția spawnAlien () și rulați-o. Ar trebui să arate ceva de genul:

 ()): void local x = FlxG.width local y = Math.random () * (FlxG.height - 100) + 50 _aliens.add (nou Alien (x, y)

Acest cod creează un extraterestru exact în partea dreaptă a ecranului și la o înălțime aleatorie. Apoi adaugă noul străin grupului de afișare. Putem face același lucru cu acest cod:

 ()):: void local x = display.contentWidth local y = math.random () * (display.contentHeight - 240) + 50 PlayState._aliens: inserați (Alien.new (x, y)

Refacerea mișcării inițiale bazate pe valuri cosine pentru străini

Dacă rulam codul acum, funcționează aproape ca originalul. Străinii apar la înălțimi aleatorii și apar lent mai frecvent. Când ajung în afara ecranului, ei îl cheamă pe ei înșiși. Acum trebuie doar să-i facem să se mute așa cum au făcut-o în codul original. În jocul original, extratereștrii au urmat calea unui val cosinus care a fost generat pe baza poziției lor x. Acest cod a fost comentat în funcția de actualizare () al străinilor. Acest cod a luat unele de joc cu. Deoarece nu avem viteza de lucru, este greu să folosim codul original. Acesta este momentul în porting în cazul în care va trebui doar să se joace cu numerele. Am gasit acest cod lucrat cel mai aproape de original:

 actualizare functie () -: void daca Alien atunci daca (Alien.x> 0 - Alien.contentWidth) apoi Alien.x = Alien.x - 2 Alien.y = Alien.y + math.cos (Alien.x / 10 ) * 2 altul Alien: kill () sfârșitul sfârșitul final

Manipularea coliziunilor

Acum că avem toate obiectele jocului care lucrează ca și originalele, trebuie să verificăm coliziunea dintre gloanțe și extratereștri, străinilor și navelor. În codul original, coliziunile au fost verificate în funcția update (). În cazul în care a apărut o coliziune, cele două obiecte au fost transmise funcțiilor suprapuseAlienBullet () și overlapAlienShip (). Să creăm mai întâi aceste funcții. Dacă necomplexăm suprapunAlienBullet (), avem un cod care arată astfel:

 () AlienBullet (străin, bullet) -: void emitter local = createEmitter () emitter.at (alien) alien.kill () FlxG.play (SoundExplosionAlien) FlxG.score = FlxG.score + 1 _scoreText. text = FlxG.score.toString () sfârșit

Acest cod creează un emițător de particule, ucide ambele obiecte, joacă un efect sonor și actualizează scorul. Refacerea sistemului de particule flixel este dincolo de sfera de aplicare a acestui tutorial și încă nu am implementat un sistem de scoruri. Pentru moment, hai să comentăm acele linii și să ucidem obiectele.

 () - () - () () - () -: - - - - - - - - - = - =. toString () sfârșitul

Faceți același lucru pentru suprapunereaAlienShip ():

 () - (): - void ship: kill () alien: kill () --FlxG.play (SoundExplosionShip) --_ gameOverText = new FlxText (0, FlxG.height / 2, FlxG.width, OVER \ nPRESS ENTER pentru a juca din nou ") --_ gameOverText.setFormat (null, 16, 0xFF597137," center ") - add (_gameOverText) end

Acum, să creăm efectul de sunet pentru utilizarea în aceste funcții. Dezactivați declarațiile de variabile de sunet în create ().

 () -: void - declarații variabile PlayState._inGame = true PlayState._background = nil PlayState._ship = nil PlayState._aliens = nil PlayState._bullets = nil --PlayState._scoreText = nil --PlayState._gameOverText = nil PlayState._spawnTimer = nil PlayState._spawnInterval = 2.5 PlayState.SoundExplosionShip = nil PlayState.SoundExplosionAlien = nil PlayState.SoundBullet = zero? Sfârșit

Acum le atribui sunetelor lor:

 funcția create () -: void? - misiuni variabile PlayState._background = display.newRect (0, 0, display.contentWidth, display.contentHeight) PlayState._background: setFillColor (171, 204, 125) PlayState._ship = Ship.new () PlayState._shoot = false PlayState._aliens = display.newGroup () PlayState._bullets = display.newGroup () PlayState.SoundBullet = media.newEventSound ("Bullet.caf") PlayState.SoundExplosionShip = media.newEventSound ("ExplosionShip.caf") PlayState.SoundExplosionAlien = media.newEventSound ("ExplosionAlien.caf") PlayState._spawnTimer = 0 PlayState._spawnInterval = 2.5 resetSpawnTimer () Sfârșit

Redarea sunetelor este la fel de ușoară ca o singură linie pe funcție ().

 () strălucitor (), strălucitor (), kill () bullet: kill () media.playEventSound (PlayState.SoundExplosionAlien) --FlxG.score = FlxG.score + 1__ scoreText.text = FlxG.score. toString () termină funcția overlapAlienShip (străin, navă) -: void ship: kill () străin: kill () media.playEventSound (PlayState.SoundExplosionShip) --_ gameOverText = FlxText nou. latime, "GAME OVER \ nPRESS ENTER pentru a juca din nou") --_ gameOverText.setFormat (null, 16, 0xFF597137, "center") - add (_gameOverText)

Rulați propriul cod de coliziune

Acum, când avem funcțiile noastre de suprapunere, trebuie să verificăm coliziunea fiecărui cadru. În Corona, nu avem o modalitate ușoară de a verifica suprapunerea obiectelor afișate. Va trebui să facem verificările manual. Acesta este un concept destul de ușor, dar devine destul de murdar în punerea în aplicare. Să ne gândim la asta pentru o secundă. Ce definește o suprapunere? Primul dvs. instinct ar putea fi să verificați dacă un obiect se află în interiorul altui. Acest lucru ar funcționa, dar în acest caz o suprapunere ar putea fi doar părți ale obiectelor. Un obiect nu trebuie să se afle în interiorul celuilalt pentru a se suprapune. Cum arată acest lucru în cod? Tot ce trebuie să facem este să verificăm dacă valoarea maximă x a unui obiect este mai mare decât minimul x
valoarea celuilalt obiect. Apoi verificăm dacă valoarea minimă x a aceluiași obiect este mai mică decât valoarea maximă x a celorlalte obiecte. Aceasta se va întoarce pentru fiecare suprapunere. În continuare, efectuăm aceleași verificări asupra valorilor y ale obiectelor. Dacă buclele prin toate obiectele din grupurile de afișare pe care le-am creat mai devreme, ar trebui să avem un sistem de coliziune.

Să încercăm asta cu gloanțele și străinii. Trebuie să efectuăm aceste verificări numai în timpul jocului. Așa că puneți acest cod în interiorul părții corecte a funcției update ():

 actualizare funcție () -: void? dacă PlayState._inGame atunci dacă PlayState._shoot == true și PlayState._ship atunci p = PlayState._ship: getBulletSpawnPosition () spawnBullet (p) se termină dacă PlayState._bullets.numChildren> 0 și PlayState._aliens.numChildren> 0, apoi pentru b = 1, PlayState._bullets.numChildrenul face local bulletXMax = PlayState._bullets [b] .contentBounds.xMax local bulletXMin = PlayState._bullets [b] .contentBounds.xMin local bulletYMax = PlayState._bullets [b] .contentBounds.yMax local bulletYMin = PlayState._bullet [b] .contentBounds.yMin pentru a = 1, PlayState._aliens.numChildren face dacă (PlayState._aliens [a] .contentBounds.xMin <= bulletXMax) then if (PlayState._aliens[a].contentBounds.xMax >= bulletXMin) atunci dacă (PlayState._aliens [a] .contentBounds.yMin <= bulletYMax) then if (PlayState._aliens[a].contentBounds.yMax >= bulletYMin), apoi overlapAlienBullet (PlayState._aliens [a], PlayState._bullets [b]) capăt capăt capăt capăt capăt capăt capăt capăt capăt

Asa cum am spus, acest cod pare cam murdar, dar functioneaza. Deci ce face asta? În primul rând, verifică dacă există un glonț sau un străin. Acest cod poate deveni într-adevăr intens de memorie, deci trebuie să verificăm totul. Nu vrem să pierdem timpul dacă nu avem nici măcar ambele obiecte. Odată ce codul trece, începem o buclă. Această buclă stabilește o variabilă ("b" numită după "gloanțe") la 1 și rulează restul codului pentru fiecare glonț în _bullete. Următoarele patru linii de coduri creează o copie locală a valorilor min și max ale glonțului. Cum am spus mai înainte, trebuie să economisim memoria aici. Nu este nevoie să calculam valorile x și y ale gloanțelor din nou și din nou dacă nu se schimbă. Următoarea linie începe încă una pentru buclă. Acest lucru se repetă pentru toți străinii din _aliens. Codul din interiorul celui de al doilea buclă efectuează doar verificările despre care am vorbit mai devreme. Valoarea max x a glonțului este mai mare decât valoarea min x a străinului? Nu-mi pot aminti destul de mult aici
este motivul pentru care verificăm fiecare condiție într-o instrucțiune separată dacă. Dacă unul dintre aceste teste eșuează, putem să scăpăm de bucla. Nu este nevoie să continuați să verificați dacă nu există o coliziune. În cele din urmă, chiar în centrul, dacă toate aceste verificări trec, numim funcția overlapAlienBullet () cu glonțul care se ciocnește și cu străinul.

Whew. A fost o mulțime de cod. Acum trebuie să facem același lucru pentru navă.

 actualizare funcție () -: void? dacă PlayState._inGame atunci dacă PlayState._shoot == true și PlayState._ship atunci local p = PlayState._ship: getBulletSpawnPosition () spawnBullet (p) final? dacă PlayState._aliens.numChildren> 0 atunci nava localăXMax = PlayState._ship.contentBounds.xMax navă localăXMin = PlayState._ship.contentBounds.xMin local shipYMax = PlayState._ship.contentBounds.yMax local shipYMin = PlayState._ship.contentBounds.yMin pentru a = 1, PlayState._aliens.numChildren face dacă (PlayState._aliens [a] .contentBounds.xMin <= shipXMax) then if (PlayState._aliens[a].contentBounds.xMax >= shipXMin) atunci dacă (PlayState._aliens [a] .contentBounds.yMin <= shipYMax) then if (PlayState._aliens[a].contentBounds.yMax >= shipYMin), apoi overlapAlienShip (PlayState._aliens [a], PlayState._ship) capăt capăt capăt capăt capăt capăt sfârșit sfârșit

Acest cod este identic cu cel al glonțului și al codului extraterestru. Singura diferență este că avem doar o navă. Știm că există o navă, altfel PlayState.inGame ar fi falsă. Nu avem nevoie de o buclă prin intermediul unui grup de nave afișate, deoarece avem doar unul.

Înainte de a putea testa acest cod, trebuie să transformăm jocul în overlapAlienShip (). Modificați _inGame la fals.

 (0) (0, FlxG.height / 2, FlxG ()) - (1) Fluturaș (1) .width, "GAME OVER \ nPRESS ENTER pentru a juca din nou") --_ gameOverText.setFormat (null, 16, 0xFF597137, "center") - add (_gameOverText)

Rularea codului arată acum că munca noastră grea a fost plătită. Acum avem un port complet de lucru al jocului original. Încă mai trebuie să recreăm sistemul de scoruri și trebuie să reușim să reluăm jocul, dar portarea greșită este terminată.

Implementarea unui sistem de scoruri

Să începem cu sistemul de scoruri. Acest lucru este la fel de simplu ca crearea unei etichete de text și actualizarea acesteia atunci când scorul se schimbă. Dezactivați linia _scoreText și adăugați o proprietate _score nouă în declarațiile create ().

 function create () -: void - declaratii variabile PlayState._inGame = true PlayState._background = nil PlayState._ship = nil PlayState._aliens = nil PlayState._bullets = nil PlayState._score = nil PlayState._scoreText = nil --PlayState ._gameOverText = nil PlayState._spawnTimer = nil PlayState._spawnInterval = 2.5 PlayState.SoundExplosionShip = nil PlayState.SoundExplosionAlien = nil PlayState.SoundBullet = nil? Sfârșit

Acum trebuie să le atribuim câteva valori. _score poate fi doar setat la 0. _scoreText trebuie să fie atribuit un obiect text nou situat în partea din stânga sus a ecranului.

 funcția create () -: void? - misiuni variabile PlayState._background = display.newRect (0, 0, display.contentWidth, display.contentHeight) PlayState._background: setFillColor (171, 204, 125) PlayState._ship = Ship.new () PlayState._shoot = false PlayState._aliens = display.newGroup () PlayState._bullet = display.newGroup () PlayState._score = 0 PlayState._scoreText = display.newText ("0", 10, 8, zero, 32) PlayState._scoreText: setTextColor , 113, 55) PlayState.SoundBullet = media.newEventSound ("Bullet.caf") PlayState.SoundExplosionShip = media.newEventSound ("ExplosionShip.caf") PlayState.SoundExplosionAlien = media.newEventSound ("ExplosionAlien.caf") PlayState._spawnTimer = 0 PlayState._spawnInterval = 2.5 resetSpawnTimer () final

API-ul newText este simplu: display.newText ("textul de afișat", poziția x, poziția y, fontul, mărimea). "PlayState._scoreText: setTextColor (89, 113, 55)" stabilește doar culoarea de umplere la aceeași culoare verde cu gloanțele. Tot ce avem nevoie acum este să actualizăm scorul în overlapAlienBullet ():

 () Strălucire () Strălucire Strălucire Strălucire Strălucire Strălucire Strălucire Strălucire Strălucire Strălucire Strălucire

Acest lucru adaugă pur și simplu 1 la proprietatea _score atunci când un străin este ucis de un glonț. Apoi modifică proprietatea textului _scoreText la valoarea scorului.

Joc încheiat

Înainte de a încheia acest joc, avem nevoie de o resetare. În acest fel, utilizatorul poate începe din nou când mor. Va trebui să facem acest lucru în două etape. În primul rând, trebuie să oprim tot ce poate controla utilizatorul de îndată ce nava moare. Apoi, trebuie să restabilim totul în momentul în care utilizatorul pune la dispoziție un nou joc.

Să dezactivați toate butoanele din funcția overlapAlienShip (). De asemenea, să eliminăm proprietatea navei. Putem face acest lucru prin setarea tuturor valorilor la zero.

 suprapusAlienShip (străin, navă) -: void ship: kill () străin: kill () media.playEventSound (PlayState.SoundExplosionShip) PlayState._inGame = false PlayState._ship = null PlayState._upButton.onPress = null PlayState._upButton. onRelease = nil PlayState._downButton.onPress = nil PlayState._downButton.onRelease = nil PlayState._leftButton.onPress = nil PlayState._leftButton.onRelease = nil PlayState._rightButton.onPress = nil PlayState._rightButton.onRelease = nil PlayState._shootButton.onPress = nil PlayState._shootButton.onRelease = nil --_ jocOverText = nou FlxText (0, FlxG.height / 2, FlxG.width, "GAME OVER \ nPRESS ENTER pentru a juca din nou") --_ gameOverText.setFormat (null, 16, 0xFF597137 , "center") --add (_gameOverText) sfârșitul

Acest cod doar atribuie toate valorile onPress și onRelease la zero. Butoanele vor continua
afișare, dar nu vor apela niciun cod când este apăsat.

Joc peste mesaj

Acum vedem că funcția inițială overlapAlienShip () a afișat o etichetă de text pentru a spune utilizatorului că jocul sa terminat. Vom face același lucru. În primul rând, dezactivați proprietatea _gameOverText în funcția create ().

 create function () -: void - declarații variabile PlayState._inGame = true PlayState._ship = nil PlayState._ship = nil PlayState._aliens = nil PlayState._bullets = nil PlayState._score = nil PlayState._scoreText = nil PlayState._gameOverText = nil PlayState._spawnTimer = nil PlayState._spawnInterval = 2.5 PlayState.SoundExplosionShip = nil PlayState.SoundExplosionAlien = nil PlayState.SoundBullet = zero? Sfârșit

Înapoi în overlapAlienShip (), trebuie să înlocuim codul comentat cu aceste linii.

 suprapusAlienShip (străin, navă) -: void ship: kill () străin: kill () media.playEventSound (PlayState.SoundExplosionShip) PlayState._inGame = false PlayState._ship = null PlayState._upButton.onPress = null PlayState._upButton. onRelease = nil PlayState._downButton.onPress = nil PlayState._downButton.onRelease = nil PlayState._leftButton.onPress = nil PlayState._leftButton.onRelease = nil PlayState._rightButton.onPress = nil PlayState._rightButton.onRelease = nil PlayState._shootButton.onPress = nil PlayState._shootButton.onRelease = nil PlayState._gameOverText = display.newText ("Joc peste TAP pentru a juca din nou", 35, display.contentHeight / 2 - 50, nil, 16) PlayState._gameOverText: setTextColor (89, 55) sfârșit

Acesta este același cod pe care l-am folosit pentru a crea și a completa textul scorului. Poziția este schimbată pentru a centra textul de pe ecran, iar textul spune "TAP TO PLAY AGAIN" în loc de "PRESS ENTER TO PLAY AGAIN".

Adăugați o melodie de ascultare

Din moment ce vom fi bate pentru a reporni jocul, trebuie să adăugăm un nou ascultător al evenimentului. Putem face acest lucru la fel cum am adăugat ascultătorul enterFrame, dar de această dată evenimentul pe care îl ascultăm este "atingeți". De asemenea, trebuie să adăugăm o funcție pentru a asculta ascultătorul. În partea de jos a suprapuneAlienShip () adăugați acest ascultător al evenimentului:

 suprapusAlienShip (străin, navă) -: void ship: kill () străin: kill () media.playEventSound (PlayState.SoundExplosionShip) PlayState._inGame = false PlayState._ship = null PlayState._upButton.onPress = null PlayState._upButton. onRelease = nil PlayState._downButton.onPress = nil PlayState._downButton.onRelease = nil PlayState._leftButton.onPress = nil PlayState._leftButton.onRelease = nil PlayState._rightButton.onPress = nil PlayState._rightButton.onRelease = nil PlayState._shootButton.onPress = nil PlayState._shootButton.onRelease = nil PlayState._gameOverText = display.newText ("Joc peste TAP pentru a juca din nou", 35, display.contentHeight / 2 - 50, nil, 16) PlayState._gameOverText: setTextColor (89, 55) Runtime: addEventListener ("atingeți", atingeți) sfârșit

Acest cod verifică un buton oriunde pe ecran. Când apare o apăsare, aceasta apelează funcția atingeți (). Să facem o funcțiune de atingere goală () pentru ca aceasta să sune. Puneți-l chiar deasupra create ().

? funcția atingeți (eveniment) - avem nevoie doar de acest lucru ca un substituent pentru funcția end end create ()? Sfârșit

Curățând totul

Să facem o funcție remove () pentru a face față curățării tuturor obiectelor de joc. Puneți această funcție peste noua funcție de atingere ().

? remove function () - capătul funcției atingeți (eveniment) - avem nevoie doar de acest lucru ca un substituent pentru funcția end end create ()? Sfârșit

Eliminarea obiectelor și a grupurilor de afișare

Pentru a începe, ar trebui să ucidem toți străinii și gloanțele rămase. Pentru a face acest lucru, putem pur și simplu să bucle prin grupurile de afișare respective. Acesta este modul potrivit de a elimina obiectele din Corona:

 funcția remove () pentru i = PlayState._bullets.numChildren, 1, -1 do PlayState._bullets [i]: kill () sfârșit pentru i = PlayState._aliens.numChildren, 1, -1 nu PlayState._aliens [i]: killState._bullets: removeSelf () PlayState._bullets = nil PlayState._aliens: removeSelf () PlayState._aliens = Sfârșitul nilului

Aceste bucle funcționează într-un mod special. Fiecare buclă începe cu "i" setată la ultimul obiect din grupurile de afișare. Apoi bucla omoară obiectul și scade 1 din "i". Bucla se repetă până când "i" este egală cu 1. Motivul pentru care scădem din "i" este faptul că de fiecare dată când omorăm un obiect, acesta se elimină din grupul de afișare. Aceasta înseamnă că există un obiect mai puțin în grupul de afișare. Dacă trebuia să adăugăm 1 la "i", am ajunge să sunăm kill () pe obiecte care nu mai există. Pentru a repara acest lucru, numărăm înapoi ori de câte ori eliminăm un obiect.

După eliminarea tuturor obiectelor din grupuri, eliminăm grupurile. De asemenea, setăm proprietățile care au ținut grupurile la zero. Acum ele pot fi folosite din nou.

Variații de eliminare a colectorului de gunoi

Să setăm toate variabilele folosite la zero. În acest fel, colectorul de gunoi poate elibera memoria. Acest lucru va asigura, de asemenea, ca toate variabilele să fie resetate înainte de a începe un nou joc. Îndepărtați mai întâi toate butoanele:

 funcția remove () pentru i = PlayState._bullets.numChildren, 1, -1 do PlayState._bullets [i]: kill () sfârșit pentru i = PlayState._aliens.numChildren, 1, -1 nu PlayState._aliens [i]: killState._bullet: removeSelf () PlayState._bullets = nil PlayState._aliens: removeSelf () PlayState._aliens = nil PlayState._upButton: removeSelf () PlayState._upButton = nula PlayState._downButton: removeSelf () PlayState._downButton = nil PlayState._leftButton: removeSelf () PlayState._leftButton = zero PlayState._rightButton: removeSelf () PlayState._rightButton = nul PlayState._shootButton: removeSelf () PlayState._shootButton = sfârșitul nil

Trebuie să le eliminăm mai întâi de pe ecran și apoi să le setăm la zero. Să avem grijă de sunetele noastre acum.

 funcția remove () pentru i = PlayState._bullets.numChildren, 1, -1 do PlayState._bullets [i]: kill () sfârșit pentru i = PlayState._aliens.numChildren, 1, -1 nu PlayState._aliens [i]: killState._bullet: removeSelf () PlayState._bullets = nil PlayState._aliens: removeSelf () PlayState._aliens = nil PlayState._upButton: removeSelf () PlayState._upButton = nula PlayState._downButton: removeSelf () PlayState._downButton = zero PlayState._leftButton: removeSelf () PlayState._leftButton = nil PlayState._rightButton: removeSelf () PlayState._rightButton = nul PlayState._shootButton: removeSelf () PlayState._shootButton = nul PlayState.SoundExplosionShip = nil PlayState.SoundExplosionAlien = PlayState nul. SoundBullet = capăt zero

Acum obiectele noastre text:

 funcția remove ()? PlayState._scoreText: removeSelf () PlayState._scoreText = nul PlayState._gameOverText: removeSelf () PlayState._gameOverText = sfârșitul nil

Eliminarea ascultătorilor de evenimente

Pentru a termina curățarea, trebuie să eliminăm ascultătorii evenimentului. După aceasta, putem restabili în final PlayState la o matrice goală:

 funcția remove ()? Runtime: removeEventListener ("enterFrame", actualizare) Runtime: removeEventListener ("apăsați", atingeți) PlayState = null PlayState =  end

Repornirea jocului

Repornirea jocului este la fel de simplă ca și eliminarea () și apoi crearea () în funcția noastră de atingere ().

 funcția atinge (eveniment) șterge () crea () sfârșit

Finalizări finale

Suntem aproape gata. Trebuie doar să punem câteva sfaturi finale. Începeți prin eliminarea tuturor liniilor comentate din codul sursă vechi. Acest lucru va curăța fișierele noastre până la o tonă.

Activarea funcției Multitouch

O altă optimizare rapidă pe care o putem face este să activați multitouch-ul. Nu veți observa schimbarea pe simulator, dar este frumos să puteți apăsa mai multe butoane simultan pe dispozitivul propriu. Aceasta este o ajustare cu o singură linie. Trebuie doar să se întâmple o singură dată, deci să o adăugăm în fișierul principal.lua.

 playState = () PlayState.PlayState () end () Main () sistem.activate ("multitouch") display.setStatusBar (display.HiddenStatusBar)

Modificarea Bibliotecii UI pentru a se potrivi nevoilor noastre

De asemenea, aveam probleme cu modulul ui.lua. Butoanele nu contează tragerea degetului de pe dispozitiv, o eliberare, cu excepția cazului în ultimul loc atins a fost butonul. Acest lucru nu funcționează întotdeauna în mod corespunzător pentru acest joc particular și uneori nava se va mișca singură, deoarece funcția de lansare nu este apelată. A fost o rezolvare simplă. Am scos verificarea pentru a vedea dacă butonul era apăsat atunci când degetul utilizatorilor a fost eliberat. Acest lucru însemna doar comentarea afirmațiilor dacă și sfârșitul liniilor 91 și 98.

? dacă "a terminat" = = faza atunci - Considerați doar un "clic" dacă utilizatorul își ridică degetul în interiorul butonului stageBounds - ifWithinBounds atunci ifEvent apoi buttonEvent.phase = "release" result = onEvent (buttonEvent) elseif onRelease rezultatul = onRelease (eveniment) end - end? 

Aceste modificări sunt incluse în fișierul ui.lua inclus în acest tutorial.

Concluzie

Suntem terminati. Acum avem o replică completă a jocului flash original. Avem o navă care se mișcă, focuri, extratereștri și un sistem de scoruri. Jocul gestionează memoria tuturor obiectelor și are capacitatea de a reseta și de a începe din nou. Altele decât sistemul de particule, acest joc este un port identic. Acum, că ați terminat acest tutorial, trebuie să aveți cunoștințe suficiente pentru a porni aproape orice joc flash / actionscript pe iPhone.

Exerciții și caracteristici suplimentare

O mulțime de dezvoltatori doresc să adauge funcționalitate sau să schimbe modul de joc un pic când portează un joc pe un dispozitiv mobil. Aș dori să vă provoc să îmbunătățiți / modificați acest joc pentru a deveni mai mult ca o aplicație reală. Puteți schimba schema de control la oricare dintre tipurile despre care am vorbit în lecția 2. Puteți crea un meniu cu setări sau mai multe nivele. Puteți adăuga diferite tipuri de dușmani. Puteți adăuga un sistem de scoruri local sau online. Posibilitățile sunt nesfârșite. Din fericire, Corona face dezvoltarea foarte rapidă și foarte liniștită. Sper că v-ați bucurat de acest tutorial și, mai important, ați învățat multe. Lasă un comentariu de mai jos pentru a ne spune cum au mers lucrurile.

Cod