Maak een vliegtuiggevecht in Corona meer gameplay

Wat je gaat creëren

Invoering

In de vorige zelfstudie van deze serie zijn we begonnen met het implementeren van de gameplay van de game en al in geslaagd om het vliegtuig op het scherm te laten bewegen. In deze zelfstudie gaan we door met het implementeren van de gameplay. Laten we gelijk duiken met de startTimers functie.

1. startTimers

Zoals de naam al aangeeft, is de startTimers functie start de timers. Voeg de volgende code toe aan gamelevel.lua.

functie startTimers () einde

Roep deze functie aan in de enterScene methode zoals hieronder getoond.

function scene: enterScene (event) local planeSound = audio.loadStream ("planeesound.mp3") planeSoundChannel = audio.play (planeSound, loops = -1) Runtime: addEventListener ("enterFrame", gameLoop) startTimers () einde

2. firePlayerBullet

De firePlayerBullet functie creëert een kogel voor de speler.

function firePlayerBullet () local tempBullet = display.newImage ("bullet.png", (player.x + playerWidth / 2) - bulletWidth, player.y-bulletHeight) table.insert (playerBullets, tempBullet); planeGroup: insert (tempBullet) end 

Hier gebruiken we het object Weergeven nieuw beeld methode om de kogel te creëren. We plaatsen het zodanig dat het zich in het midden van het vlak op de x-as en helemaal boven aan het vlak op de y-as bevindt. De kogel wordt vervolgens ingevoegd in de playerBullets tabel voor latere referentie en ook in de planeGroup.

3. Bellen firePlayerBullet

We moeten de firePlayerBullet functioneer periodiek om ervoor te zorgen dat het vliegtuig van de speler automatisch kogels afvuurt. Voeg het volgende codefragment toe in de startTimers functie.

function startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) einde

Zoals de naam al aangeeft, de Timer's performWithDelay methode roept een gespecificeerde functie aan nadat een periode is verstreken. De tijd is in milliseconden, dus hier noemen we de firePlayerBullet functioneer elke twee seconden. Door te passeren -1 als het derde argument, zal de timer voor altijd herhalen.

Als je het spel nu test, zou je moeten zien dat elke twee seconden een bolletje verschijnt. Ze zijn echter nog niet in beweging. Daar zullen we in de volgende paar stappen voor zorgen.

4. movePlayerBullets

In movePlayerBullets, we lopen door de playerBullets tabel en verander de Y coördinaat van elke kogel. We controleren eerst om zeker te zijn van de playerBullets tafel heeft kogels erin. De # voor playerBullets wordt het lengte operator en retourneert de lengte van het object waarop deze wordt aangeroepen. Het is handig om te weten dat de # operator werkt ook op strings.

