Lag et flykampspill i Corona Mer spill

Hva du skal skape

Introduksjon

I den tidligere opplæringen av denne serien begynte vi å implementere spillets spill og klarte allerede å få flyet til å bevege seg rundt på skjermen. I denne opplæringen fortsetter vi å implementere spillingen. La oss dykke rett inn i startTimers funksjon.

1. startTimers

Som navnet antyder, er startTimers funksjonen starter timeren. Legg til følgende kode til gamelevel.lua.

funksjon startTimers () slutten

Oppgi denne funksjonen i enterScene metode som vist nedenfor.

funksjonsscene: enterScene (event) lokalplanSound = audio.loadStream ("planesound.mp3") planetSoundChannel = audio.play (planetSound, loops = -1) Runtime: addEventListener ("enterFrame", gameLoop) startTimers

2. firePlayerBullet

De firePlayerBullet funksjonen skaper en kulde for spilleren.

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

Her bruker vi Display-objektet newImage metode for å skape kule. Vi posisjonerer den på en slik måte at den er i midten av flyet på x-aksen og øverst på planet på y-aksen. Kulen settes deretter inn i playerBullets bord for senere referanse og også inn i planeGroup.

3. Ringe firePlayerBullet

Vi må ringe firePlayerBullet fungere med jevne mellomrom for å sikre at spillerens plan automatisk skyver kuler. Legg til følgende kodestykke i startTimers funksjon.

funksjon startTimers () firePlayerBulletTimer = timer.performWithDelay (2000, firePlayerBullet, -1) slutten

Som navnet antyder, er timeren performWithDelay Metoden kaller en spesifisert funksjon etter at en tidsperiode er gått. Tiden er i millisekunder, så her ringer vi på firePlayerBullet Funksjon hvert 2. sekund. Ved å passere -1 Som det tredje argumentet vil timeren gjenta for alltid.

Hvis du tester spillet nå, bør du se at hvert eneste sekund vises en kule. Imidlertid beveger de seg ikke ennå. Vi vil ta vare på det i de neste trinnene.

4. movePlayerBullets

I movePlayerBullets, vi løp gjennom playerBullets bord og endre y koordinat av hvert punktum. Vi kontrollerer først for å sikre at playerBullets bordet har kuler i den. De # før playerBullets kalles lengde operatør og det returnerer lengden på objektet det er påkalt. Det er nyttig å vite at # operatør jobber også på strenger.

