Crea un gioco di combattimento aereo in Corona più gioco

Cosa starai creando

introduzione

Nel tutorial precedente di questa serie, abbiamo iniziato a implementare il gameplay del gioco e siamo già riusciti a far muovere l'aereo sullo schermo. In questo tutorial, continueremo ad implementare il gameplay. Facciamo un tuffo proprio con il startTimers funzione.

1. startTimers

Come indica il nome, il startTimers la funzione avvia i timer. Aggiungere il seguente codice a gamelevel.lua.

funzione startTimers () end

Invoca questa funzione nel enterScene metodo come mostrato di seguito.

function scene: enterScene (evento) local planeSound = audio.loadStream ("planesound.mp3") planeSoundChannel = audio.play (planeSound, loops = -1) Runtime: addEventListener ("enterFrame", gameLoop) startTimers () fine

2. firePlayerBullet

Il firePlayerBullet la funzione crea un proiettile per il giocatore.

function firePlayerBullet () local tempBullet = display.newImage ("bullet.png", (player.x + playerWidth / 2) - bulletWidth, player.y-bulletHeight) table.insert (playerBullets, tempBullet); planeGroup: inserire (tempBullet) end 

Qui usiamo l'oggetto Display nuova immagine metodo per creare il proiettile. Lo posizioniamo in modo tale che si trovi al centro del piano sull'asse x e nella parte superiore del piano sull'asse y. Il proiettile viene quindi inserito nel playerBullets tavolo per riferimento futuro e anche nel planeGroup.

3. Chiamare firePlayerBullet

Dobbiamo chiamare il firePlayerBullet funzione periodicamente per assicurarsi che l'aereo del giocatore stia sparando automaticamente proiettili. Aggiungi il seguente snippet di codice nel file startTimers funzione.

function startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) end

Come indica il nome, il timer performWithDelay il metodo richiama una funzione specificata dopo che è trascorso un periodo di tempo. Il tempo è in millisecondi, quindi qui stiamo chiamando il firePlayerBullet funzione ogni due secondi. Passando -1 come terzo argomento, il timer si ripeterà per sempre.

Se stai testando il gioco ora, dovresti vedere che ogni due secondi appare un proiettile. Tuttavia, non si stanno ancora muovendo. Ci prenderemo cura di ciò nei prossimi passi.

4. movePlayerBullets

Nel movePlayerBullets, passiamo attraverso il playerBullets tavolo e cambia il y coordinata di ogni proiettile. Per prima cosa controlliamo per accertarci che playerBullets la tabella contiene proiettili. Il # prima playerBullets è chiamato il lunghezza operatore e restituisce la lunghezza dell'oggetto su cui è chiamato. È utile sapere che il # l'operatore lavora anche sulle stringhe.

