Questo tutorial fornirà il porting di un gioco Flash / Flex all'SDK Corona. In particolare, eseguiremo il porting da ActionScript a Lua, con l'obiettivo finale di riprodurre in precedenza giochi solo su Flash sull'iPhone. Oltre a dimostrare differenze linguistiche e API, questa serie di tutorial terrà conto anche delle restrizioni hardware come la dimensione dello schermo e la mancanza di pulsanti fisici su iPhone.
Ora inizieremo a lavorare con il nostro nemico: "de / pixelate / flixelprimer / Alien.as". Come sempre, la sintassi viene convertita per prima.
Quando hai finito, aggiungi la decodifica del modulo e avvolgi tutte le funzioni all'interno di Alien ().
module (?, package.seeall) - [Incorpora (source = "? /? /? /? /assets/png/Alien.png")] private var ImgAlien: Class function Alien (x, y) -: void super (x, y, ImgAlien) velocity.x = -200 function update () -: void velocity.y = Math.cos (x / 50) * 50 super.update () end end
L'alieno funziona in modo molto simile al nostro proiettile. Crea un'immagine, imposta la sua xey
coordinate, e gli dà una velocità. Quindi, ci avvicineremo allo stesso modo. Le prime due righe all'interno della funzione possono essere sostituite con quasi lo stesso codice utilizzato per il proiettile. Questa volta useremo comunque un'immagine.
module (?, package.seeall) function Alien (x, y) -: void local Alien = display.newImage ("Alien.png") Alien.x = x Alien.y = y aggiornamento funzione () -: void ? fine fine
Ora che abbiamo caricato e impostato l'immagine, spostiamola a sinistra. Di nuovo creeremo qualcosa come il codice update () del nostro proiettile. Lascia le vecchie linee all'interno di update () commentate.
module (?, package.seeall) function Alien (x, y) -: void? function update () -: void if Alien then if (Alien.x> 0 - Alien.contentWidth) quindi Alien.x = Alien.x - 2 end end? codice commentato? end Runtime: addEventListener ("enterFrame", update) end
Ora facciamo una funzione kill () e facciamo Alien restituire un alieno.
module (?, package.seeall) function Alien (x, y) -: void? function update () -: void? fine funzione Alien: kill () Alien.parent: remove (Alien) Alien = nil end Runtime: addEventListener ("enterFrame", update) return Alien end
Ora possiamo uccidere () il nostro alieno se è x è fuori dallo schermo a sinistra. Possiamo anche aggiungere una nuova funzione () per comodità.
module (?, package.seeall) function Alien (x, y) -: void local Alien = display.newImage ("Alien.png") Alien.x = x Alien.y = y aggiornamento funzione () -: void se Alieno poi se (Alien.x> 0 - Alien.contentWidth) poi Alien.x = Alien.x - 2 altro Alien: kill () end end end function Alien: kill () Alien.parent: remove (Alien) Alien = nil end Runtime: addEventListener ("enterFrame", update) return Alien end function new (x, y) return Alien (x, y) end
Creare l'alieno era abbastanza facile. Ora dobbiamo iniziare ad aggiungerli al gioco attraverso PlayState.
Innanzitutto, importa il modulo in PlayState.lua.
module (?, package.seeall) Local Ship = require ("Ship") local Bullet = require ("Bullet") local Alien = require ("Alien") Buttons locali = require ("Buttons")
Ora abbiamo bisogno di impostare un timer. Il codice originale aveva una variabile _spawnInterval che era stata usata per impostare _spawnTimer. Ogni volta che _spawnTimer ha raggiunto 0, sarebbe stato reimpostato sul valore di _spawnInterval._spawnInterval, quindi sarebbe stato diminuito di .1, con il risultato che gli alieni venivano generati più rapidamente.
Per iniziare, decommentare le declinazioni delle proprietà _spawnInterval e _spawnTimer in create ().
function create () -: void - dichiarazioni variabili 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 = nil? fine
Ora nelle assegnazioni di variabili, impostare _spawnTimer su 0 e _spawnInterval su 2.5. Aggiungi anche una chiamata a resetSpawnTimer (). Creeremo questa funzione in un secondo.
function create () -: void? - assegnazioni variabili 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 () fine
Ora trova la funzione commentata resetSpawnTimer (). Assomiglierà a questo.
function resetSpawnTimer () -: void _spawnTimer = _spawnInterval _spawnInterval = _spawnInterval * 0,95 if (_spawnInterval < 0.1) then _spawnInterval = 0.1 end end
Sorprendentemente, è esattamente ciò di cui abbiamo bisogno. Abbiamo solo bisogno di rendere le proprietà delle variabili di PlayState. In questo modo la funzione saprà cosa stiamo parlando di _spawnInterval e _spawnTimer.
function resetSpawnTimer () -: void PlayState._spawnTimer = PlayState._spawnInterval PlayState._spawnInterval = PlayState._spawnInterval * 0,95 if (PlayState._spawnInterval < 0.1) then PlayState._spawnInterval = 0.1 end end
Ora dobbiamo aggiungere del codice ad update (). Nel codice originale, il gioco creava alieni anche se il gioco era finito e la nave era morta. Per fare la stessa cosa, mettiamo il nostro codice di gestione alieno al di fuori di dove controlliamo se il gioco è finito.
function update () PlayState._spawnTimer = PlayState._spawnTimer - (30/1000) if (PlayState._spawnTimer < 0) then spawnAlien() resetSpawnTimer() end if PlayState._inGame then? end end
Questo codice funziona proprio come il codice sorgente. Sottrae 1 fotogramma di tempo da _spawnTimer. Quindi controlla se _spawnTimer è inferiore a zero. Se lo è, ripristina il timer e genera un nuovo alieno.
Prima di poter generare qualsiasi alieno, abbiamo bisogno di un gruppo di visualizzazione per aggiungerli. Proprio come _bullets, decommenta la declinazione _aliens e assegnali a un nuovo gruppo di visualizzazione.
function create () -: void - dichiarazioni variabili 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 = nil - assegnazioni di variabili 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._spawnTimer = 0 PlayState._spawnInterval = 2.5 resetSpawnTimer ()? fine
Ora trova la tua funzione spawnAlien () e decommentala. Dovrebbe assomigliare a qualcosa di simile a questo:
function spawnAlien () -: void local x = FlxG.width local y = Math.random () * (FlxG.height - 100) + 50 _aliens.add (new Alien (x, y)) end
Questo codice crea uno straniero appena a destra dello schermo e ad un'altezza casuale. Quindi aggiunge il nuovo alieno al gruppo di visualizzazione. Possiamo fare la stessa cosa con questo codice:
function spawnAlien () -: void local x = display.contentWidth local y = math.random () * (display.contentHeight - 240) + 50 PlayState._aliens: insert (Alien.new (x, y)) end
Se eseguiamo il codice ora, funziona quasi come l'originale. Gli alieni appaiono ad altezze casuali e appaiono lentamente più frequentemente. Quando escono dallo schermo, chiamano kill () su se stessi. Ora abbiamo solo bisogno di farli muovere come hanno fatto nel codice originale. Nel gioco originale, gli alieni seguivano il percorso di un'onda cosina generata in base alla loro posizione x. Abbiamo questo codice commentato nel funciton alieni update (). Questo codice ha richiesto un po 'di gioco. Perché non abbiamo velocità con cui lavorare, è difficile usare il codice originale. Questo è il momento del porting in cui dovrai solo giocare con i numeri. Ho trovato questo codice funzionato più vicino all'originale:
function update () -: void if Alien then if (Alien.x> 0 - Alien.contentWidth) then Alien.x = Alien.x - 2 Alien.y = Alien.y + math.cos (Alien.x / 10 ) * 2 altro Alien: kill () end end end
Ora che abbiamo tutti i nostri oggetti di gioco che funzionano come gli originali, dobbiamo controllare le collisioni tra i proiettili e gli alieni, gli alieni e la nave. Nel codice originale, le collisioni sono state controllate nella funzione update (). Se si verifica una collisione, i due oggetti sono stati passati alle funzioni sovrapposte a AlienBullet () e overlapAlienShip (). Creiamo prima quelle funzioni. Se il commento è sovrapposto a AlienBullet (), abbiamo un codice simile al seguente:
function overlapAlienBullet (alien, bullet) -: void emitter locale = createEmitter () emitter.at (alien) alien.kill () bullet.kill () FlxG.play (SoundExplosionAlien) FlxG.score = FlxG.score + 1 _scoreText. text = FlxG.score.toString () end
Questo codice crea un emettitore di particelle, uccide entrambi gli oggetti, riproduce un effetto sonoro e aggiorna il punteggio. Ricreare il sistema di particelle di flixel va oltre lo scopo di questo tutorial, e dobbiamo ancora implementare un sistema di punteggio. Per ora, commentiamo solo quelle righe e uccidiamo gli oggetti.
function overlapAlienBullet (alien, bullet) -: void alien: kill () bullet: kill () --FlxG.play (SoundExplosionAlien) --FlxG.score = FlxG.score + 1 --_ scoreText.text = FlxG.score. toString () fine
Fai lo stesso per overlapAlienShip ():
function overlapAlienShip (alien, ship) -: void ship: kill () alien: kill () --FlxG.play (SoundExplosionShip) --_ gameOverText = new FlxText (0, FlxG.height / 2, FlxG.width, "GAME OVER \ nPRESS ENTRA PER GIOCARE ANCORA ") --_ gameOverText.setFormat (null, 16, 0xFF597137," center ") --add (_gameOverText) fine
Ora creiamo l'effetto sonoro per l'uso in quelle funzioni. Decommentare le dichiarazioni della variabile sonora in create ().
function create () -: void - dichiarazioni variabili 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 = nil? fine
Ora assegnali ai loro suoni:
function create () -: void? - assegnazioni variabili 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 () fine
Riproduzione dei suoni è facile come una riga per funzione ().
function overlapAlienBullet (alien, bullet) -: void alien: kill () bullet: kill () media.playEventSound (PlayState.SoundExplosionAlien) --FlxG.score = FlxG.score + 1 --_ scoreText.text = FlxG.score. toString () end function overlapAlienShip (alien, ship) -: void ship: kill () alien: kill () media.playEventSound (PlayState.SoundExplosionShip) --_ gameOverText = new FlxText (0, FlxG.height / 2, FlxG. width, "GAME OVER \ nPRESS ENTRA PER GIOCARE ANCORA") --_ gameOverText.setFormat (null, 16, 0xFF597137, "center") --add (_gameOverText) fine
Ora che abbiamo le nostre funzioni di sovrapposizione, dobbiamo verificare la presenza di collisioni su ogni frame. In Corona, non abbiamo un modo semplice per verificare la sovrapposizione di oggetti di visualizzazione. Dovremo fare i controlli manualmente. Questo è un concetto abbastanza semplice, ma diventa piuttosto complicato nell'implementazione. Pensiamo a questo per un secondo. Cosa definisce una sovrapposizione? Il tuo primo istinto potrebbe essere quello di verificare se un oggetto si trova all'interno di un altro. Funzionerebbe, ma in questo caso una sovrapposizione potrebbe essere solo parti degli oggetti. Un oggetto non deve necessariamente essere completamente dentro a un altro per sovrapporsi. Che aspetto ha questo in codice? Tutto quello che dobbiamo fare è controllare se il valore x massimo di un oggetto è maggiore del minimo x
valore dell'altro oggetto. Quindi controlliamo se il valore x minimo dello stesso oggetto è inferiore al valore x massimo degli altri oggetti. Ciò restituirà true per ogni sovrapposizione. Successivamente eseguiamo gli stessi controlli sui valori y degli oggetti. Se passiamo in rassegna tutti gli oggetti nei gruppi di visualizzazione che abbiamo creato in precedenza, dovremmo avere un sistema di collisione funzionante.
Proviamo questo con i proiettili e gli alieni. Dobbiamo eseguire questi controlli solo nel gioco. Quindi inserisci questo codice all'interno della parte appropriata della funzione update ():
function update () -: void? se PlayState._inGame poi se PlayState._shoot == true e PlayState._ship allora locale p = PlayState._ship: getBulletSpawnPosition () spawnBullet (p) termina se PlayState._bullets.numChildren> 0 e PlayState._aliens.numChildren> 0 poi per b = 1, PlayState._bullets.numChildren fanno locale bulletXMax = PlayState._bullets [b] .contentBounds.xMax local bulletXMin = PlayState._bullets [b] .contentBounds.xMin bullet localeMax = PlayState._bullets [b] .contentBounds.yMax local bulletYMin = PlayState._bullets [b] .contentBounds.yMin per a = 1, PlayState._aliens.numChildren do if (PlayState._aliens [a] .contentBounds.xMin <= bulletXMax) then if (PlayState._aliens[a].contentBounds.xMax >= bulletXMin) quindi se (PlayState._aliens [a] .contentBounds.yMin <= bulletYMax) then if (PlayState._aliens[a].contentBounds.yMax >= bulletYMin) quindi sovrapponiAlienBullet (PlayState._aliens [a], PlayState._bullets [b]) fine fine fine fine fine fine fine fine fine
Come ho detto, questo codice sembra un po 'disordinato, ma funziona. Quindi, cosa fa questo? Per prima cosa controlla se esiste addirittura un proiettile o un alieno. Questo codice può diventare davvero intensivo della memoria, quindi dobbiamo controllare tutto. Non vogliamo perdere tempo se non abbiamo nemmeno entrambi i tipi di oggetti. Una volta che il codice passa, iniziamo un ciclo for. Questo ciclo imposta una variabile ("b" che prende il nome da "punti elenco") su 1 e esegue il resto del codice per ogni punto elenco in _bullet. Le successive quattro righe di codice creano una copia locale dei valori minimo e massimo del punto elenco. Come ho detto prima, dobbiamo salvare la memoria qui. Non è necessario calcolare i valori xey di proiettili ripetutamente se non cambiano. La riga successiva inizia ancora un altro ciclo. Questo si ripete per tutti gli alieni in _aliens. Il codice all'interno del secondo ciclo for esegue solo i controlli di cui stavamo parlando in precedenza. Il valore x max del proiettile è maggiore del valore min x dello straniero? Non posso sottolineare abbastanza la memoria qui, quello
è il motivo per cui stiamo controllando ogni condizione in una dichiarazione separata. Se uno di questi test fallisce, possiamo semplicemente abbandonare il ciclo. Non è necessario continuare a controllare se non c'è collisione. Infine, proprio nel centro, se passano tutti questi controlli, chiamiamo la nostra funzione overlapAlienBullet () con il proiettile collisione e lo straniero.
Accidenti. Quello era un sacco di codice. Ora dobbiamo solo fare lo stesso per la nave.
function update () -: void? se PlayState._inGame allora se PlayState._shoot == true e PlayState._ship allora locale p = PlayState._ship: getBulletSpawnPosition () spawnBullet (p) end? se PlayState._aliens.numChildren> 0 quindi shipXMax locale = PlayState._ship.contentBounds.xMax shipXMin locale = PlayState._ship.contentBounds.xMin nave localeYMax = PlayState._ship.contentBounds.yMax nave localeYMin = PlayState._ship.contentBounds.yMin per a = 1, PlayState._aliens.numI bambini fanno se (PlayState._aliens [a] .contentBounds.xMin <= shipXMax) then if (PlayState._aliens[a].contentBounds.xMax >= shipXMin) quindi se (PlayState._aliens [a] .contentBounds.yMin <= shipYMax) then if (PlayState._aliens[a].contentBounds.yMax >= shipYMin) quindi sovrapponiAlienShip (PlayState._aliens [a], PlayState._ship) fine fine fine fine fine fine fine fine
Questo codice è identico al proiettile e al codice alieno. L'unica differenza è che abbiamo solo una nave. Sappiamo che esiste una nave, altrimenti PlayState._inGame sarebbe falsa. Non abbiamo bisogno di passare in rassegna un gruppo di display di navi perché ne abbiamo solo uno.
Prima di poter testare questo codice, dobbiamo fare in modo che il gioco finisca in overlapAlienShip (). Cambia _inGame in falso.
function overlapAlienShip (alien, ship) -: void ship: kill () alien: kill () media.playEventSound (PlayState.SoundExplosionShip) PlayState._inGame = false --_ gameOverText = new FlxText (0, FlxG.height / 2, FlxG .width, "GAME OVER \ nPRESS ENTRA PER GIOCARE ANCORA") --_ gameOverText.setFormat (null, 16, 0xFF597137, "center") --add (_gameOverText) fine
Esecuzione del codice ora mostra che il nostro duro lavoro ha dato i suoi frutti. Ora abbiamo una porta completamente funzionante del gioco originale. Abbiamo ancora bisogno di ricreare il sistema di punteggio, e dobbiamo essere in grado di riavviare il gioco, ma il duro porting è finito.
Iniziamo con il sistema di punteggio. È semplice come creare un'etichetta di testo e aggiornarla quando il punteggio cambia. Decommentare la riga _scoreText e aggiungere una nuova proprietà _score nelle dichiarazioni create ().
function create () -: void - dichiarazioni variabili 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? fine
Ora dobbiamo assegnare loro alcuni valori. _score può essere impostato su 0. _scoreText deve essere assegnato a un nuovo oggetto di testo situato nella parte superiore sinistra dello schermo.
function create () -: void? - assegnazioni variabili 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._score = 0 PlayState._scoreText = display.newText ("0", 10, 8, nil, 32) PlayState._scoreText: setTextColor (89 , 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 () fine
L'API newText è semplice: display.newText ("testo da visualizzare", posizione x, posizione y, carattere, dimensione). "PlayState._scoreText: setTextColor (89, 113, 55)" imposta semplicemente il colore di riempimento sullo stesso colore verde dei punti elenco. Tutto ciò di cui abbiamo bisogno ora è di aggiornare il punteggio in overlapAlienBullet ():
function overlapAlienBullet (alien, bullet) -: void alien: kill () bullet: kill () media.playEventSound (PlayState.SoundExplosionAlien) PlayState._score = PlayState._score + 1 PlayState._scoreText.text = PlayState._score fine
Questo semplicemente aggiunge 1 alla proprietà _score quando un alieno viene ucciso da un proiettile. Quindi modifica la proprietà text di _scoreText sul valore del punteggio.
Prima di concludere questo gioco, abbiamo bisogno di un modo per resettarlo. In questo modo, l'utente può ricominciare da capo quando muore. Dovremo farlo in due passaggi. Per prima cosa, dobbiamo fermare tutto ciò che l'utente può controllare non appena la nave muore. Quindi, dobbiamo resettare tutto il resto quando l'utente tocca per iniziare una nuova partita.
Disattiviamo tutti i pulsanti nella funzione overlapAlienShip (). Inoltre, rimuoviamo la proprietà della nave. Possiamo farlo impostando tutti i valori su zero.
function overlapAlienShip (alien, ship) -: void ship: kill () alien: kill () media.playEventSound (PlayState.SoundExplosionShip) PlayState._inGame = false PlayState._ship = nil PlayState._upButton.onPress = nil 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 --_ gameOverText = nuovo FlxText (0, FlxG.height / 2, FlxG.width, "GAME OVER \ nPRESS ENTRA PER GIOCARE DI NUOVO") --_ gameOverText.setFormat (null, 16, 0xFF597137 , "center") --add (_gameOverText) fine
Questo codice assegna tutti i valori onPress e onRelease a zero. I pulsanti saranno fermi
display, ma non chiamano alcun codice quando vengono premuti.
Vediamo ora che la funzione overlapAlienShip () originale mostrava un'etichetta di testo per dire all'utente che il gioco era finito. Faremo la stessa cosa Per prima cosa decommenta la nostra proprietà _gameOverText nella funzione create ().
function create () -: void - dichiarazioni variabili 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? fine
Tornando in overlapAlienShip (), dobbiamo sostituire il codice commentato con queste righe.
function overlapAlienShip (alien, ship) -: void ship: kill () alien: kill () media.playEventSound (PlayState.SoundExplosionShip) PlayState._inGame = false PlayState._ship = nil PlayState._upButton.onPress = nil 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 ("GAME OVER TAP TO PLAY AGAIN", 35, display.contentHeight / 2 - 50, nil, 16) PlayState._gameOverText: setTextColor (89, 113, 55) fine
Questo è lo stesso codice che abbiamo usato per creare e riempire il testo del punteggio. La posizione viene cambiata per centrare il testo sullo schermo e il testo dice "TAP TO PLAY ANCORA" invece di "PREMERE INVIO PER GIOCARE DI NUOVO".
Dal momento che stiamo per toccare per riavviare il gioco, dobbiamo aggiungere un nuovo listener di eventi. Possiamo farlo nello stesso modo in cui abbiamo aggiunto il listener di enterFrame, ma questa volta l'evento che stiamo ascoltando è "tap". Inoltre, è necessario aggiungere una funzione per l'ascoltatore da chiamare. Nella parte inferiore di overlapAlienShip () aggiungi questo listener di eventi:
function overlapAlienShip (alien, ship) -: void ship: kill () alien: kill () media.playEventSound (PlayState.SoundExplosionShip) PlayState._inGame = false PlayState._ship = nil PlayState._upButton.onPress = nil 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 ("GAME OVER TAP TO PLAY AGAIN", 35, display.contentHeight / 2 - 50, nil, 16) PlayState._gameOverText: setTextColor (89, 113, 55) Runtime: addEventListener ("tap", tap) end
Questo codice controlla la presenza di un tocco in qualsiasi punto dello schermo. Quando si verifica un "tap", chiama la funzione tap (). Facciamo una funzione tap () vuota per chiamare. Mettilo appena sopra create ().
? function tap (event) - abbiamo solo bisogno di questo come segnaposto per la funzione end now create ()? fine
Facciamo una funzione remove () per gestire la pulizia di tutti gli oggetti del gioco. Metti questa funzione sopra la nostra nuova funzione tap ().
? function remove () - end function tap (event) - abbiamo solo bisogno di questo come segnaposto per la funzione end now create ()? fine
Per cominciare, dovremmo uccidere tutti gli altri alieni e proiettili. Per fare ciò, possiamo semplicemente scorrere i rispettivi gruppi di visualizzazione. Questo è il modo corretto per rimuovere oggetti in Corona:
function remove () per i = PlayState._bullets.numChildren, 1, -1 do PlayState._bullets [i]: kill () fine per i = PlayState._aliens.numChildren, 1, -1 do PlayState._aliens [i]: kill () fine PlayState._bullets: removeSelf () PlayState._bullets = nil PlayState._aliens: removeSelf () PlayState._aliens = nil end
Questi loop funzionano in modo speciale. Ogni ciclo inizia con "i" impostato sull'ultimo oggetto nei gruppi di visualizzazione. Quindi il ciclo uccide quell'oggetto e sottrae 1 da "i". Il ciclo si ripete finché "i" è uguale a 1. Il motivo per cui stiamo sottraendo da "i" è che ogni volta che uccidiamo un oggetto esso si rimuove dal gruppo di visualizzazione. Ciò significa che c'è un oggetto in meno nel gruppo di visualizzazione. Se dovessimo aggiungere 1 a "i", finiremmo per chiamare kill () su oggetti che non esistono più. Per risolvere questo problema, contiamo all'indietro ogni volta che rimuoviamo un oggetto.
Dopo che tutti gli oggetti sono stati rimossi dai gruppi, rimuoviamo i gruppi. Abbiamo anche impostato le proprietà che hanno tenuto i gruppi a zero. Ora possono essere riutilizzati.
Impostiamo tutte le variabili utilizzate su zero. In questo modo il garbage collector può liberare la memoria. Ciò assicurerà anche che tutte le variabili vengano ripristinate prima di iniziare una nuova partita. Rimuovi prima tutti i pulsanti:
function remove () per i = PlayState._bullets.numChildren, 1, -1 do PlayState._bullets [i]: kill () fine per i = PlayState._aliens.numChildren, 1, -1 do PlayState._aliens [i]: kill () fine PlayState._bullets: removeSelf () PlayState._bullets = nil PlayState._aliens: removeSelf () PlayState._aliens = nil PlayState._upButton: removeSelf () PlayState._upButton = nil PlayState._downButton: removeSelf () PlayState._downButton = nil PlayState._leftButton: removeSelf () PlayState._leftButton = nil PlayState._rightButton: removeSelf () PlayState._rightButton = nil PlayState._shootButton: removeSelf () PlayState._shootButton = nil end
Dobbiamo prima rimuoverli dal display e quindi impostarli su zero. Prendiamoci cura dei nostri suoni ora.
function remove () per i = PlayState._bullets.numChildren, 1, -1 do PlayState._bullets [i]: kill () fine per i = PlayState._aliens.numChildren, 1, -1 do PlayState._aliens [i]: kill () fine PlayState._bullets: removeSelf () PlayState._bullets = nil PlayState._aliens: removeSelf () PlayState._aliens = nil PlayState._upButton: removeSelf () PlayState._upButton = nil PlayState._downButton: removeSelf () PlayState._downButton = nil PlayState._leftButton: removeSelf () PlayState._leftButton = nil PlayState._rightButton: removeSelf () PlayState._rightButton = nil PlayState._shootButton: removeSelf () PlayState._shootButton = nil PlayState.SoundExplosionShip = nil PlayState.SoundExplosionAlien = nil PlayState. SoundBullet = nil end
Ora i nostri oggetti di testo:
funzione remove ()? PlayState._scoreText: removeSelf () PlayState._scoreText = nil PlayState._gameOverText: removeSelf () PlayState._gameOverText = nil end
Per completare la pulizia, dobbiamo rimuovere i nostri listener di eventi. Dopodiché, possiamo finalmente resettare PlayState su un array vuoto:
funzione remove ()? Runtime: removeEventListener ("enterFrame", update) Runtime: removeEventListener ("tap", tap) PlayState = nil PlayState = fine
Riavviare il gioco è semplice come chiamare remove () e quindi create () nella nostra funzione tap ().
funzione tap (evento) remove () create () end
Abbiamo quasi finito. Dobbiamo solo aggiungere qualche tocco finale. Inizia rimuovendo tutte le righe commentate dal vecchio codice sorgente. Questo pulirà i nostri file di una tonnellata.
Un'altra rapida modifica che possiamo fare è abilitare il multitouch. Non noterai il cambiamento sul simulatore, ma è bello poter premere più pulsanti alla volta sul dispositivo reale. Questa è una regolazione a una linea. Ne abbiamo bisogno solo una volta, quindi aggiungiamolo al file main.lua.
local PlayState = require ("PlayState") function Main () system.activate ("multitouch") display.setStatusBar (display.HiddenStatusBar) PlayState.PlayState () end Main ()
Avevo anche qualche problema con il modulo ui.lua. I pulsanti non contano allontanando il dito dal dispositivo, a meno che l'ultimo tocco toccato non sia stato il pulsante. Questo non sempre funziona correttamente per questo particolare gioco, ea volte la nave sembrerà muoversi da solo perché la funzione di rilascio non viene chiamata. Questa era una soluzione semplice. Ho rimosso il controllo per vedere se il pulsante veniva premuto quando il dito dell'utente veniva rilasciato. Questo significava solo commentare le dichiarazioni if e end alle righe 91 e 98.
? se "ended" == phase then - Considera questo solo un "click" se l'utente alza il dito all'interno dello stage del pulsanteBounds - if isWithinBounds then if onEvent then buttonEvent.phase = "release" result = onEvent (buttonEvent) elseif onRelease then risultato = onRelease (evento) fine - fine fine?
Queste modifiche sono incluse nel file ui.lua incluso in questo tutorial.
Abbiamo finito. Ora abbiamo una replica completamente funzionante del gioco flash originale. Abbiamo una nave che si muove e spara, alieni e un sistema di punteggio. Il gioco gestisce la memoria di tutti gli oggetti e ha la capacità di resettare e ricominciare. Oltre al sistema particellare, questo gioco è una porta identica. Ora che hai completato questo tutor