In het vorige deel van deze serie kregen we het schip van de speler in beweging, kregen de indringers beweging en ontdekten ze dat een speler-kogel een indringer had geraakt. In dit laatste deel van de serie zullen we de indringers de speler laten aanvallen, levels hanteren en de speler de mogelijkheid geven om te sterven.
Af en toe vuurt een van de indringers een kogel af. We zullen een timer gebruiken om dit te bereiken. Voeg de volgende code toe aan gamelevel.lua.
function fireInvaderBullet () if (#invadersWhoCanFire> 0) dan local randomIndex = 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 deze functie controleren we eerst of het invadersWhoCanFire
tabel bevat minstens één element. Als dat het geval is, voeren we de code uit in de if-instructie. Anders betekent dit dat het niveau voorbij is en we roepen het level voltooid
functie.
Er zal altijd tenminste één indringer zijn die een kogel kan afvuren tot je de laatste indringer doodt, op welk moment de invadersWhoCanFire
tafel zal leeg zijn.
Binnen de if-instructie genereren we een willekeurig getal randomIndex
afhankelijk van hoeveel items in de invadersWhoCanFire
tafel. We kiezen vervolgens dat item, randomInvader
, van de invadersWhoCanFire
tafel.
We maken een opsommingsteken, geef het een naam
zodat we het later kunnen identificeren, in de scène kunnen invoegen en dezelfde eigenschappen kunnen instellen als bij de kogel van de speler. Ten slotte voegen we de kogel in de invaderBullets
tafel zodat we er later naar kunnen verwijzen.
We moeten nu de timer instellen. Voeg het volgende toe aan de scène: toon
methode.
function scene: show (event) if (phase == "did") then --SNIP-- Runtime: addEventListener ("collision", onCollision) invaderFireTimer = timer.performWithDelay (1500, fireInvaderBullet, -1) end end
Elke 1500 milliseconden fireInvaderBullet
wordt aangeroepen. Merk op dat de laatste parameter die we doorgeven is -1
, wat betekent dat de timer voor altijd herhaalt. Telkens wanneer u een timer maakt die voor altijd wordt herhaald, moet u deze uiteindelijk annuleren. We doen dit in descène: verberg
functie zoals hieronder getoond.
function scene: hide (event) if (phase == "will") then --SNIP-- Runtime: removeEventListener ("collision", onCollision) timer.cancel (invaderFireTimer) end end
Net als de kogels van de speler zullen de kogels van de indringers buiten het scherm bewegen en blijven bewegen, waardoor ze waardevolle herinneringen opnemen. Om dit te verhelpen, verwijderen we ze net als bij de kogels van de speler.
functie checkInvaderBulletsOutOfBounds () if (#invaderBullets> 0) en dan voor i = # invaderBullets, 1, -1 do if (invaderBullets [i] .y> display.contentHeight) en dan invaderBullets [i]: removeSelf () invaderBullets [i] = nul table.remove (invaderBullets, i) einde end end end
Deze code lijkt sterk op het controleren of de kogels van de speler buiten de grenzen vallen, dus ik zal de implementatie ervan niet in detail bespreken.
De volgende stap is om te detecteren of de kogel van een indringer de speler heeft geraakt. Voeg de volgende code toe aan de onCollision
functie.
function onCollision (event) if (event.phase == "started") then --SNIP-- if (event.object1.name == "player" en event.object2.name == "invaderBullet") then table.remove (invaderBullets, table.indexOf (invaderBullets, event.object2)) event.object2: removeSelf () event.object2 = nil if (playerIsInvincible == false) en killPlayer () end return end if (event.object1.name == " invaderBullet "en event.object2.name ==" player ") en vervolgens table.remove (invaderBullets, table.indexOf (invaderBullets, event.object1)) event.object1: removeSelf () event.object1 = nil if (playerIsInvincible == false ) en vervolgens killPlayer () end end end end return
Net als voorheen weten we niet welk object event.object1
en event.object2
zal zo zijn dat we twee if-statements gebruiken om beide situaties te controleren. We verwijderen de kogel van de indringer van de invaderBullets
tafel, verwijder het van het display en stel het in op nul
. Als de speler niet onoverwinnelijk is, doden we het.
Wanneer we de speler doden, geven we hem een korte tijd van onoverwinnelijkheid. Dit geeft de gebruiker de tijd om zich weer op het spel te concentreren. Als het numberOfLives
variabele is gelijk aan 0
, we weten dat het spel voorbij is en gaan over op de begin scène waar de gebruiker een nieuw spel kan beginnen.
function killPlayer () numberOfLives = numberOfLives- 1; if (numberOfLives <= 0) then gameData.invaderNum = 1 composer.gotoScene("start") else playerIsInvincible = true spawnNewPlayer() end end
De spawnNewPlayer
functie maakt de speler een paar seconden lang in- en uitfaden. Het is een leuk effect om de gebruiker te laten weten dat het schip tijdelijk onoverwinnelijk is.
function spawnNewPlayer () local numberOfTimesToFadePlayer = 5 local numberOfTimesPlayerHasFaded = 0 lokale functie fadePlayer () player.alpha = 0; transition.to (speler, time = 400, alpha = 1,) numberOfTimesPlayerHasFaded = numberOfTimesPlayerHasFaded + 1 if (numberOfTimesPlayerHasFaded == numberOfTimesTo FadePlayer) then playerIsInvincible = false end end fadePlayer () timer.performWithDelay (400, fadePlayer, numberOfTimesToFadePlayer) einde
We gebruiken een lokale functie, fadePlayer
, die de overgangsbibliotheek gebruikt om de alpha
waarde van de speler
. We houden bij hoeveel keer de speler
is in en uit vervaagd en de onoverwinnelijkheid van de speler ingesteld vals
zodra we de numberOfTimesToFadePlayer
. We gebruiken een timer om het te bellen fadePlayer
functie voor vele keren numberOfTimesToFadePlayer
is gelijk aan.
Start het spel om dit uit te testen. De speler
zou moeten sterven als de kogel van een indringer het schip raakt. Als drie kogels het schip raken, moet u naar de begin scène waarin u een nieuw spel kunt starten.
Om dit gemakkelijker te testen, geeft u een commentaar op de aanroep moveInvaders
in de gameLoop
functie zoals hieronder getoond.
function gameLoop () checkPlayerBulletsOutOfBounds () --moveInvaders () checkInvaderBulletsOutOfBounds () end
Als je elke indringer hebt vermoord, zou het spel het level voltooid
functie, die nog niet bestaat. Laat dat oplossen. Voeg het volgende codeblok toe.
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
We verhogen gameData.invaderNum
en, als het minder is dan gameData.maxLevels
, we gaan over naar de spel is over tafereel. Anders heeft de speler elk niveau voltooid en zijn we gereset gameData.invaderNum
naar 1. We gaan over naar de begin scène waarin de speler een nieuw spel kan beginnen.
Een eenvoudige manier om dit te testen, is door de oproep aan te geven moveInvaders
in de gameLoop
functie en gebruik de knoppen om het schip te verplaatsen. Als dat nog steeds te moeilijk is, dan kun je ook de twee oproepen aan commentaart killPlayer
in de onCollision
methode.
Voeg de volgende code toe aan gameover.lua om het spel over scène te implementeren.
local composer = require ("composer") local scene = composer.newScene () local starFieldGenerator = require ("starfieldgenerator") local pulsatingText = require ("pulsatingtext") local nextLevelButton lokale starGenerator functiescène: 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) group: insert (nextLevelButton) functie van einde-functie: show (event) local phase = event.phase composer .removeScene ("gamelevel") if (phase == "did") then nextLevelButton: addEventListener ("tap", startNewGame) Runtime: addEventListener ("enterFrame", starGenerator) eindscènescène: hide (gebeurtenis) lokale fase = gebeurtenis .fase als (fase == "zal") dan Runtime: removeEventListener ("enterF rame ", starGenerator) nextLevelButton: removeEventListener (" tap ", startNewGame) end-end-functie startNewGame () composer.gotoScene (" gamelevel ") eindscène: addEventListener (scène" create ", scène): addEventListener (" show ", scène) scène: addEventListener (scène "verbergen", scène) retourneert scène
Deze code lijkt veel op de begin scène, zodat je er nu bekend mee bent.
De laatste botsingcontrole die we moeten uitvoeren, is een botsing tussen de speler en een van de indringers. Voeg het volgende codeblok toe aan de onCollision
methode die we eerder zagen.
function onCollision (event) --SNIP-- if (event.phase == "started") then --SNIP-- if (event.object1.name == "player" en event.object2.name == "invader" ) vervolgens numberOfLives = 0 killPlayer () einde if (event.object1.name == "invader" en event.object2.name == "player") dan numberOfLives = 0 killPlayer () end end
Zoals gewoonlijk moeten we beide botsingssituaties controleren. We hebben de numberOfLives
naar 0 en bel killPlayer
. Door in te stellen numberOfLives
naar 0 en aanroepen killPlayer
, het spel is voorbij en het spel gaat over naar de begin tafereel.
Hiermee is onze game voltooid, maar ik raad aan om de game uit te breiden met een paar extra functies. U kunt bijvoorbeeld de levens van de speler in een HUD weergeven.
Ik heb ook een UFO-afbeelding opgenomen in de bronbestanden. Je zou kunnen proberen om een UFO willekeurig te laten verschijnen en als de speler hem met een kogel raakt, geef hem een extra leven.
Als je hulp nodig hebt met deze concepten, bekijk dan mijn Plane Fighting Game-serie over Tuts+.
Als je deze serie hebt gevolgd, zou je nu een volledig functioneel spel moeten hebben dat lijkt op het originele Space Invaders. Breid het uit en maak het uw eigen. Ik hoop dat je deze tutorial nuttig hebt gevonden en wat nieuwe technieken hebt geleerd. Bedankt voor het lezen.