I den forrige delen av denne serien fikk vi spillerens skip, flyttet, fikk inntrengerne til å bevege seg og oppdaget når en spillerkule hadde rammet en invaderer. I denne siste delen av serien får vi inntrengerne angriper spilleren, håndterer nivåer og legger til evnen til spilleren til å dø.
Hver gang en av inntrengerne brenner en kule. Vi bruker en timer for å oppnå dette. Legg til følgende kode til gamelevel.lua.
funksjon fireInvaderBullet () hvis (#invadersWhoCanFire> 0) deretter lokale randomIndex = math.random (#invadersWhoCanFire) lokale randomInvader = invadersWhoCanFire [randomIndex] lokal tempInvaderBullet = display.newImage ("laser.png", randomInvader.x, randomInvader.y + invaderSize / 2) tempInvaderBullet.name = "invaderBullet" scene.view: sett inn (tempInvaderBullet) physics.addBody (tempInvaderBullet, "dynamisk") tempInvaderBullet.gravityScale = 0 tempInvaderBullet.isBullet = sann tempInvaderBullet.isSensor = sann tempInvaderBullet: setLinearVelocity (0,400) table.insert (invaderBullets, tempInvaderBullet) ellers levelComplete () slutten
I denne funksjonen kontrollerer vi først om invadersWhoCanFire
bordet har minst ett element i det. Hvis det er tilfelle, kjører vi koden i if-setningen. Ellers betyr det at nivået er over og vi påberoper levelComplete
funksjon.
Det vil alltid være minst en inntrenger som kan brenne en kule til du dreper den siste invaderen, på hvilket tidspunkt invadersWhoCanFire
bordet vil være tomt.
Innenfor if-setningen genererer vi et tilfeldig tall randomIndex
avhengig av hvor mange elementer som er i invadersWhoCanFire
bord. Vi velger da det aktuelle elementet, randomInvader
, fra invadersWhoCanFire
bord.
Vi lager et kulebilde, gi det en Navn
eiendom slik at vi kan identifisere det senere, sette det inn i scenen og sette de samme egenskapene som vi gjorde på spillerens kulde. Til slutt legger vi inn kule i invaderBullets
bord slik at vi kan referere det senere.
Vi må nå sette opp timeren. Legg til følgende i scene: Vis
metode.
funksjonsscene: show (event) hvis (fase == "gjorde") da --SNIP-- Runtime: addEventListener ("kollisjon", onCollision) invaderFireTimer = timer.performWithDelay (1500, fireInvaderBullet, -1)
Hver 1500 millisekunder fireInvaderBullet
er påkalt. Vær oppmerksom på at den siste parameteren vi sender inn er -1
, noe som betyr at timeren gjentas for alltid. Når du oppretter en timer som gjentas for alltid, bør du til slutt avbryte den. Vi gjør dette iscene: hide
fungere som vist nedenfor.
funksjonsscene: skjul (hendelse) hvis (fase == "vil") da --SNIP-- Runtime: removeEventListener ("collision", onCollision) timer.cancel (invaderFireTimer) endeend
Som spillerens kuler vil inntrengernes kuler bevege seg på skjermen og fortsette å bevege seg og ta opp verdifullt minne. For å rette opp dette, fjerner vi dem akkurat som vi gjorde med spillerens kuler.
funksjonen checkInvaderBulletsOutOfBounds () hvis (#invaderBullets> 0) så for i = # invaderBullets, 1, -1 gjør hvis (invaderBullets [i] .y> display.contentHeight) så invaderBullets [i]: removeSelf () invaderBullets [i] = nil table.remove (invaderBullets, i) endeendens ende ende
Denne koden ligner veldig på å sjekke om spillerens kuler er ute av grensene, så jeg vil ikke diskutere implementeringen i detalj.
Det neste trinnet er å oppdage om en invaders kulde har truffet spilleren. Legg til følgende kode i onCollision
funksjon.
Funksjon onCollision (event) hvis (event.phase == "startet") så --SNIP-- hvis (event.object1.name == "player" og event.object2.name == "invaderBullet") så table.remove (invaderBullets, table.indexOf (invaderBullets, event.object2)) event.object2: removeSelf () event.object2 = null hvis (playerIsInvincible == false) da killPlayer () end tilbake ende hvis (event.object1.name == " invaderBullet "og event.object2.name ==" player ") så table.remove (invaderBullets, table.indexOf (invaderBullets, event.object1)) event.object1: removeSelf () event.object1 = null hvis (playerIsInvincible == false ) da killPlayer () slutter returendets ende ende
Som før vet vi ikke hvilket objekt event.object1
og event.object2
vil være så vi bruker to hvis setninger for å kontrollere begge situasjoner. Vi fjerner invaderens kulde fra invaderBullets
bord, fjern det fra skjermen, og sett det på nil
. Hvis spilleren ikke er uovervinnelig, dreper vi det.
Når vi dreper spilleren, gir vi ham en kort tid med uovervinnelighet. Dette gir brukeren tid til å gjenvinne fokus på spillet. Hvis numberOfLives
variabel er lik 0
, Vi vet at spillet er over og overgang til start scene der brukeren kan starte et nytt spill.
funksjon killPlayer () numberOfLives = numberOfLives-1; if (numberOfLives <= 0) then gameData.invaderNum = 1 composer.gotoScene("start") else playerIsInvincible = true spawnNewPlayer() end end
De spawnNewPlayer
funksjonen gjør spilleren til å falle inn og ut i noen sekunder. Det er en fin effekt å la brukeren vite at skipet er midlertidig uovervinnelig.
funksjon spawnNewPlayer () lokalnummerOfTimesToFadePlayer = 5 lokalnummerOfTimesPlayerHasFaded = 0 lokal funksjon fadePlayer () player.alpha = 0; overgang.to (spiller, time = 400, alfa = 1,) numberOfTimesPlayerHasFaded = numberOfTimesPlayerHasFaded + 1 hvis (numberOfTimesPlayerHasFaded == numberOfTimesToFadePlayer) then playerIsInvincible = falsk ende ende fadePlayer () timer.performWithDelay (400, fadePlayer, numberOfTimesToFadePlayer)
Vi bruker en lokal funksjon, fadePlayer
, som bruker overgangsbiblioteket til å modifisere alfa
verdien av spiller
. Vi holder styr på hvor mange ganger spiller
har bleknet inn og ut, og satte spillernes uovervinnelighet til falsk
når vi kommer til numberOfTimesToFadePlayer
. Vi bruker en timer til å ringe fadePlayer
funksjon for mange ganger numberOfTimesToFadePlayer
er lik.
Kjør spillet for å teste dette ut. De spiller
skal dø når en invaders kule treffer skipet. Hvis tre kuler rammer skipet, bør du bli tatt til start scene hvor du kan starte et nytt spill.
For å gjøre det enklere å teste, kommentere samtalen til moveInvaders
i gameLoop
fungere som vist nedenfor.
funksjon gameLoop () checkLayerBulletsOutOfBounds () --moveInvaders () checkInvaderBulletsOutOfBounds () end
Hvis du har klart å drepe hver invader, ville spillet ha kalt levelComplete
funksjon, som ikke eksisterer ennå. La fikse det. Legg til følgende kodeblokk.
funksjonsnivåComplete () gameData.invaderNum = gameData.invaderNum + 1 hvis (gameData.invaderNum <= gameData.maxLevels) then composer.gotoScene("gameover") else gameData.invaderNum = 1 composer.gotoScene("start") end end
Vi øker gameData.invaderNum
og, hvis det er mindre enn gameData.maxLevels
, vi overgår til spillet er slutt scene. Ellers har spilleren fullført alle nivåer og vi tilbakestilt gameData.invaderNum
til 1. Vi overgår til start scene hvor spilleren kan starte et nytt spill.
En enkel måte å teste dette på er å kommentere samtalen til moveInvaders
i gameLoop
funksjon og bruk knappene for å flytte skipet. Hvis det fortsatt er for vanskelig, kan du også kommentere de to anropene til killPlayer
i onCollision
metode.
Legg til følgende kode til gameover.lua å implementere spillet over scenen.
lokal komponent = krever ("komponent") lokal scene = komponent.newScene () lokal starFieldGenerator = krever ("starfieldgenerator") lokal pulsatingText = krever ("pulsatingtext") lokal nextLevelButton lokal starGenerator funksjonsscene: opprett (hendelse) lokal gruppe = selv .view starGenerator = starFieldGenerator.new (200, gruppe, 5) lokale invadersText = pulsatingText.new ("LEVEL COMPLETE", display.contentCenterX, display.contentCenterY-200, "Conquest", 20, gruppe) invadersText: setColor (1, 1, 1) invadersText: pulsate () nextLevelButton = display.newImage ("next_level_btn.png", display.contentCenterX, display.contentCenterY) gruppe: sett inn (nextLevelButton) sluttfunksjonsscene: show (event) lokale fase = event.phase komponist .removeScene ("gamelevel") hvis (fase == "gjorde") deretter nextLevelButton: addEventListener ("trykk", startNewGame) Runtime: addEventListener ("enterFrame", starGenerator) endeendens funksjonsscene: skjul .fase hvis (fase == "vil") så Runtime: removeEventListener ("enterF rame ", starGenerator) nextLevelButton: removeEventListener (" trykk ", startNewGame) slutten sluttfunksjon startNewGame () composer.gotoScene (" gamelevel ") slutt scene: addEventListener (" create "scene) scene: addEventListener (" show " scene: addEventListener ("skjul", scene) retur scene
Denne koden er veldig lik den start scene så du burde være kjent med det nå.
Den siste kollisjonskontrollen vi trenger å utføre er en kollisjon mellom spilleren og på inntrengerne. Legg til følgende kodeblokk til onCollision
metode vi så tidligere.
Funksjon onCollision (event) --SNIP - hvis (event.phase == "startet") så --SNIP-- hvis (event.object1.name == "player" og event.object2.name == "invader" ) så numberOfLives = 0 killPlayer () avslutte hvis (event.object1.name == "invader" og event.object2.name == "player") deretter numberOfLives = 0 killPlayer () slutten
Som vanlig må vi sjekke begge kollisjonssituasjonene. Vi satte numberOfLives
til 0 og ring killPlayer
. Ved innstilling numberOfLives
til 0 og påberope seg killPlayer
, spillet er over og spillovergangene til start scene.
Dette fullfører spillet vårt, men jeg foreslår at du prøver å utvide spillet med noen få ekstra funksjoner. For eksempel kan du vise spillerens liv i en HUD.
Jeg har også tatt med en UFO-grafikk i kildefilene. Du kan prøve å lage en UFO tilfeldig, og hvis spilleren treffer den med en kule, gi dem et ekstra liv.
Hvis du trenger hjelp med disse konseptene, sjekk ut min Plane Fighting Game-serie på Tuts+.
Hvis du har fulgt denne serien, bør du nå ha et fullt funksjonelt spill som ligner på de originale Space Invaders. Utvid på det og gjør det ditt eget. Jeg håper du fant denne opplæringen nyttig og har lært noen nye teknikker. Takk for at du leser.