Nella parte precedente di questa serie, abbiamo spostato la nave del giocatore, fatto muovere gli invasori e rilevato quando un proiettile giocatore ha colpito un invasore. In questa parte finale della serie, otterremo gli invasori che attaccano il giocatore, gestiscono i livelli e aggiungono l'abilità per il giocatore di morire.
Ogni tanto uno degli invasori spara un proiettile. Useremo un timer per realizzare questo. Aggiungere il seguente codice a gamelevel.lua.
function fireInvaderBullet () if (#invadersWhoCanFire> 0) then randomIndex locale = math.random (#invadersWhoCanFire) local randomInvader = invadersWhoCanFire [randomIndex] local tempInvaderBullet = display.newImage ("laser.png", randomInvader.x, randomInvader.y + invaderSize / 2) tempInvaderBullet.name = "invaderBullet" scene.view: insert (tempInvaderBullet) physics.addBody (tempInvaderBullet, "dynamic") tempInvaderBullet.gravityScale = 0 tempInvaderBullet.isBullet = true tempInvaderBullet.isSensor = true tempInvaderBullet: setLinearVelocity (0,400) table.insert (invaderBullets, tempInvaderBullet) else levelComplete () end end
In questa funzione, per prima cosa controlliamo se il invadersWhoCanFire
tabella ha almeno un elemento in esso. Se questo è il caso, eseguiamo il codice nella dichiarazione if. Altrimenti significa che il livello è finito e invochiamo il livello completato
funzione.
Ci sarà sempre almeno un invasore che può sparare un proiettile finché non uccidi l'ultimo invasore, a quel punto il invadersWhoCanFire
il tavolo sarà vuoto.
All'interno dell'istruzione if, generiamo un numero casuale randomIndex
a seconda di quanti oggetti ci sono in invadersWhoCanFire
tavolo. Quindi selezioniamo quell'elemento, randomInvader
, dal invadersWhoCanFire
tavolo.
Creiamo un'immagine bullet, diamo a nome
proprietà in modo che possiamo identificarlo in seguito, inserirlo nella scena e impostare le stesse proprietà che abbiamo fatto sul proiettile del giocatore. Infine, inseriamo il proiettile nel invaderBullets
tabella in modo che possiamo fare riferimento in seguito.
Ora dobbiamo impostare il timer. Aggiungi il seguente al scena: spettacolo
metodo.
function scene: show (event) if (phase == "did") then --SNIP-- Runtime: addEventListener ("collision", onCollision) invaderFireTimer = timer.performWithDelay (1500, fireInvaderBullet, -1) end end
Ogni 1500 millisecondi fireInvaderBullet
è invocato. Si noti che l'ultimo parametro che passiamo è -1
, il che significa che il timer si ripete per sempre. Ogni volta che crei un timer che si ripete per sempre, dovresti eventualmente cancellarlo. Lo facciamo nelscena: nascondere
funzione come mostrato di seguito.
function scene: hide (event) if (phase == "will") then --SNIP-- Runtime: removeEventListener ("collision", onCollision) timer.cancel (invaderFireTimer) end end
Come i proiettili del giocatore, i proiettili degli invasori si spostano fuori dallo schermo e continuano a muoversi, occupando una memoria preziosa. Per rimediare, li rimuoviamo proprio come abbiamo fatto con i proiettili del giocatore.
function checkInvaderBulletsOutOfBounds () if (#invaderBullets> 0) quindi per i = # invaderBullets, 1, -1 do if (invaderBullets [i] .y> display.contentHeight) quindi invaderBullets [i]: removeSelf () invaderBullets [i] = nil table.remove (invaderBullets, i) end end end end
Questo codice è molto simile al controllo se i proiettili del giocatore sono fuori limite, quindi non discuterò la sua implementazione in dettaglio.
Il passo successivo è quello di rilevare se il proiettile di un invasore ha colpito il giocatore. Aggiungi il seguente codice al onCollision
funzione.
function onCollision (event) if (event.phase == "begin") then --SNIP-- if (event.object1.name == "player" ed event.object2.name == "invaderBullet") then table.remove (invaderBullets, table.indexOf (invaderBullets, event.object2)) event.object2: removeSelf () event.object2 = nil if (playerIsInvincible == false) then killPlayer () end return end if (event.object1.name == " invaderBullet "e event.object2.name ==" player ") then table.remove (invaderBullets, table.indexOf (invaderBullets, event.object1)) event.object1: removeSelf () event.object1 = nil if (playerIsInvincible == false ) then killPlayer () end return end end end
Come prima, non sappiamo quale oggetto event.object1
e event.object2
sarà così che useremo due istruzioni if per verificare entrambe le situazioni. Rimuoviamo il proiettile dell'invasore dal invaderBullets
tabella, rimuoverlo dal display e impostarlo su zero
. Se il giocatore non è invincibile, lo uccidiamo.
Quando uccidiamo il giocatore, gli diamo un breve periodo di invincibilità. Questo dà all'utente il tempo di riguadagnare l'attenzione sul gioco. Se la numberOfLives
la variabile è uguale a 0
, sappiamo che il gioco è finito e la transizione al inizio scena in cui l'utente può iniziare una nuova partita.
function killPlayer () numberOfLives = numberOfLives- 1; se (numberOfLives <= 0) then gameData.invaderNum = 1 composer.gotoScene("start") else playerIsInvincible = true spawnNewPlayer() end end
Il spawnNewPlayer
la funzione fa sbiadire il lettore per alcuni secondi. È un buon effetto per far sapere all'utente che la nave è temporaneamente invincibile.
function spawnNewPlayer () local numberOfTimesToFadePlayer = 5 local numberOfTimesPlayerHasFaded = 0 local function fadePlayer () player.alpha = 0; transition.to (player, time = 400, alpha = 1,) numberOfTimesPlayerHasFaded = numberOfTimesPlayerHasFaded + 1 if (numberOfTimesPlayerHasFaded == numberOfTimesToFadePlayer) then playerIsInvincible = false end end fadePlayer () timer.performWithDelay (400, fadePlayer, numberOfTimesToFadePlayer) end
Usiamo una funzione locale, fadePlayer
, che usa la libreria di transizione per modificare il alfa
valore del giocatore
. Teniamo traccia di quante volte il giocatore
è sbiadito dentro e fuori e ha impostato l'invincibilità del giocatore a falso
una volta raggiunto il numberOfTimesToFadePlayer
. Usiamo un timer per chiamare il fadePlayer
funzione per comunque molte volte numberOfTimesToFadePlayer
è uguale a.
Esegui il gioco per testare questo. Il giocatore
dovrebbe morire quando il proiettile di un invasore colpisce la nave. Se tre proiettili colpiscono la nave, dovresti essere portato al inizio scena in cui è possibile iniziare una nuova partita.
Per rendere più semplice il test, commentare la chiamata a moveInvaders
nel gameLoop
funzione come mostrato di seguito.
function gameLoop () checkPlayerBulletsOutOfBounds () --moveInvaders () checkInvaderBulletsOutOfBounds () end
Se sei riuscito a uccidere ogni invasore, il gioco avrebbe chiamato il livello completato
funzione, che non esiste ancora. Lascia che risolvi quello Aggiungi il seguente blocco di codice.
function levelComplete () gameData.invaderNum = gameData.invaderNum + 1 if (gameData.invaderNum <= gameData.maxLevels) then composer.gotoScene("gameover") else gameData.invaderNum = 1 composer.gotoScene("start") end end
Aumentiamo gameData.invaderNum
e, se è inferiore a gameData.maxLevels
, passiamo al gioco finito scena. Altrimenti, il giocatore ha completato tutti i livelli e noi resettiamo gameData.invaderNum
a 1. Passiamo al inizio scena in cui il giocatore può iniziare una nuova partita.
Un modo semplice per testare questo è commentando la chiamata a moveInvaders
nel gameLoop
funzione e utilizzare i pulsanti per spostare la nave. Se è ancora troppo difficile, puoi anche commentare le due chiamate killPlayer
nel onCollision
metodo.
Aggiungere il seguente codice a gameover.lua per implementare il gioco sulla scena.
compositore locale = require ("compositore") local scene = composer.newScene () local starFieldGenerator = require ("starfieldgenerator") local pulsatingText = require ("pulsatingtext") local nextLevelButton local starGenerator function scene: create (event) local group = self .view starGenerator = starFieldGenerator.new (200, group, 5) local invadersText = pulsatingText.new ("LEVEL COMPLETE", display.contentCenterX, display.contentCenterY-200, "Conquest", 20, group) invadersText: setColor (1, 1, 1) invadersText: pulsate () nextLevelButton = display.newImage ("next_level_btn.png", display.contentCenterX, display.contentCenterY) gruppo: insert (nextLevelButton) end function scene: show (evento) local phase = event.phase compositore .removeScene ("gamelevel") if (phase == "did") then nextLevelButton: addEventListener ("tap", startNewGame) Runtime: addEventListener ("enterFrame", starGenerator) end end function scene: hide (evento) local phase = evento .phase if (phase == "will") then Runtime: removeEventListener ("enterF rame ", starGenerator) nextLevelButton: removeEventListener (" tap ", startNewGame) end end function startNewGame () compositer.gotoScene (" gamelevel ") end scene: addEventListener (" crea ", scena) scena: addEventListener (" mostra ", scena) scena: addEventListener ("nascondi", scena) restituisce la scena
Questo codice è molto simile al inizio scena quindi dovresti averne già familiarità.
L'ultimo controllo di collisione che dobbiamo eseguire è una collisione tra il giocatore e gli invasori. Aggiungere il seguente blocco di codice al onCollision
metodo che abbiamo visto prima.
function onCollision (event) --SNIP-- if (event.phase == "begin") then --SNIP-- if (event.object1.name == "player" ed event.object2.name == "invader" ) then numberOfLives = 0 killPlayer () end if (event.object1.name == "invader" e event.object2.name == "player") then numberOfLives = 0 killPlayer () end end
Come al solito, dobbiamo controllare entrambe le situazioni di collisione. Abbiamo impostato il numberOfLives
a 0 e chiama killPlayer
. IMPOSTANDO numberOfLives
a 0 e invocando killPlayer
, il gioco è finito e il gioco passa a inizio scena.
Questo completa il nostro gioco, ma ti suggerisco di provare ad espandere il gioco con alcune funzionalità aggiuntive. Ad esempio, potresti visualizzare le vite del giocatore in un HUD.
Ho anche incluso un grafico UFO nei file sorgente. Potresti provare a far apparire un UFO in modo casuale e se il giocatore lo colpisce con un proiettile dà loro una vita extra.
Se hai bisogno di aiuto con questi concetti, dai un'occhiata alla mia serie di Plane Fighting Game su Tuts+.
Se hai seguito questa serie, ora dovresti avere un gioco completamente funzionale simile agli Space Invaders originali. Espandilo e rendilo tuo. Spero che questo tutorial sia stato utile e abbia imparato alcune nuove tecniche. Grazie per la lettura.