funksjon movePlayerBullets () hvis (#playerBullets> 0) så for i = 1, # playerBullets gjør playerBullets [i]. y = playerBullets [i] .y - 7 slutten slutten

Vi må påberope movePlayerBulletsgameLoop fungere som vist nedenfor.

funksjon gameLoop () --SNIP-- numberOfTicks = numberOfTicks + 1 movePlayer () movePlayerBullets () ende

5. checkPlayerBulletsOutOfBounds

Når en kule går på skjermen, er den ikke lenger relevant for spillet. Imidlertid er de fortsatt en del av playerBullets bord og fortsett å bevege seg som alle andre kuler i bordet. Dette er spild av ressurser, og hvis spillet skulle fortsette i svært lang tid, ville det resultere i hundrevis eller tusenvis av ubrukte objekter.

For å overvinne dette overvåker vi kulene, og når de beveger seg på skjermen, fjerner vi dem fra playerBullets bord samt fra fra displayet. Ta en titt på implementeringen av checkPlayerBulletsOutOfBounds.

funksjonskontrollPlayerBulletsOutOfBounds () hvis (#playerBullets> 0) så for i = # playerBullets, 1, -1 gjør hvis (playerBullets [i] .y < -18) then playerBullets[i]:removeSelf() playerBullets[i] = nil table.remove(playerBullets,i) end end end end

Det er viktig å merke seg at vi løper gjennom playerBullets bord i bakover. Hvis vi går gjennom bordet fremover, da, når vi fjerner en av kulene, vil den kaste loopingsindeksen av og forårsake en feil. Ved å løfte over bordet i omvendt rekkefølge, er den siste kulen allerede behandlet. De removeSelf Metoden fjerner skjermobjektet og frigjør dets minne. Som en god praksis bør du stille inn noen objekter nil etter å ha ringt removeSelf.

Vi påberoper denne funksjonen i gameLoop funksjon.

funksjon gameLoop () --SNIP-- movePlayer () movePlayerBullets () kontrollerBlitterBulletsOutOfBounds () ende

Hvis du vil se om denne funksjonen fungerer som den skal, kan du midlertidig sette inn en print ("Fjerner Bullet") uttalelse umiddelbart etter at skjermobjektet er satt til nil.

6. generateIsland

For å gjøre spillet mer interessant, genererer vi en øy hver så ofte, og flytter den nedover skjermen for å gi utseendet til flyet som flyr over øyene. Legg til følgende kodestykke for generateIsland funksjon.

funksjon generereIsland () lokal tempIsland = display.newImage ("island1.png", math.random (0, display.contentWidth - islandWidth), - islandHeight) table.insert (øyer, tempIsland) islandGroup: insert (tempIsland) end

Vi benytter oss av newImage metode igjen og plassere øya ved å sette en negativ verdi for islandHeight. For x stilling, bruker vi math.random metode for å generere et tall mellom 0 og vise's contentWidth minus islandWidth. Grunnen til at vi trekker bredden på øya er å sørge for at øya er helt på skjermen. Hvis vi ikke ville trekke øyas bredde, ville det være en sjanse for at en del av øya ikke ville være på skjermen.

Vi må starte en timer for å generere en øy hver så ofte. Legg til følgende utdrag til startTimers funksjonen vi opprettet tidligere. Som du kan se, genererer vi en øy hverfem sekunder. I neste trinn vil vi gjøre øyene flytte.

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

7. moveIslands

Gjennomføringen av moveIslands er nesten identisk med movePlayerBullets funksjon. Vi sjekker om øyer Bordet inneholder noen øyer, og hvis det gjør det, går vi gjennom det og flytter hver øy litt.

funksjon flytterlands () hvis (#islands> 0) da for i = 1, #islands øyene [i] .y = øyene [i] .y + 3 endeenden

8. checkIslandsOutOfBounds

Akkurat som vi kontrollerer om spillernes kuler har flyttet på skjermen, kontrollerer vi om noen av øyene hadde flyttet på skjermen. Gjennomføringen av checkIslandsOutOfBounds bør derfor se deg kjent. Vi sjekker om øyene y posisjonen er større enn display.contentHeight og hvis det er, vet vi at øya har beveget seg på skjermen og derfor kan fjernes.

FunksjonskontrollIslandsOutOfBounds () hvis (#islands> 0) så for i = # øyer, 1, -1 gjør hvis (øyene [i] .y> display.contentHeight) deretter øyene [i]: removeSelf () øyene [i] = nil table.remove (øyer, i) endeendens ende ende

9. generateFreeLife

Hver så ofte har spilleren en sjanse til å få et fritt liv. Vi genererer først et gratis livsbilde, og hvis spilleren kolliderer med bildet, får de et ekstra liv. Spilleren kan ha maksimalt seks liv.

funksjon generateFreeLife () hvis (numberOfLives> = 6) og deretter returnere ende lokal freeLife = display.newImage ("newlife.png", math.random (0, display.contentWidth - 40), 0); table.insert (freeLifes, freeLife) planeGroup: sett inn (freeLife) ende 

Hvis spilleren allerede har seks liv, gjør vi ingenting ved å returnere tidlig fra funksjonen. Hvis ikke, oppretter vi et nytt livsbilde og legger det til på skjermen. I likhet med hvordan vi plasserte øyene tidligere, satte vi bildet på et negativt y posisjon og generere en tilfeldig verdi for bildet x stilling. Vi legger det inn i freeLifes bord for å kunne referere det senere.

Vi må ringe denne funksjonen så ofte. Legg til følgende utdrag til startTimers funksjon.

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

10. moveFreeLives

Gjennomføringen av moveFreeLifes bør se kjent ut. Vi løper gjennom freeLifes bord og flytte hvert bilde i det.

funksjon moveFreeLifes () hvis (#freeLifes> 0) then for i = 1, # freeLifes gjør freeLifes [i] .y = freeLifes [i] .y +5 endeendens ende

Alt vi trenger å gjøre er å ringe moveFreeLifesgameLoop funksjon.

funksjon gameLoop () --SNIP-- checkIslandsOutOfBounds () moveFreeLifes () slutten

11. checkFreeLifesOutOfBounds

Følgende kodestykke skal også bli kjent med deg nå. Vi sjekker om noen av bildene i freeLifes bordet har flyttet på skjermen og fjern de som har.

funksjonen checkFreeLifesOutOfBounds () hvis (#freeLifes> 0) så for i = # freeLifes, 1, -1 gjør hvis (freeLifes [i] .y> display.contentHeight) then freeLifes [i]: removeSelf () freeLifes [i] = nil table.remove (freeLifes, i) endeendens ende ende 

Vi kaller denne funksjonen i gameLoop funksjon.

funksjon gameLoop () --SNIP-- checkIslandsOutOfBounds () moveFreeLifes () checkFreeLifesOutOfBounds () slutten

12. hasCollided

Vi må kunne fortelle når spillobjekter kolliderer med hverandre, for eksempel spillerenes plan og de frie livbildene, kulene og flyene, etc. Mens Corona tilbyr en meget robust fysikkmotor som lett kan håndtere sammenstøt mellom displayobjekter for oss, gjør det, legger litt overhead med beregningene motoren må gjøre hver ramme.

I dette spillet vil vi bruke et enkelt kollisjonsdeteksjonssystem for avgrensningsboks. Hva denne funksjonen gjør, er å sørge for at rektanglene eller grensekassene rundt to objekter ikke overlapper. Hvis de gjør det, kolliderer gjenstandene. Denne logikken er implementert i hasCollided funksjon.

funksjonen harCollided (obj1, obj2) hvis (obj1 == nil) deretter returnere falsk ende hvis (obj2 == nil) deretter returnere falsk ende lokal venstre = obj1.contentBounds.xMin <= obj2.contentBounds.xMin and obj1.contentBounds.xMax >= obj2.contentBounds.xMin lokal høyre = obj1.contentBounds.xMin> = obj2.contentBounds.xMin og obj1.contentBounds.xMin <= obj2.contentBounds.xMax local up = obj1.contentBounds.yMin <= obj2.contentBounds.yMin and obj1.contentBounds.yMax >= obj2.contentBounds.yMin lokal ned = obj1.contentBounds.yMin> = obj2.contentBounds.yMin og obj1.contentBounds.yMin <= obj2.contentBounds.yMax return (left or right) and (up or down) end

Jeg fant denne kodestykket på CoronaLabs nettsted. Det fungerer veldig bra, fordi spillobjektene i spillet vårt er rektangulære. Hvis du jobber med objekter som ikke er rektangulære, kan du bedre dra nytte av Coronas fysikkmotor, da kollisjonsdeteksjonen er svært godt optimalisert for dette.

1. 3. checkPlayerCollidesWithFreeLife

Vi ønsker å sjekke om spillerens fly har kollidert med et gratis livsobjekt. Hvis den har, gir vi spilleren et fritt liv.

FunksjonskontrollPlayerCollidesWithFreeLife () hvis (#freeLifes> 0) så for i = # freeLifes, 1, -1 gjør hvis (hasCollided (freeLifes [i], spiller)) then freeLifes [i]: removeSelf () freeLifes [i] = null table.remove (freeLifes, i) numberOfLives = numberOfLives + 1 hideLives () showLives () endeendens ende ende

I checkPlayerCollidesWithFreeLife funksjon, vi løp gjennom freeLives Tabell bakover av samme grunn som jeg beskrev tidligere. Vi kaller hasCollided fungere og passere i det aktuelle bildet og spillerens plan. Hvis de to objektene kolliderer, fjerner vi det gratis livbildet, øker numberOfLives variabel og ring til hideLives og showLives funksjon.

Vi påberoper denne funksjonen i gameLoop funksjon.

funksjon gameLoop () --SNIP - moveFreeLifes () checkFreeLifesOutOfBounds () checkPlayerCollidesWithFreeLife () slutten

14. hideLives

De hideLives funksjonsløkker gjennom livesImages bord og setter isVisible egenskapen til hvert livs bilde til falsk.

funksjon hideLives () for i = 1, 6 do livesImages [i] .isVisible = false end-end 

15. showLives

De showLives funksjonsløkker gjennom livesImages bord og angir hvert bilde isVisible eiendom til ekte.

funksjon showLives () for i = 1, numberOfLives gjør livesImages [i] .isVisible = true; slutten

Konklusjon

Dette bringer den tredje delen av denne serien til slutt. I neste og siste utgave av denne serien vil vi skape fiendens fly og fullføre spillets spill. Takk for at du leser og ser deg der.