În partea anterioară a acestei serii, am reușit să ne mișcăm nava jucătorului, să ne mișcăm invadatorii și să detectăm când un glonț a lovit un invadator. În această ultimă parte a seriei vom primi invadatorii care atacă jucătorul, se vor ocupa de niveluri și vor adăuga capacitatea jucătorului de a muri.
De câte ori unul dintre invadatori izbucnește un glonț. Vom folosi un cronometru pentru a realiza acest lucru. Adăugați următorul cod la gamelevel.lua.
funcția fireInvaderBullet () dacă (#invadersWhoCanFire> 0), apoi local randomIndex = math.random (#invadersWhoCanFire) local randomInvader = invadatoriWhoCanFire [randomIndex] local tempInvaderBullet = display.newImage ("laser.png", randomInvader.x, randomInvader.y + (2) tempInvaderBullet.name = "invaderBullet" scene.view: inserați (tempInvaderBullet) fizics.addBody (tempInvaderBullet, "dynamic") tempInvaderBullet.gravityScale = 0 tempInvaderBullet.isBullet = true tempInvaderBullet.isSensor = true tempInvaderBullet: setLinearVelocity table.insert (invaderBullets, tempInvaderBullet) altfel levelComplete () sfârșitul final
În această funcție, verificăm mai întâi dacă invadersWhoCanFire
tabelul are cel puțin un element în el. Dacă este cazul, atunci vom executa codul în instrucțiunea if. În caz contrar, înseamnă că nivelul sa terminat și noi invocăm nivel complet
funcţie.
Va exista întotdeauna cel puțin un invadator care poate declanșa un glonț până când ucizi ultimul invadator, moment în care invadersWhoCanFire
tabelul va fi gol.
În cadrul instrucțiunii if, generăm un număr aleatoriu randomIndex
în funcție de numărul de articole din invadersWhoCanFire
masa. Apoi alegem articolul respectiv, randomInvader
, de la invadersWhoCanFire
masa.
Creăm o imagine de tip glonț, dă-i o Nume
astfel încât să îl putem identifica mai târziu, să-l inserăm în scenă și să setăm aceleași proprietăți ca și noi pe glonțul jucătorului. În cele din urmă, introducem glonțul în invaderBullets
astfel încât să putem face referire mai târziu.
Acum trebuie să setăm cronometrul. Adăugați următoarele la scena: spectacol
metodă.
(event) dacă (faza == "a făcut") atunci --SNIP-- Runtime: addEventListener ("collision", onCollision) invaderFireTimer = timer.performWithDelay (1500, fireInvaderBullet,
La fiecare 1500 de milisecunde fireInvaderBullet
este invocată. Rețineți că ultimul parametru pe care îl transmitem este -1
, ceea ce înseamnă că temporizatorul se repetă pentru totdeauna. Ori de câte ori creați un cronometru care se repetă pentru totdeauna, ar trebui să îl anulați în cele din urmă. Noi facem asta înscena: ascunde
după cum se arată mai jos.
funcția scena: ascunde (eveniment) dacă (faza == "va") atunci --SNIP-- Runtime: removeEventListener ("collision", onCollision) timer.cancel (invaderFireTimer)
Ca gloanțele jucătorului, gloanțele invadatorilor se vor mișca off-screen și vor continua să se deplaseze, preluând memorie valoroasă. Pentru a remedia acest lucru, le eliminăm la fel ca în cazul gloanțelor jucătorului.
funcția checkInvaderBulletsOutOfBounds () dacă (#invaderBullets> 0), atunci pentru i = # invaderBullets, 1, -1 dacă (invaderBullets [i] .y> display.contentHeight) invaderBullets [i]: removeSelf nil table.remove (invaderBullets, i) end end end end
Acest cod este foarte similar cu a verifica dacă gloanțele jucătorului sunt în afara limitelor, așa că nu voi discuta implementarea în detaliu.
Următorul pas este să detectezi dacă glonțul unui invadator a lovit jucătorul. Adăugați următorul cod la onCollision
funcţie.
(event.phase == "started") atunci --SNIP-- dacă (event.object1.name == "player" și event.object2.name == "invaderBullet") apoi table.remove (invadareaBullets, table.indexOf (invaderBullets, event.object2)) event.object2: removeSelf () event.object2 = zero dacă (playerIsInvincible == false) invadorulBullet, event.object1)) event.object1: removeSelf () event.object1 = zero dacă (playerIsInvincible == false ), apoi killPlayer () sfârșitul capătului final al capătului de retur
Ca și înainte, nu știm ce obiect event.object1
și event.object2
va fi așa că vom folosi două declarații pentru a verifica ambele situații. Eliminăm glontul invadatorului din invaderBullets
tabel, scoateți-l din afișaj și setați-l la zero
. Dacă jucătorul nu este invincibil, îl omorâm.
Când omoram jucătorul, îi dăm un timp scurt de invincibilitate. Acest lucru oferă utilizatorului timp pentru a-și recupera atenția asupra jocului. În cazul în care numberOfLives
variabila este egală cu 0
, știm că jocul sa terminat și trecerea la start scenă în care utilizatorul poate începe un nou joc.
funcția killPlayer () numberOfLives = numberOfLives-1; în cazul în care (numberOfLives <= 0) then gameData.invaderNum = 1 composer.gotoScene("start") else playerIsInvincible = true spawnNewPlayer() end end
spawnNewPlayer
funcția face ca playerul să se estompeze și să se stingă pentru câteva secunde. Este un efect frumos de a permite utilizatorului să știe că nava este temporar invincibilă.
funcția spawnNewPlayer () number localOfTimesToFadePlayer = 5 număr localOfTimesPlayerHasFaded = 0 funcție locală fadePlayer () player.alpha = 0; (player, time = 400, alpha = 1,) numărOfTimesPlayerHasFaded = numberOfTimesPlayerHasFaded + 1 dacă (numberOfTimesPlayerHasFaded == numberOfTimesToFadePlayer) apoi playerIsInvincible = sfârșitul final fadePlayer () timer.performWithDelay (400, fadePlayer, numberOfTimesToFadePlayer) end
Folosim o funcție locală, fadePlayer
, care folosește biblioteca de tranziție pentru a modifica alfa
valoarea jucător
. Urmărim de câte ori jucător
a stins și a ieșit și a stabilit invincibilitatea jucătorului fals
odată ce ajungem la numberOfTimesToFadePlayer
. Folosim un cronometru pentru a apela fadePlayer
funcție de multe ori numberOfTimesToFadePlayer
este egal cu.
Rulați jocul pentru a testa acest lucru. jucător
ar trebui să moară când glonțul unui invadator lovește nava. Dacă trei gloanțe lovesc nava, ar trebui să fii dus la start unde puteți începe un nou joc.
Pentru a face acest lucru mai ușor de testat, comentează apelul către moveInvaders
în gameLoop
după cum se arată mai jos.
funcția gameLoop () checkPlayerBulletsOutOfBounds () --moveInvaders () checkInvaderBulletsOutOfBounds () sfârșit
Dacă ai reușit să omori pe fiecare invadator, jocul ar fi sunat-o nivel complet
care nu există încă. Să rezolvăm asta. Adăugați următorul bloc de coduri.
funcția levelComplete () gameData.invaderNum = gameData.invaderNum + 1 dacă (gameData.invaderNum <= gameData.maxLevels) then composer.gotoScene("gameover") else gameData.invaderNum = 1 composer.gotoScene("start") end end
Noi creștem gameData.invaderNum
și, dacă este mai mică decât gameData.maxLevels
, trecem la joc încheiat scenă. În caz contrar, jucătorul a terminat fiecare nivel și ne reinițializăm gameData.invaderNum
la 1. Trecem la start scena unde jucatorul poate incepe un nou joc.
O modalitate ușoară de a testa acest lucru este prin a comenta apelul la moveInvaders
în gameLoop
funcția și utilizați butoanele pentru a muta nava. Dacă este încă prea greu, puteți să comenteze și cele două apeluri killPlayer
în onCollision
metodă.
Adăugați următorul cod la gameover.lua pentru a implementa jocul peste scenă.
compozitor local = necesită ("compozitor") scena locală = compozitor.newScene () local starFieldGenerator = necesită ("starfieldgenerator") pulsatingText locală necesită ("pulsatingtext") local nextLevelButton star localGenerator scena funcției: .view starGenerator = starFieldGenerator.new (200, grup, 5) invadatorii localiText = pulsatingText.new ("LEVEL COMPLETE", display.contentCenterX, display.contentCenterY-200, "Conquest" 1, 1) invadersText: pulsate () nextLevelButton = display.newImage ("next_level_btn.png", display.contentCenterX, display.contentCenterY) grup: insert (nextLevelButton) .RemoveScene ("gamelevel") dacă (faza == "a făcut"), apoi nextLevelButton: addEventListener ("tap", startNewGame) Runtime: addEventListener (enterFrame, starGenerator) .phase dacă (faza == "va") apoi Runtime: removeEventListener ("enterF rame ", starGenerator) nextLevelButton: removeEventListener (" tap ", startNewGame) funcția end end startNewGame () composer.gotoScene (" gamelevel ") scena final: addEventListener (" scena: addEventListener ("ascunde", scena) scena de întoarcere
Acest cod este foarte similar cu start astfel încât ar trebui să fiți familiarizați până acum.
Ultimul control de coliziune pe care trebuie să-l realizăm este o coliziune între jucător și invadatori. Adăugați următorul bloc de coduri la onCollision
metoda pe care am văzut-o mai devreme.
(event.phase == "started") atunci --SNIP-- dacă (event.object1.name == "player" și event.object2.name == "invader" ), atunci numărulOfLives = 0 killPlayer () se termină dacă (event.object1.name == "invader" și event.object2.name == "player"), apoi numberOfLives = 0 killPlayer
Ca de obicei, trebuie să verificăm ambele situații de coliziune. Am setat numberOfLives
la 0 și sunați killPlayer
. Prin setare numberOfLives
la 0 și invocând killPlayer
, jocul sa terminat și jocul trece la start scenă.
Acest lucru completează jocul nostru, dar vă sugerăm să încercați să extindeți jocul cu câteva funcții suplimentare. De exemplu, puteți afișa viața jucătorului într-un HUD.
Am inclus, de asemenea, un grafic OZN în fișierele sursă. Ai putea încerca să faci un OZN să apară la întâmplare și dacă jucătorul îl lovește cu un glonț, dă-i o viață suplimentară.
Dacă aveți nevoie de ajutor cu aceste concepte, atunci verificați seria de jocuri de luptă cu avionul pe Tuts+.
Dacă ați urmat această serie, atunci ar trebui să aveți acum un joc pe deplin funcțional similar cu Space Invaders. Extindeți-l și creați-vă propriul. Sper că ați găsit acest tutorial util și ați învățat câteva tehnici noi. Mulțumesc că ați citit.