function movePlayerBullets () if (#playerBullets> 0) en dan voor i = 1, # playerBullets doen playerBullets [i]. y = playerBullets [i] .y - 7 end end end

We moeten aanroepen movePlayerBullets in de gameLoop functie zoals hieronder getoond.

function gameLoop () --SNIP-- numberOfTicks = numberOfTicks + 1 movePlayer () movePlayerBullets () end

5. checkPlayerBulletsOutOfBounds

Wanneer een kogel van het scherm gaat, is deze niet langer relevant voor het spel. Ze maken echter nog steeds deel uit van de playerBullets tafel en blijven bewegen zoals elke andere opsommingsteken in de tabel. Dit is verspilling van middelen en als het spel heel lang door zou gaan, zou dit resulteren in honderden of duizenden ongebruikte objecten.

Om dit te verhelpen, monitoren we de kogels en, als ze eenmaal van het scherm zijn verwijderd, verwijderen we ze uit de playerBullets zowel als vanuit het display. Bekijk de implementatie van checkPlayerBulletsOutOfBounds.

function checkPlayerBulletsOutOfBounds () if (#playerBullets> 0) en dan voor i = # playerBullets, 1, -1 do if (playerBullets [i] .y < -18) then playerBullets[i]:removeSelf() playerBullets[i] = nil table.remove(playerBullets,i) end end end end

Het is belangrijk op te merken dat we door de playerBullets tafel naar achteren. Als we de tabel naar voren doorlopen, zullen we bij het verwijderen van een van de kogels de lusindex weggooien en een fout veroorzaken. Door de tabel in omgekeerde volgorde in een lus te plaatsen, is het laatste opsommingsteken al verwerkt. De removeSelf methode verwijdert het weergaveobject en maakt het geheugen vrij. Als een best practice, moet u alle objecten instellen nul na het bellen removeSelf.

We roepen deze functie aan in de gameLoop functie.

function gameLoop () --SNIP-- movePlayer () movePlayerBullets () checkPlayerBulletsOutOfBounds () einde

Als u wilt zien of deze functie goed werkt, kunt u tijdelijk een print ("Bullet verwijderen") direct nadat het weergaveobject is ingesteld nul.

6. generateIsland

Om het spel interessanter te maken, genereren we af en toe een eiland en verplaatsen het het scherm om het uiterlijk te geven van het vliegtuig dat over de eilanden vliegt. Voeg het volgende codefragment toe voor de generateIsland functie.

function generateIsland () local tempIsland = display.newImage ("island1.png", math.random (0, display.contentWidth - islandWidth), - islandHeight) table.insert (islands, tempIsland) islandGroup: insert (tempIsland) end

We maken gebruik van de nieuw beeld methode nogmaals en positioneer het eiland door een negatieve waarde in te stellen voor de islandHeight. Voor de X positie gebruiken we de Math.random methode om een ​​getal tussen te genereren 0 en de tonen's contentWidth minus de islandWidth. De reden dat we de breedte van het eiland aftrekken, is ervoor te zorgen dat het eiland volledig op het scherm staat. Als we de breedte van het eiland niet zouden aftrekken, zou er een kans zijn dat een deel van het eiland niet op het scherm zou verschijnen.

We moeten een timer starten om zo nu en dan een eiland te genereren. Voeg het volgende fragment toe aan de startTimers functie die we eerder hebben gecreëerd. Zoals je ziet, genereren we elk een eilandvijf seconden. In de volgende stap zullen we de eilanden laten bewegen.

function startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) generateIslandTimer = timer.performWithDelay (5000, generateIsland, -1) end

7. moveIslands

De implementatie van moveIslands is bijna identiek aan de movePlayerBullets functie. We controleren of het eilanden tafel bevat alle eilanden en als dat zo is, gaan we er doorheen en verplaatsen we elk eiland een beetje.

function moveIslands () if (#islands> 0) en dan voor i = 1, #islands do eilanden [i] .y = eilanden [i] .y + 3 end end end

8. checkIslandsOutOfBounds

Net zoals we controleren of de kogels van de speler van het scherm zijn verplaatst, controleren we of een van de eilanden buiten beeld is verplaatst. De implementatie van checkIslandsOutOfBounds moet je daarom bekend voorkomen. We controleren of de eilanden Y positie is groter dan display.contentHeight en als dat zo is, weten we dat het eiland buiten beeld is verplaatst en daarom kan worden verwijderd.

functie checkIslandsOutOfBounds () if (#islands> 0) en dan voor i = # eilanden, 1, -1 do if (eilanden [i] .y> display.contentHeight) en vervolgens eilanden [i]: removeSelf () eilanden [i] = nul table.remove (eilanden, i) einde end end end

9. generateFreeLife

Om de zoveel tijd heeft de speler een kans om een ​​gratis leven te krijgen. We genereren eerst een gratis afbeelding van het leven en als de speler in botsing komt met de afbeelding, krijgen ze een extra leven. De speler kan maximaal zes levens hebben.

function generateFreeLife () if (numberOfLives> = 6) en dan end end local freeLife = display.newImage ("newlife.png", math.random (0, display.contentWidth - 40), 0); table.insert (freeLifes, freeLife) planeGroup: insert (freeLife) end 

Als de speler al zes levens heeft, doen we niets door vroeg uit de functie terug te komen. Als dat niet het geval is, maken we een nieuwe levensafbeelding en voegen deze toe aan het scherm. Vergelijkbaar met hoe we de eilanden eerder hebben gepositioneerd, stellen we het beeld op een negatief Y positie en genereer een willekeurige waarde voor de afbeeldingen X positie. We plaatsen het vervolgens in de freeLifes tabel om er later naar te kunnen verwijzen.

We moeten deze functie af en toe bellen. Voeg het volgende fragment toe aan de startTimers functie.

function startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) generateIslandTimer = timer.performWithDelay (5000, generateIsland, -1) generateFreeLifeTimer = timer.performWithDelay (7000, generateFreeLife, - 1) end

10. moveFreeLives

De implementatie van moveFreeLifes moet bekend voorkomen. We lopen door de freeLifes tabel en verplaats elke afbeelding erin.

functie moveFreeLifes () if (#freeLifes> 0) en dan voor i = 1, # freeLifes doen freeLifes [i] .y = freeLifes [i] .y +5 end end end

We hoeven alleen maar te bellen moveFreeLifes in de gameLoop functie.

function gameLoop () --SNIP-- checkIslandsOutOfBounds () moveFreeLifes () einde

11. checkFreeLifesOutOfBounds

Het volgende codefragment hoort er nu ook bekend uit te zien. We controleren of een van de afbeeldingen in de freeLifes tafel zijn verplaatst van het scherm en verwijder degenen die hebben.

functie checkFreeLifesOutOfBounds () if (#freeLifes> 0) en dan voor i = # freeLifes, 1, -1 do if (freeLifes [i] .y> display.contentHeight) then freeLifes [i]: removeSelf () freeLifes [i] = nul table.remove (freeLifes, i) einde end end end 

We noemen deze functie in de gameLoop functie.

function gameLoop () --SNIP-- checkIslandsOutOfBounds () moveFreeLifes () checkFreeLifesOutOfBounds () einde

12. hasCollided

We moeten kunnen zien wanneer game-objecten met elkaar botsen, zoals het vliegtuig van de speler en de gratis afbeeldingen van het leven, de kogels en de vliegtuigen, enz. Hoewel Corona een zeer robuuste physics-engine biedt die botsingen tussen weergave-objecten gemakkelijk kan verwerken voor ons voegt dit een beetje overhead toe met de berekeningen die de motor in elk frame moet uitvoeren.

Voor de doeleinden van deze game zullen we een eenvoudig begrenzingsdetectiesysteem voor grensboxen gebruiken. Wat deze functie doet, is ervoor zorgen dat de rechthoeken of begrenzende vakken rond twee objecten elkaar niet overlappen. Als ze dat doen, botsen de objecten. Deze logica is geïmplementeerd in de hasCollided functie.

function hasCollided (obj1, obj2) if (obj1 == nil) retourneer dan false end if (obj2 == nil) en vals einde local left = obj1.contentBounds.xMin <= obj2.contentBounds.xMin and obj1.contentBounds.xMax >= obj2.contentBounds.xMin local right = obj1.contentBounds.xMin> = obj2.contentBounds.xMin en obj1.contentBounds.xMin <= obj2.contentBounds.xMax local up = obj1.contentBounds.yMin <= obj2.contentBounds.yMin and obj1.contentBounds.yMax >= obj2.contentBounds.yMin local down = obj1.contentBounds.yMin> = obj2.contentBounds.yMin en obj1.contentBounds.yMin <= obj2.contentBounds.yMax return (left or right) and (up or down) end

Ik heb dit codefragment gevonden op de CoronaLabs-website. Het werkt heel goed, omdat de spelobjecten in onze game rechthoekig zijn. Als u met een object werkt dat niet rechthoekig is, kunt u beter gebruikmaken van de physics-engine van Corona, omdat de botsingsdetectie hiervoor zeer goed is geoptimaliseerd..

13. checkPlayerCollidesWithFreeLife

We willen controleren of het vliegtuig van de speler in botsing is gekomen met een gratis levensobject. Als dat zo is, kennen we de speler een gratis leven toe.

function checkPlayerCollidesWithFreeLife () if (#freeLifes> 0) en dan voor i = # freeLifes, 1, -1 do if (hasCollided (freeLifes [i], player)) then freeLifes [i]: removeSelf () freeLifes [i] = nihil table.remove (freeLifes, i) numberOfLives = numberOfLives + 1 hideLives () showLives () end end end end

In de checkPlayerCollidesWithFreeLife functie doorlopen we de freeLives tafel achteruit om dezelfde reden die ik eerder heb beschreven. We noemen het hasCollided functie en geef de huidige afbeelding en het vliegtuig van de speler door. Als de twee objecten botsen, verwijderen we de gratis afbeelding van het leven, verhogen de numberOfLives variabele, en bel de hideLives en showLives functie.

We roepen deze functie aan in de gameLoop functie.

function gameLoop () --SNIP-- moveFreeLifes () checkFreeLifesOutOfBounds () checkPlayerCollidesWithFreeLife () einde

14. hideLives

De hideLives functie loopt door de livesImages tabel en stelt de is zichtbaar eigendom van elk levensbeeld aan vals.

function hideLives () voor i = 1, 6 do livesImages [i] .isVisible = false end end 

15. showLives

De showLives functie loopt door de livesImages tabel en stelt elke afbeelding in is zichtbaar eigendom aan waar.

function showLives () voor i = 1, numberOfLives do livesImages [i] .isVisible = true; einde

Conclusie

Dit brengt het derde deel van deze serie tot een einde. In het volgende en laatste deel van deze serie zullen we vijandelijke vliegtuigen maken en de gameplay van de game voltooien. Bedankt voor het lezen en zie je daar.