function movePlayerBullets () if (#playerBullets> 0) quindi per i = 1, # playerBullets do playerBullets [i]. y = playerBullets [i] .y - 7 end end end

Dobbiamo invocare movePlayerBullets nel gameLoop funzione come mostrato di seguito.

function gameLoop () --SNIP-- numberOfTicks = numberOfTicks + 1 movePlayer () movePlayerBullets () end

5. checkPlayerBulletsOutOfBounds

Quando un proiettile va fuori campo, non è più rilevante per il gioco. Tuttavia, fanno ancora parte del playerBullets tabella e continuare a muoversi come qualsiasi altro proiettile nella tabella. Questo è uno spreco di risorse e, se il gioco dovesse durare a lungo, risulterebbe in centinaia o migliaia di oggetti non utilizzati.

Per ovviare a ciò, monitoriamo i proiettili e, una volta spostati fuori dallo schermo, li rimuoviamo dal playerBullets tavolo così come dal display. Dai un'occhiata all'implementazione di checkPlayerBulletsOutOfBounds.

function checkPlayerBulletsOutOfBounds () if (#playerBullets> 0) quindi per 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

È importante notare che stiamo scorrendo attraverso il playerBullets tavolo all'indietro. Se eseguiamo il ciclo di inoltro della tabella, quando rimuoviamo uno dei proiettili, l'indice di looping viene eliminato e causa un errore. Eseguendo il ciclo sulla tabella in ordine inverso, l'ultimo punto è già stato elaborato. Il removeSelf metodo rimuove l'oggetto di visualizzazione e libera la sua memoria. Come best practice, dovresti impostare qualsiasi oggetto zero dopo aver chiamato removeSelf.

Invochiamo questa funzione nel gameLoop funzione.

function gameLoop () --SNIP-- movePlayer () movePlayerBullets () checkPlayerBulletsOutOfBounds () end

Se vuoi vedere se questa funzione funziona correttamente, puoi inserire temporaneamente un print ("Rimozione del proiettile") dichiarazione immediatamente dopo l'impostazione dell'oggetto di visualizzazione zero.

6. generateIsland

Per rendere il gioco più interessante, generiamo un'isola ogni tanto, e spostiamolo lungo lo schermo per dare l'aspetto dell'aereo che sorvola le isole. Aggiungi il seguente snippet di codice per generateIsland funzione.

function generateIsland () local tempIsland = display.newImage ("island1.png", math.random (0, display.contentWidth - islandWidth), - islandHeight) table.insert (isole, tempIsland) islandGroup: insert (tempIsland) end

Facciamo uso del nuova immagine metodo ancora una volta e posizionare l'isola impostando un valore negativo per il islandHeight. Per il X posizione, usiamo il Math.random metodo per generare un numero tra 0 e il display'S contentWidth meno il islandWidth. Il motivo per cui sottrarre la larghezza dell'isola è assicurarsi che l'isola sia completamente sullo schermo. Se non volessimo sottrarre la larghezza dell'isola, ci sarebbe la possibilità che parte dell'isola non sia sullo schermo.

Abbiamo bisogno di avviare un timer per generare un'isola ogni tanto. Aggiungi il seguente snippet al startTimers funzione che abbiamo creato in precedenza. Come puoi vedere, stiamo generando un'isola ognicinque secondi. Nel prossimo passo, faremo muovere le isole.

function startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) generateIslandTimer = timer.performWithDelay (5000, generateIsland, -1) fine

7. moveIslands

L'implementazione di moveIslands è quasi identico al movePlayerBullets funzione. Controlliamo se il isole il tavolo contiene alcune isole e, se lo fa, lo attraversiamo e spostiamo ogni isola un po '.

function moveIslands () if (#islands> 0) quindi per i = 1, #islands do isole [i] .y = isole [i] .y + 3 end end end

8. checkIslandsOutOfBounds

Proprio come controlliamo se i proiettili del giocatore sono stati spostati fuori dallo schermo, controlliamo se una delle isole si è spostata fuori dallo schermo. L'implementazione di checkIslandsOutOfBounds dovrebbe quindi sembrarti familiare. Controlliamo se le isole y la posizione è maggiore di display.contentHeight e se lo è, sappiamo che l'isola è stata spostata fuori dallo schermo e può quindi essere rimossa.

function checkIslandsOutOfBounds () if (#islands> 0) quindi per i = # isole, 1, -1 do if (isole [i] .y> display.contentHeight) quindi isole [i]: removeSelf () isole [i] = nil table.remove (isole, i) fine fine fine

9. generateFreeLife

Ogni tanto, il giocatore ha la possibilità di ottenere una vita libera. Per prima cosa generiamo un'immagine di vita libera e se il giocatore collide con l'immagine ottiene una vita extra. Il giocatore può avere un massimo di sei vite.

function generateFreeLife () if (numberOfLives> = 6) quindi restituisce end local freeLife = display.newImage ("newlife.png", math.random (0, display.contentWidth - 40), 0); table.insert (freeLifes, freeLife) planeGroup: insert (freeLife) end 

Se il giocatore ha già sei vite, non facciamo nulla ritornando presto dalla funzione. In caso contrario, creiamo una nuova immagine di vita e la aggiungiamo allo schermo. Simile a come abbiamo posizionato le isole in precedenza, abbiamo impostato l'immagine su un valore negativo y posiziona e genera un valore casuale per l'immagine X posizione. Quindi lo inseriamo nel freeLifes tavolo per poterlo consultare più tardi.

Dobbiamo chiamare questa funzione ogni tanto. Aggiungi il seguente snippet al startTimers funzione.

function startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) generateIslandTimer = timer.performWithDelay (5000, generateIsland, -1) generateFreeLifeTimer = timer.performWithDelay (7000, generateFreeLife, - 1) fine

10. moveFreeLives

L'implementazione di moveFreeLifes dovrebbe sembrare familiare Stiamo collegando il freeLifes tabella e spostare ogni immagine in esso.

function moveFreeLifes () if (#freeLifes> 0) quindi per i = 1, # freeLifes do freeLifes [i] .y = freeLifes [i] .y +5 end end end

Tutto ciò che dobbiamo fare è chiamare moveFreeLifes nel gameLoop funzione.

function gameLoop () --SNIP-- checkIslandsOutOfBounds () moveFreeLifes () fine

11. checkFreeLifesOutOfBounds

Il seguente frammento di codice dovrebbe anche sembrarti familiare. Controlliamo se una qualsiasi delle immagini nel freeLifes il tavolo si è spostato fuori dallo schermo e rimuove quelli che lo hanno.

function checkFreeLifesOutOfBounds () if (#freeLifes> 0) quindi per i = # freeLifes, 1, -1 do if (freeLifes [i] .y> display.contentHeight) quindi freeLifes [i]: removeSelf () freeLifes [i] = nil table.remove (freeLifes, i) end end end end 

Chiamiamo questa funzione nel gameLoop funzione.

function gameLoop () --SNIP-- checkIslandsOutOfBounds () moveFreeLifes () checkFreeLifesOutOfBounds () fine

12. hasCollided

Dobbiamo essere in grado di dire quando gli oggetti del gioco si scontrano tra di loro, come il piano del giocatore e le immagini della vita libera, i proiettili e gli aerei, ecc. Mentre Corona offre un motore fisico molto robusto che può gestire facilmente le collisioni tra gli oggetti di visualizzazione per noi, fare così aggiunge un po 'di overhead con i calcoli che il motore deve fare ogni frame.

Ai fini di questo gioco, utilizzeremo un semplice sistema di rilevamento delle collisioni. Che cosa fa questa funzione, assicurati che i rettangoli o le caselle di delimitazione attorno a due oggetti non si sovrappongano. Se lo fanno, gli oggetti si scontrano. Questa logica è implementata nel hasCollided funzione.

function hasCollided (obj1, obj2) if (obj1 == nil) quindi restituisce false end if (obj2 == nil) quindi restituisce false end local left = obj1.contentBounds.xMin <= obj2.contentBounds.xMin and obj1.contentBounds.xMax >= obj2.contentBounds.xMin right locale = obj1.contentBounds.xMin> = obj2.contentBounds.xMin e 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 e obj1.contentBounds.yMin <= obj2.contentBounds.yMax return (left or right) and (up or down) end

Ho trovato questo snippet di codice sul sito web di CoronaLabs. Funziona molto bene, perché gli oggetti del gioco nel nostro gioco sono rettangolari. Se stai lavorando con oggetti che non sono rettangolari, allora è meglio sfruttare il motore fisico di Corona poiché il rilevamento delle collisioni è ottimizzato molto bene per questo.

13. checkPlayerCollidesWithFreeLife

Vogliamo verificare se l'aereo del giocatore si è scontrato con un oggetto di vita libero. Se è così, assegniamo al giocatore una vita libera.

function checkPlayerCollidesWithFreeLife () if (#freeLifes> 0) quindi per i = # freeLifes, 1, -1 do if (hasCollided (freeLifes [i], player)) then freeLifes [i]: removeSelf () freeLifes [i] = nil table.remove (freeLifes, i) numberOfLives = numberOfLives + 1 hideLives () showLives () fine fine fine fine

Nel checkPlayerCollidesWithFreeLife funzione, passiamo attraverso il freeLives tabella indietro per la stessa ragione che ho descritto in precedenza. Chiamiamo il hasCollided funzione e passa nell'immagine corrente e nel piano del giocatore. Se i due oggetti si scontrano, rimuoviamo l'immagine di vita libera, incrementiamo il numberOfLives variabile e chiama il hideLives e showLives funzione.

Invochiamo questa funzione nel gameLoop funzione.

function gameLoop () --SNIP-- moveFreeLifes () checkFreeLifesOutOfBounds () checkPlayerCollidesWithFreeLife () fine

14. hideLives

Il hideLives la funzione scorre attraverso il livesImages tavolo e imposta il è visibile proprietà di ogni immagine di vita a falso.

function hideLives () per i = 1, 6 do livesImages [i] .isVisible = false end end 

15. showLives

Il showLives la funzione scorre attraverso il livesImages tabella e imposta ogni immagine è visibile proprietà a vero.

function showLives () per i = 1, numberOfLives do livesImages [i] .isVisible = true; fine fine

Conclusione

Ciò porta alla conclusione la terza parte di questa serie. Nella prossima e ultima puntata di questa serie, creeremo aerei nemici e finalizzeremo il gameplay del gioco. Grazie per aver letto e ci vediamo lì.