În tutorialul precedent al acestei serii, am început să implementăm gameplay-ul jocului și deja am reușit să ajungem în avion pe ecran. În acest tutorial vom continua implementarea gameplay-ului. Hai să ne aruncăm cu ochii startTimers
funcţie.
startTimers
După cum indică și numele, startTimers
Funcția pornește cronometrele. Adăugați următorul cod la gamelevel.lua.
funcția startTimers () sfârșit
Invocați această funcție în enterScene
așa cum se arată mai jos.
Functia scena: enterScene (eveniment) planul localSound = audio.loadStream (planesound.mp3) planeSoundChannel = audio.play (planeSound, loops = -1) Runtime: endEndList (endFrame, gameLoop)
firePlayerBullet
firePlayerBullet
funcția creează un glonț pentru player.
funcția firePlayerBullet () local tempBullet = display.newImage ("bullet.png", (player.x + playerWidth / 2) - bulletWidth, player.y-bulletHeight) table.insert (playerBullets, tempBullet); planeGroup: introduceți (tempBullet) sfârșitul
Aici folosim Obiectul de afișare imagine noua
metodă pentru a crea gloanțele. Poziționăm-o astfel încât să se afle în centrul planului pe axa x și chiar în partea superioară a planului pe axa y. Glonțul este apoi introdus în playerBullets
tabel pentru referință ulterioară și, de asemenea, în planeGroup
.
firePlayerBullet
Trebuie să sunăm firePlayerBullet
funcția periodică pentru a vă asigura că avionul jucătorului trage automat gloanțele. Adăugați următorul fragment de cod în startTimers
funcţie.
funcția startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) sfârșit
După cum indică numele său, cronometrele performWithDelay
metoda solicită o funcție specificată după o perioadă de timp. Timpul este în milisecunde, deci sunăm aici firePlayerBullet
funcționează la fiecare două secunde. Trecând -1
ca al treilea argument, cronometrul se va repeta pentru totdeauna.
Dacă încercați acum jocul, ar trebui să vedeți că la fiecare două secunde apare un glonț. Cu toate acestea, încă nu se mișcă. Vom avea grijă de asta în următorii pași.
movePlayerBullets
În movePlayerBullets
, ne bucle prin playerBullets
și schimbați tabelul y
coordonează fiecare glonț. Mai întâi verificăm să vă asigurați că playerBullets
tabelul conține gloanțe în el. #
inainte de playerBullets
este numit lungime operator și returnează lungimea obiectului la care este chemat. Este util să știți că #
operatorul funcționează și pe șiruri de caractere.
funcția movePlayerBullets () dacă (#playerBullets> 0) atunci pentru i = 1, # playerBullets face playerBullets [i]. y = playerBullets [i] .y - 7 end end end
Trebuie să invocăm movePlayerBullets
în gameLoop
după cum se arată mai jos.
funcția gameLoop () --SNIP-- numberOfTicks = numărOfTicks + 1 movePlayer () movePlayerBullets () end
checkPlayerBulletsOutOfBounds
Atunci când un glonț scade din ecran, acesta nu mai este relevant pentru joc. Cu toate acestea, ei încă fac parte din playerBullets
și continuați să vă deplasați ca orice alt glonț din tabel. Aceasta este o risipă de resurse și, dacă jocul urma să dureze mult timp, ar avea ca rezultat sute sau mii de obiecte neutilizate.
Pentru a depăși acest lucru, monitorizăm gloanțele și, odată ce se îndepărtează de pe ecran, le eliminăm din playerBullets
precum și de pe afișaj. Aruncați o privire la punerea în aplicare a checkPlayerBulletsOutOfBounds
.
funcția checkPlayerBulletsOutOfBounds () dacă (#playerBullets> 0) atunci pentru i = # playerBullets, 1, -1 do if (playerBullets [i] .y < -18) then playerBullets[i]:removeSelf() playerBullets[i] = nil table.remove(playerBullets,i) end end end end
Este important să rețineți că ne întoarcem prin playerBullets
masa înapoi. Dacă vom bifa masa înainte, atunci când vom elimina unul dintre gloanțe, vom arunca indicele de bucle și vom cauza o eroare. Prin rularea peste masă în ordine inversă, ultimul glonț este deja procesat. removeSelf
metoda elimină obiectul afișat și își eliberează memoria. Ca o bună practică, ar trebui să setați orice obiecte zero
după ce a sunat removeSelf
.
Invocăm această funcție în gameLoop
funcţie.
funcția gameLoop () --SNIP - movePlayer () movePlayerBullets () checkPlayerBulletsOutOfBounds () sfârșit
Dacă doriți să vedeți dacă această funcție funcționează corect, puteți introduce temporar a print ("Scoaterea Bullet")
imediat după ce ați setat obiectul de afișare la zero
.
generateIsland
Pentru a face jocul mai interesant, generăm o insulă atât de des și o mutați pe ecran pentru a da aspectul avionului care zboară peste insule. Adăugați următorul fragment de cod pentru generateIsland
funcţie.
funcția generateIsland () local tempIsland = display.newImage ("island1.png", math.random (0, display.contentWidth - islandWidth), - islandHeight) table.insert (insulă, tempIsland) islandGroup:
Folosim imagine noua
din nou, și poziționați insula stabilind o valoare negativă pentru islandHeight
. Pentru X
poziție, vom folosi math.random
pentru a genera un număr între 0
si afişa
„s contentWidth
minus islandWidth
. Motivul pentru care scădem lățimea insulei este să ne asigurăm că insula este complet pe ecran. Dacă nu am scădea lățimea insulei, ar fi o șansă ca o parte a insulei să nu fie pe ecran.
Trebuie să începem un cronometru pentru a genera o insulă atât de des. Adăugați fragmentul următor în startTimers
pe care am creat-o mai devreme. După cum puteți vedea, noi generăm o insulă în fiecarecinci secunde. În pasul următor, vom face ca insulele să se miște.
Funcția startTimers () firePlayerBulletTimer = Timer.performWithDelay (2000, firePlayerBullet, -1) generateIslandTimer = Timer.performWithDelay (5000, generateIsland, -1) Sfârșit
moveIslands
Implementarea sistemului moveIslands
este aproape identică cu movePlayerBullets
funcţie. Verificăm dacă Insulele
tabelul conține orice insulă și, dacă se întâmplă, o facem prin ea și o mutăm pe fiecare insulă.
funcția moveIslands () dacă (#islands> 0) atunci pentru i = 1, #islands do inslands [i] .y = insule [i] .y + 3 end end end
checkIslandsOutOfBounds
Așa cum verificăm dacă gloanțele jucătorului s-au mutat off-screen, verificăm dacă vreunul dintre insule sa mutat off-screen. Implementarea sistemului checkIslandsOutOfBounds
ar trebui, prin urmare, să vă arătați familiar. Verificăm dacă insulele y
poziția este mai mare decât display.contentHeight
și dacă este, știm că insula sa mutat off-screen și, prin urmare, poate fi eliminată.
funcția checkIslandsOutOfBounds () dacă (#islands> 0), atunci pentru i = # insule, 1, -1 dacă (insulele [i] .y> display.contentHeight), apoi insulele [i]: removeSelf () nil table.remove (insule, i) end end end end
generateFreeLife
Atât de des, jucătorul are șansa de a obține o viață liberă. Mai întâi generăm o imagine a vieții libere și, dacă jucătorul se ciocnește cu imaginea, primește o viață suplimentară. Jucătorul poate avea maximum șase vieți.
funcția generateFreeLife () dacă (numberOfLives> = 6) apoi returnați sfârșitul localului freeLife = display.newImage ("newlife.png", math.random (0, display.contentWidth - 40), 0); table.insert (freeLifes, freeLife) planGroup: introduceți (freeLife) sfârșitul
Dacă jucătorul are deja șase vieți, nu facem nimic returnându-ne devreme din funcție. Dacă nu, vom crea o nouă imagine de viață și o vom adăuga pe ecran. Similar cu modul în care am poziționat insulele mai devreme, am stabilit imaginea negativă y
poziția și generează o valoare aleatorie pentru imaginea respectivă X
poziţie. Apoi îl inserăm în freeLifes
tabel pentru a putea face referire mai târziu.
Trebuie să numim această funcție atât de des. Adăugați fragmentul următor în startTimers
funcţie.
Funcția startTimers () FirePlayerBulletTimer = Timer.performWithDelay (2000, FirePlayerBullet, -1) generateIslandTimer = Timer.performWithDelay (5000, generateIsland, -1) generateFreeLifeTimer = Timer.performWithDelay (7000, generateFreeLife,
moveFreeLives
Implementarea sistemului moveFreeLifes
ar trebui să arate familiar. Ne întoarcem prin freeLifes
și mutați fiecare imagine în ea.
funcția moveFreeLifes () dacă (#freeLifes> 0) atunci pentru i = 1, # freeLifes do freeLifes [i] .y = freeLifes [i] .y +5 end end end
Tot ce trebuie să facem este să sunăm moveFreeLifes
în gameLoop
funcţie.
funcția gameLoop () --SNIP-- checkIslandsOutOfBounds () moveFreeLifes () end
checkFreeLifesOutOfBounds
Următorul fragment de cod ar trebui, de asemenea, să vă pară cunoscut până acum. Verificăm dacă oricare dintre imaginile din freeLifes
masa s-au mutat off-screen și eliminați cele care au.
funcția checkFreeLifesOutOfBounds () dacă (#freeLifes> 0), atunci pentru i = # freeLifes, 1, -1 face dacă (freeLifes [i] .y> display.contentHeight) apoi freeLifes [i]: removeSelf nil table.remove (freeLifes, i) sfârșitul capătului final
Noi numim această funcție în gameLoop
funcţie.
funcția gameLoop () --SNIP-- checkIslandsOutOfBounds () moveFreeLifes () checkFreeLifesOutOfBounds () sfârșit
hasCollided
Trebuie să putem spune când obiectele jocului se ciocnesc unul cu celălalt, cum ar fi avionul jucătorului și imaginile de viață liberă, gloanțele și avioanele etc. În timp ce Corona oferă un motor de fizică foarte robust, care poate manipula cu ușurință coliziunile dintre obiectele afișate pentru noi, acest lucru adaugă un pic de overhead cu calculele motorul trebuie să facă fiecare cadru.
În scopul acestui joc, vom folosi un sistem simplu de detectare a coliziunii caseta delimitată. Ce face această funcție este să vă asigurați că dreptunghiurile sau casetele de margine din jurul a două obiecte nu se suprapun. Dacă o fac, obiectele se ciocnesc. Această logică este implementată în hasCollided
funcţie.
funcția hasCollided (obj1, obj2) dacă (obj1 == nil), apoi întoarceți capătul false dacă (obj2 == nil) apoi întoarceți false end local local left = obj1.contentBounds.xMin <= obj2.contentBounds.xMin and obj1.contentBounds.xMax >= obj2.contentBounds.xMin drept local = obj1.contentBounds.xMin> = obj2.contentBounds.xMin și obj1.contentBounds.xMin <= obj2.contentBounds.xMax local up = obj1.contentBounds.yMin <= obj2.contentBounds.yMin and obj1.contentBounds.yMax >= obj2.contentBounds.yMin local down = obj1.contentBounds.yMin> = obj2.contentBounds.yMin și obj1.contentBounds.yMin <= obj2.contentBounds.yMax return (left or right) and (up or down) end
Am găsit acest fragment de cod pe site-ul CoronaLabs. Funcționează foarte bine, deoarece obiectele de joc din jocul nostru sunt rectangulare. Dacă lucrați cu obiect care nu este dreptunghiular, atunci ar fi bine să profitați de motorul de fizică al Corona, deoarece detectarea coliziunii sale este foarte bine optimizată pentru aceasta.
checkPlayerCollidesWithFreeLife
Vrem să verificăm dacă avionul jucătorului sa ciocnit cu un obiect de viață liberă. Dacă are, atunci îi acordăm jucătorului o viață liberă.
()), dacă pentru (i) = freeLifes, 1, -1, dacă (aCollided (freeLifes [i], player)) freeLifes [i]: removeSelf table.remove (freeLifes, i) numberOfLives = numărOfLivi + 1 hideLives () showLives () end end end end
În checkPlayerCollidesWithFreeLife
funcția, ne bucle prin freeLives
tabelul înapoi din același motiv pe care l-am descris mai devreme. Noi numim hasCollided
funcția și treceți în imaginea curentă și în planul jucătorului. Dacă ambele obiecte se ciocnesc, eliminăm imaginea de viață liberă, incrementăm numberOfLives
variabilă și apelați hideLives
și showLives
funcţie.
Invocăm această funcție în gameLoop
funcţie.
funcția gameLoop () --SNIP - moveFreeLifes () checkFreeLifesOutOfBounds () checkPlayerCollidesWithFreeLife () sfârșit
hideLives
hideLives
funcționează prin livesImages
tabel și stabilește este vizibil
proprietății fiecărei imagini de viață fals
.
funcția hideLives () pentru i = 1, 6 face lives_mages [i] .isvisible = end end false
showLives
showLives
funcționează prin livesImages
tabel și stabilește fiecare imagine este vizibil
proprietate la Adevărat
.
funcția showLives () pentru i = 1, numberOfLives livesImages [i] .isVisible = true; sfârșitul final
Aceasta aduce la sfârșit oa treia parte a acestei serii. În următoarea și ultima tranșă a acestei serii, vom crea avioane inamice și vom finaliza gameplay-ul jocului. Mulțumesc că ai citit și te-am văzut acolo.