Create en Space Invaders spillet i Corona: Implementing Gameplay
27
Del
6
Del
Dette Cyber mandag Envato Tuts + kurs vil bli redusert til bare $ 3. Ikke gå glipp av
Dette innlegget er en del av en serie som heter Opprett en Space Invaders spillet i Corona.Create et Space Invaders spillet i Corona. Prosjekt SetupCreate en Space Invaders spillet i Corona: Ferdigstilling GameplayWhat du skal lage < p> I den første delen av denne serien, har vi satt opp noen standarder for spillet og la grunnlaget for overgangen mellom scenene. I denne delen vil vi begynne å implementere spillets gameplay.
1. Et ord om Metatables
Lua programmeringsspråk ikke har en klasse system bygget i. Men ved å bruke Lua er metatable konstruksjon kan vi etterligne en klasse system. Det er et godt eksempel på Corona nettsiden som viser hvordan du kan implementere dette.
En viktig ting å merke seg er at Corona visningsobjekter ikke kan stilles som metatable. Dette har å gjøre med hvordan de underliggende C språkgrensesnitt med dem. En enkel måte å komme rundt dette på er å sette skjerm objekt som en nøkkel på et nytt bord og deretter sette det bordet som metatable. Dette er den tilnærmingen som vi tar i denne opplæringen.
Hvis du leser artikkelen ovenfor på Corona nettside, vil du ha lagt merke til at __Index metamethod ble brukt på metatable. Måten __Index metamethod verk, er at når du prøver å få tilgang til en fraværende felt i en tabell, utløser det tolken å lete etter en __Index metamethod. Hvis __Index er der, vil det se for feltet og gi resultatet, ellers vil det resultere i null.
2. Implementering PulsatingText Class
Spillet har tekst som kontinuerlig vokser og krymper, og skaper et pulserende teksteffekt. Vi vil skape denne funksjonaliteten som en modul, slik at vi kan bruke den gjennom hele prosjektet. Også, ved å ha det som en modul, kan vi bruke det i ethvert prosjekt som ville kreve denne typen funksjonalitet.
Legg til følgende i pulsatingtext.lua filen du opprettet i første del av denne opplæringen. Sørg for at denne koden og all koden fra her på er plassert over hvor du er tilbake på scenen objektet.
Lokal pulsatingText = {} lokale pulsatingText_mt = {__index = pulsatingText} funksjon pulsatingText.new (theText, positionX, positionY, theFont, theFontSize, Dersom Gruppe) lokal theTextField = display.newText (theText, positionX, positionY, theFont, theFontSize) lokal newPulsatingText = {theTextField = theTextField} Dersom Gruppe: Sett (theTextField) avkastning setmetatable (newPulsatingText, pulsatingText_mt) endfunction pulsatingText: SetColor (r, b , g) self.theTextField: setFillColor (r, g, b) endfunction pulsatingText: pulsere () transition.to (self.theTextField, {XScale = 4.0, ySkala = 4.0, tid = 1500, gjentakelser = -1}) endreturn pulsatingText
Vi skaper hovedtabellen pulsatingText og bordet for å bli brukt som metatable pulsatingText_mt. I den nye metoden, skaper vi Textfield objekt og legge den til bordet newPulsatingText som vil bli satt som metatable. Vi legg deretter til Textfield objektet til den gruppen som ble vedtatt i gjennom parameter, som vil være scenens gruppe hvor instantiate vi en forekomst av PulsatingText.
Det er viktig å sørge for at vi legger det til scenens gruppe, så det vil bli fjernet når scenen er fjernet. Til slutt satt vi metatable.
Vi har to metoder som har tilgang til Textfield objektet og utføre operasjoner på sine eiendommer. En setter farge ved hjelp av setFillColor metode og tar inn som parametre R, G og B-farger som et tall fra 0 til 1. Den andre bruker Transition biblioteket for å gjøre teksten vokse og krympe. Det forstørrer teksten ved hjelp av XScale og ySkala egenskaper. Stille gjentakelser eiendommen til -1 gjør handlingen gjentar alltid.
3. Bruke PulsatingText Class
Åpne start.lua og legge til følgende kode i scenen: skape metode
funksjon scene. Opprette (hendelse) --SNIP-- lokal invadersText = pulsatingText.new ("Invaderz", display.contentCenterX, display.contentCenterY-200, "Conquest", 20, gruppe) invadersText: SetColor (1, 1, 1) invadersText: pulsere () end
Vi skaper en ny Textfield forekomst med Ordet "Invaderz", satt sin farge, og kaller den pulsere metoden. Legg merke til hvordan vi passerte gruppen variabelen som en parameter for å sikre Textfield objektet blir lagt til denne scenen syn hierarki.
Jeg har tatt med en skrift i nedlas heter "Conquest" som har et futuristisk utseende til det. Sørg for at du legger den til prosjektet mappe hvis du ønsker å bruke den. Jeg lastet ned skriften fra dafont.com, som er en flott nettside for å finne tilpassede skrifter. Men sørg for at du følger lisensen skriften forfatteren har satt på plass.
For å bruke skriften, trenger vi også å oppdatere prosjektets build.settings fil. Ta en titt på den oppdaterte build.settings filen.
Innstillinger = {orientering = {default = "portrett", støttet = {"portrett"},}, iphone = {plist = {UIAppFonts = {"Conquest.ttf" }}}}
Hvis du tester prosjektet nå, bør du se teksten ble lagt til åstedet og pulserer som forventet.
4. Stjerne Feltet Generator
For å gjøre spillet litt mer interessant, er en rørende stjerne felt opprettet i bakgrunnen. For å oppnå dette, gjør vi det samme som vi gjorde med PulsatingText klassen og skape en modul. Lag en fil som heter starfieldgenerator.lua og legg følgende til det:
lokale starFieldGenerator = {} lokale starFieldGenerator_mt = {__index = starFieldGenerator} funksjons starFieldGenerator.new (numberOfStars, Vis-, starSpeed) lokal starGroup = display.newGroup () lokal Allstars = {} - tabell som inneholder alle stjernene for i = 0, numberOfStars gjøre lokale stjerne = display.newCircle (Math.random (display.contentWidth), Math.random (display.contentHeight), Math.random (2, 8)) stjerne: setFillColor (1, 1,1) starGroup: sett (stjerne) table.insert (Allstars, star) end Vis-: sett (starGroup) lokal newStarFieldGenerator = {Allstars = Allstars, starSpeed = starSpeed} returnere setmetatable (newStarFieldGenerator , starFieldGenerator_mt) endfunction starFieldGenerator: enterframe () selv: moveStars () selv: checkStarsOutOfBounds () endfunction starFieldGenerator: moveStars () for i = 1, # self.allStars gjøre self.allStars [i] .Y = self.allStars [i] .Y + self.starSpeed endendfunction starFieldGenerator: checkStarsOutOfBounds () for i = 1, # self.allStars gjøre hvis (self.allStars [i] .Y > display.contentHeight) så self.allStars [i] .x = Math.random (display.contentWidth) self.allStars [i] .Y = 0 slutten endendreturn starFieldGenerator
Vi først opprette hovedtabellen starFieldGenerator og metatable starFieldGenerator_mt. I den nye metoden, har vi en tabell Allstars som vil bli brukt til å holde en referanse til stjernene som er opprettet i for loop. Antall gjentakelser av for loop er lik numberOfStars og vi bruker Display objektets newCircle metode for å lage en hvit sirkel.
Vi posisjonerer sirkelen tilfeldig innenfor spillet skjermen grensene og også gi den en tilfeldig størrelse mellom 2 og 8. Vi setter hver stjerne inn i Allstars bordet og plassere dem i visningen som ble vedtatt som en parameter, som er scene syn.
Vi satt Allstars og starSpeed som taster på midlertidige tabellen og deretter tildele det som metatable. Vi trenger tilgang til Allstars bordet og starSpeed egenskaper når vi beveger stjernene.
Vi vil bruke to metoder for å flytte stjernene. Den starFieldGenerator: moveStars metoden gjør flytting av stjernene mens starFieldGenerator:. CheckStarsOutOfBounds metoden sjekker om stjernene er ute av skjermens grenser
Hvis stjernene er ute av spille skjermen området, genererer det en tilfeldig x posisjonen for den aktuelle stjerne og setter y-posisjon like over toppen av skjermen. Ved å gjøre dette, er vi i stand til å gjenbruke stjernene, og det gir en illusjon av en endeløs strøm av stjerner
Vi kaller disse funksjonene i starFieldGenerator. Enterframe metode. Ved å sette enterframe metoden direkte på dette objektet, kan vi sette dette objektet som sammenheng når vi legger arrangementet lytteren
Legg til følgende kode blokken til åstedet. Skape metode i start.lua:
funksjon scene: lage (hendelse) lokal gruppe = self.view starGenerator = starFieldGenerator.new (200, gruppe 5) startknappen = display.newImage ("new_game_btn.png", display.contentCenterX, display.contentCenterY + 100) Gruppe: Sett (startknappen) end
Legg merke til at vi påberopt seg starGenerator.new metoden når vi legger på startknappen. I hvilken rekkefølge du legger ting til scenen spiller ingen rolle. Hvis vi skulle legge dem inn etter startknappen, da noen av stjernene ville ha vært på toppen av knappen.
I hvilken rekkefølge du legger ting til scenen er i hvilken rekkefølge de vil dukke opp . Det finnes to metoder for skjermklassen, toFront og toBack, som kan endre denne rekkefølgen.
Hvis du teste spillet nå, bør du se scenen strødd med tilfeldige stjerner. De er ikke i bevegelse, men. Vi trenger å flytte dem i scenen: showet metode.
Funksjon scene showet metode for start.lua:: Vis (hendelse) --SNIP-- if (fase == "gjorde") da startknappen: Legg til følgende til scenen. AddEventListener ("tap", startGame) Spilletid: addEventListener ("enterframe", starGenerator) Sluttslutt
Her kan vi legge til enterframe hendelsen lytteren, som, hvis du husker, gjør stjernene flytte og sjekker om de er utenfor banen
<. p> Når du legger til en hendelse lytteren, bør du sørge for at du også fjerne den på et tidspunkt senere i programmet. Stedet å gjøre det i dette eksempelet er når scenen er fjernet. Skjul (hendelse) lokal fase = event.phase if (fase == "vil") da startknappen:: removeEventListener ("tap", startGame) Runtime legge følgende til åstedet:
salvelse scene skjule hendelsen. : removeEventListener ("enterframe", starGenerator) Sluttslutt
Hvis du teste spillet nå, bør du se stjernene i bevegelse, og det vil virke som en endeløs strøm av stjerner. Når vi legger til spilleren, vil det også gi en illusjon av spilleren beveger seg gjennom rommet.
5. Spill nivå
Når du trykker på startknappen knappen, blir du tatt til spillet nivå scene, som er en blank skjerm i øyeblikket. La oss fikse det
Trinn 1:. Lokal Variabler
Legg den under kodebiten til gamelevel.lua. Du bør sørge for at denne koden og all koden fra dette punktet er over der du er tilbake på scenen objektet. Dette er de lokale variabler vi trenger for spillet nivå, hvorav de fleste er selvforklarende.
Lokal starFieldGenerator = require ("starfieldgenerator") lokale pulsatingText = require ("pulsatingtext") lokale fysikk = krever ("fysikk") lokale gameData = require ("gamedata") physics.start () lokal starGenerator - en forekomst av starFieldGeneratorlocal playerlocal playerHeight = 125local playerWidth = 94local invaderSize = 32 - Bredden og høyden på inntrenger imagelocal leftBounds = 30 - venstre marginlocal rightBounds = display.contentWidth - 30 - retten marginlocal invaderHalfWidth = 16local inntrengerne = {} - Tabell som holder hele invaderslocal invaderSpeed = 5local playerBullets = {} - tabell som holder spillerne Bulletslocal canFireBullet = truelocal invadersWhoCanFire = {} - - Tabell som holder inntrengere som er i stand til å avfyre bulletslocal invaderBullets = {} lokale numberOfLives = 3local playerIsInvincible = falselocal rowOfInvadersWhoCanFire = 5local invaderFireTimer - timeren brukes til brann inntrenger bulletslocal gameIsOver = false; lokale drawDebugButtons = {} --Temporary knappene for å flytte aktør i simulatorlocal enableBulletFireTimer - timer som gjør at spilleren å skyte
Trinn 2: Legge til en stjerne Feltet
Som den forrige scene, har denne scenen også et bevegelig stjernefelt. Legg til følgende gamelevel.lua
funksjon scene. Opprette (hendelse) lokal gruppe = self.view starGenerator = starFieldGenerator.new (200, gruppe 5) end
Vi legger en stjerne felt til scenen. Som før, trenger vi å få stjernene beveger seg, som vi gjør på scenen. Showet metode
funksjon scene: Vis (hendelse) lokal fase = event.phase lokal previousScene = composer.getSceneName ("forrige" ) composer.removeScene (previousScene) lokal gruppe = self.view if (fase == "gjorde") så Spilletid: addEventListener ("enterframe", starGenerator) Sluttslutt
Vi tar ut den forrige scene og legge den enterframe hendelsen lytteren. Som jeg nevnte tidligere, når du legger til en hendelse lytteren, må du sørge for at du til slutt fjerne den. Vi gjør dette i scenen. Hide metode
funksjon scene: hide (hendelse) lokal fase = event.phase lokal gruppe = self.view if (fase == "vil") så Spilletid: removeEventListener (" enterframe ", starGenerator) Sluttslutt
Til slutt, vi bør legge til lytterne for å opprette, vise og skjule metoder. Hvis du kjører programmet nå, bør du ha en bevegelig stjernefelt
scene. AddEventListener ("skape", scene) scenen: addEventListener ("show", scene) scenen: addEventListener ("skjule", scene )
Trinn 3: Legge spilleren
I dette trinnet, vil vi legge spilleren til scenen og få den i bevegelse. Dette spillet bruker akselerometeret til å flytte spilleren. Vi vil også bruke en alternativ måte å flytte spilleren i simulatoren ved å legge knappene til scenen. Legg inn følgende kode til gamelevel.lua.
Funksjon setupPlayer () lokale alternativer = {width = playerWidth, height = playerHeight, numFrames = 2} lokale playerSheet = graphics.newImageSheet ("player.png", alternativer) lokal sequenceData = {{start = 1, teller = 2, tid = 300, loopCount = 0}} spiller = display.newSprite (playerSheet, sequenceData) player.name = "player" player.x = display.contentCenterX- playerWidth /2 player. y = display.contentHeight - playerHeight - 10 spiller. play () scene.view: sett (spiller) lokal physicsData = (krever "shapedefs") physicsData (1,0) physics.addBody (spiller, physicsData: få ("skipet") ) player.gravityScale = 0end
Denne spilleren er en SpriteObject eksempel. Ved å ha spilleren være en sprite i stedet for et vanlig bilde, kan vi animere det. Spilleren har to separate bilder, ett med thruster engasjert og ett med thruster avslått.
Ved å bytte mellom de to bildene, skaper vi en illusjon av en endeløs fremstøt. Vi vil gjøre dette med et bilde ark, som er ett stort bilde sammensatt av en rekke mindre bilder. Ved å sykle gjennom de forskjellige bildene, kan du lage en animasjon.
Alternativ tabellen holder bredde, høyde og numFrames av de enkelte bildene i større format. Den numFrames variabelen inneholder verdien av antall mindre bilder. Den playerSheet er en forekomst av ImageSheet objektet, som tar som parametre bildet og alternativer tabellen.
sequenceData variabel brukes av SpriteObject eksempel, er startnøkkelen bildet du ønsker å starte en sekvens eller animasjon på mens tellingen nøkkel er hvor mange totalbilder er det i animasjonen. Klokken Nøkkelen er hvor lang tid det vil ta animasjonen til å spille og loopCount Nøkkelen er hvor mange ganger du ønsker animasjonen til å spille eller gjenta. Ved å sette loopCount til 0, vil det gjenta for alltid.
Til slutt oppretter du SpriteObject eksempel ved passering i ImageSheet forekomst og sequenceData.
Vi gir spilleren en nevne nøkkel, som vil bli brukt til å identifisere den senere. Vi har også satt sin x og y koordinater, påberope sin play-metoden, og sett det inn på scenen syn.
Vi skal bruke Corona innebygde fysikkmotor, som bruker den populære Box2D motor under panseret å detektere kollisjoner mellom objektene. Standard dueller bruker en markeringsramme metode for å detektere kollisjoner, noe som betyr at det plasserer en boks rundt objektet, og bruker det for kollisjoner. Dette fungerer ganske bra for rektangulære objekter, eller sirkler ved å bruke en radius eiendom, men for merkelig formede gjenstander det fungerer ikke så bra. Ta en titt på bildet nedenfor for å se hva jeg mener.
Du vil merke at selv om laseren ikke berører skipet, er det fortsatt registrerer seg som en kollisjon. Dette er fordi det er å kollidere med markeringsrammen rundt bildet.
For å overkomme denne begrensningen, kan du passere i en form parameter. Formen parameteren er en tabell av x og y-koordinatpar, hvor hvert par danner et toppunkt punkt for formen. Disse form parameter koordinatene kan være ganske vanskelig å finne ut av hånden, avhengig av kompleksiteten av bildet. For å overvinne dette, bruker jeg et program som heter PhysicsEditor.
physicsData variabelen er den filen som ble eksportert fra PhysicsEditor. Vi kaller det addBody metoden i fysikkmotor, passerer i spilleren og physicsData variabel. Resultatet er at kollisjonsdeteksjon vil bruke den faktiske grensene for romskip stedet for å bruke omgivende boks kollisjonsdeteksjon. Nedenfor bildet klargjør dette.
Du kan se at selv om laseren er innenfor markeringsrammen, ingen kollisjon utløses. Bare når det berører objektet kanten vil en kollisjon registreres.
Til slutt satt vi gravityScale til 0 på spilleren siden vi ikke vil at det skal bli påvirket av tyngdekraften.
Nå påberope setupPlayer i scenen: skape metode
funksjon scene. opprette (hendelse) lokal gruppe = self.view starGenerator = starFieldGenerator.new (100, gruppe 5) setupPlayer () end
Hvis du kjører spillet nå, bør du se spilleren lagt til scenen med sin thruster engasjert og aktivert
Trinn 4:. Flytte spilleren
Som nevnt tidligere, vi skal flytte spilleren ved hjelp av akselerometer. Legg til følgende kode i gamelevel.lua
lokal funksjon onAccelerate (hendelse) player.x = display.contentCenterX + (display.contentCenterX * (event.xGravity * 2)) endsystem.setAccelerometerInterval (60) Runtime.: addEventListener ("akselerometer", onAccelerate)
onAccelerate funksjonen vil bli kalt hver gang akselerometeret intervallet er avfyrt. Det er angitt å avfyre 60 ganger per sekund. Det er viktig å vite at akselerometeret kan være en stor belastning på batteriet i enheten. Med andre ord, hvis du ikke bruker den for en lengre periode, vil det være klokt å fjerne tilfelle lytteren fra den.
Hvis du tester på en enhet, bør du være i stand til å flytte spilleren ved å vippe enheten. Dette fungerer ikke når testing i simulatoren imidlertid. For å bøte på dette, vil vi lage noen midlertidige knapper
Trinn 5:.. Debug Knapper
Legg til følgende kode å trekke debug-knappene på skjermen
funksjons drawDebugButtons () lokal funksjon movePlayer (hendelse) if (event.target.name == "venstre") så player.x = player.x - 5 ElseIf (event.target.name == "riktig") så spiller .x = player.x + 5 end end lokal venstre = display.newRect (60,700,50,50) left.name = "left" scene.view: sett (til venstre) lokal høyre = display.newRect (display.contentWidth-60700 , 50,50) right.name = "right" scene.view: sett (høyre) igjen: addEventListener ("tap", movePlayer) høyre: addEventListener ("tap", movePlayer) end
Denne koden bruker skjer newRect metode for å trekke to rektangler til skjermen. Vi deretter legge et trykk selv lytter til dem som kaller den lokale movePlayer funksjonen.
6. Firing Bullets
Trinn 1: Legge til og Moving Bullets
Når brukeren kraner skjermen, spillerens skipet vil fyre av en kule. Vi skal begrense hvor ofte brukeren kan skyte en kule ved hjelp av en enkel tidtaker. Ta en titt på gjennomføringen av firePlayerBullet funksjon
funksjon firePlayerBullet () if (canFireBullet == true) da lokale tempBullet = display.newImage ("laser.png", player.x, player.y. - playerHeight /2) tempBullet.name = "playerBullet" scene.view: sett (tempBullet) physics.addBody (tempBullet, "dynamisk") tempBullet.gravityScale = 0 tempBullet.isBullet = true tempBullet.isSensor = true tempBullet: setLinearVelocity (0, -400) table.insert (playerBullets, tempBullet) lokal laserSound = audio.loadSound ("laser.mp3") lokale laserChannel = audio.play (laserSound) audio.dispose (laserChannel) canFireBullet = false ellers returnere slutten lokal funksjon enableBulletFire () canFireBullet = true slutten timer.performWithDelay (750, enableBulletFire, 1) end
Vi først sjekke om brukeren er i stand til å avfyre en kule. Vi deretter opprette en kule og gi den et navn eiendom slik at vi kan identifisere den senere. Vi legger det som en fysikk kroppen og gi den type dynamisk siden det vil være å flytte med en viss hastighet.
Vi setter gravityScale til 0, fordi vi ikke vil at det skal bli påvirket av tyngdekraften, sett isBullet eiendom til sann, og sette den til å være sensor for kollisjoner. Til slutt, vi kaller setLinearVelocity å få kulen går videre vertikalt. Du kan finne ut mer om disse egenskapene i dokumentasjonen for fysikk Bodies.
Vi laste og spille av en lyd, og deretter umiddelbart frigjøre minne forbundet med den lyden. Det er viktig å frigjøre minne fra lydobjekter når de ikke lenger er i bruk. Vi setter canFireBullet til false og starte en tidtaker som setter den tilbake til sann etter kort tid.
Vi trenger nå å legge springen lytteren til Runtime. Dette er forskjellig fra å legge til en kran lytteren til et enkelt objekt. Uansett hvor du trykker på skjermen, er Runtime lytteren sparken. Dette er fordi Runtime er den globale gjenstand for lyttere
funksjon scene. Showet (hendelse) --SNIP-- if (fase == "gjorde") så Spilletid: addEventListener ("enterframe", starGenerator) Spilletid: addEventListener ("tap", firePlayerBullet) Sluttslutt
Vi må også sørge for at vi vil fjerne denne hendelsen lytteren når vi ikke lenger trenger det
funksjon scene. hide (hendelse) if (fase = = "vil") så Spilletid: removeEventListener ("enterframe", starGenerator) Spilletid: removeEventListener ("tap", firePlayerBullet) Sluttslutt
Hvis du teste spillet og trykker på skjermen, en kule bør legges til skjermen og trekk til toppen av enheten. Det er et problem skjønt. Når kulen beveger seg utenfor skjermen, fortsetter de å bevege seg for alltid. Dette er ikke veldig nyttig for spillet minne. Tenk deg å ha hundrevis av kuler utenfor skjermen, flytter inn i uendeligheten. Det ville ta opp unødvendige ressurser. Vi skal fikse dette problemet i neste trinn
Trinn 2:. Fjerne Bullets
Når en kule blir opprettet, blir det lagret i playerBullets tabellen. Dette gjør det enkelt å referere hver kule og sjekke sine eiendommer. Det vi vil gjøre er å sløyfe gjennom playerBullets bordet, sjekke sin y eiendom, og hvis det er off-screen, fjerne den fra Display og fra playerBullet bordet.
Funksjons checkPlayerBulletsOutOfBounds () if (#playerBullets > 0) så for i = # playerBullets, 1, -1 gjøre hvis (playerBullets [i] .Y < 0) deretter playerBullets [i]: removeSelf () playerBullets [i] = null table.remove (playerBullets, jeg ) end end Sluttslutt
Et viktig poeng å merke seg er at vi er looping gjennom playersBullet bordet i motsatt rekkefølge. Hvis vi skulle sløyfe gjennom tabellen på vanlig måte, når vi fjerner et objekt det ville kaste indeksen av og forårsake en behandlingsfeil. Ved looping gjennom tabellen i omvendt rekkefølge, har objektet allerede er behandlet. Også viktig å merke seg er at når du fjerner et objekt fra Display, bør den settes til null.
Nå trenger vi et sted å kalle denne funksjonen. Den vanligste måten å gjøre dette på, er å lage et spill sløyfe. Hvis du er ukjent med konseptet av spillet loop, bør du lese denne korte artikkelen av Michael James Williams. Vi vil gjennomføre spillet sløyfe i neste trinn
Trinn 3:.. Lage spillet Loop
Legg til følgende kode i gamelevel.lua å komme i gang
funksjon gameLoop () checkPlayerBulletsOutOfBounds () end
Vi må kalle denne funksjonen gjentatte ganger så lenge spillet er i gang. Vi vil gjøre dette ved hjelp av Runtime s enterframe hendelsen.
Funksjon scene-show funksjon:: Vis (hendelse) --SNIP-- if (fase == "gjorde") så Spilletid: Legg til følgende i scenen. AddEventListener ("enterframe", gameLoop) Spilletid: addEventListener ("enterframe", starGenerator) Spilletid: addEventListener ("tap", firePlayerBullet) Sluttslutt
Vi må sørge for at vi vil fjerne denne hendelsen lytteren, når vi forlater denne scenen. Vi gjør dette i scenen: hide funksjon
funksjon scene. Hide (hendelse) if (fase == "vil") så Spilletid: removeEventListener ("enterframe", gameLoop) Spilletid: removeEventListener ("enterframe" , starGenerator) Spilletid: removeEventListener ("tap", firePlayerBullet) Sluttslutt
7. Invaders
Trinn 1: Legge Invaders
I dette trinnet, vil vi legge til inntrengerne. Start med å legge til følgende kode blokken
funksjons setupInvaders () lokal xPositionStart = display.contentCenterX -. InvaderHalfWidth - (gameData.invaderNum * (invaderSize + 10)) lokale numberOfInvaders = gameData.invaderNum * 2 + 1 for i = 1, gameData.rowsOfInvaders gjøre for j = 1, numberOfInvaders gjøre lokale tempInvader = display.newImage ("invader1.png", xPositionStart + ((invaderSize + 10) * (j-1)), i * 46) tempInvader.name = "invader" hvis (i == gameData.rowsOfInvaders) så table.insert (invadersWhoCanFire, tempInvader) end physics.addBody (tempInvader, "dynamisk") tempInvader.gravityScale = 0 tempInvader.isSensor = true scene.view: sett (tempInvader ) table.insert (inntrengerne, tempInvader) end Sluttslutt
Avhengig av hvilket nivå spilleren er på, vil radene inneholder et ulikt antall inntrengere. Vi setter hvor mange rader for å skape når vi legger til rowsOfInvaders nøkkelen til gameData tabellen (3). Den invaderNum brukes til å holde styr på hvilket nivå vi er på, men det er også brukt i noen beregninger.
For å få start x posisjon for inntrenger, vi trekker halve inntrenger bredde fra senter skjermen tallet. Vi deretter trekke uansett (invaderNum * invaderSize + 10) er lik. Det er en forskyvning av ti piksler mellom hver inntrenger, og det er derfor vi legger til invaderSize. Det kan alle virke litt forvirrende så ta deg tid til å forstå det.
Vi bestemmer hvor mange angripere det er per rad ved å ta invaderNum * 2 og legge en til det. For eksempel, på første nivå invaderNum er en slik vi vil ha tre inntrengerne per rad (1 * 2 + 1). På det andre nivået, vil det være fem angripere per rad, (2 * 2 + 1), etc.
Vi bruker nestet for løkker å sette opp rader og kolonner hhv. I den andre for loop skaper vi inntrengeren. Vi gir den et navn eiendom slik at vi kan referere til den senere. Hvis jeg er lik de gameData.rowsOfInvaders, så vi legger inntrenger til invadersWhoCanFire bordet. Dette sikrer at alle inntrengere på den nederste raden starter ut som å være i stand til å skyte kuler. Vi setter fysikken opp på samme måte som vi gjorde med spilleren tidligere, og sett inntrenger inn på scenen og inn i inntrengerne bordet slik at vi kan referere til den senere
Trinn 2:. Moving Invaders
I dette trinnet, vil vi flytte inntrengerne. Vi vil bruke gameLoop å sjekke inntrengerne stilling og reversere deres retning hvis det er nødvendig. Legg til følgende kode blokken å komme i gang.
Funksjons moveInvaders () lokal changeDirection = false for i = 1, #invaders gjøre Invaders [i] .x = Invaders [i] .x + invaderSpeed if (inntrengerne [ ,,,0],i] .x > rightBounds - invaderHalfWidth eller inntrengerne [i] .x < leftBounds + invaderHalfWidth) da changeDirection = true; end end if (changeDirection == true) så invaderSpeed = invaderSpeed * -1 for j = 1, #invaders gjøre Invaders [J] .Y = inntrengerne [j] .Y + 46 slutten changeDirection = false; end end
Vi sløyfe gjennom inntrengerne og endre sin x posisjon ved verdien som er lagret i invaderSpeed variabel. Vi se om inntrengeren er utenfor banen ved å sjekke leftBounds og rightBounds, som vi har satt opp tidligere.
Hvis en inntrenger er utenfor banen, satt vi changeDirection til sann. Hvis changeDirection er satt til sann, negere vi invaderSpeed variabel, flytter inntrengerne ned på y-aksen med 16 piksler, og tilbakestille changeDirection variabelen til false.
Vi påberope seg moveInvaders funksjon i gameLoop funksjons.
funksjon gameLoop () checkPlayerBulletsOutOfBounds () moveInvaders () end
8. Oppdage Kollisjoner
Nå som vi har noen inntrengere på skjermen og beveger seg, kan vi sjekke for kollisjoner mellom noen av spillerens kuler og inntrengerne. Vi utfører denne kontrollen i onCollision funksjonen.
Funksjon onCollision (hendelse) lokal funksjon removeInvaderAndPlayerBullet (hendelse) lokale params = event.source.params lokale invaderIndex = table.indexOf (inntrengerne, params.theInvader) lokal invadersPerRow = gameData.invaderNum * 2 + 1 if (invaderIndex > invadersPerRow) så table.insert (invadersWhoCanFire, inntrengerne [invaderIndex - invadersPerRow]) end params.theInvader.isVisible = false physics.removeBody (params.theInvader) table.remove (invadersWhoCanFire, table.indexOf (invadersWhoCanFire, params.theInvader)) if (table.indexOf (playerBullets, params.thePlayerBullet) ~ = null) deretter physics.removeBody (params.thePlayerBullet) table.remove (playerBullets, table.indexOf (playerBullets, params. thePlayerBullet)) display.remove (params.thePlayerBullet) params.thePlayerBullet = nil end end if (event.phase == "begynte") så hvis (event.object1.name == "inntrenger" og event.object2.name == "playerBullet") da lokale tm = timer.performWithDelay (10, removeInvaderAndPlayerBullet, 1) tm.params = {theInvader = event.object1, thePlayerBullet = event.object2} end if (event.object1.name == "playerBullet" og event .object2.name == "invader") da lokale tm = timer.performWithDelay (10, removeInvaderAndPlayerBullet, 1) tm.params = {theInvader = event.object2, thePlayerBullet = event.object1} slutten Sluttslutt
Det er to måter å gjøre dueller bruker Corona innebygde fysikkmotor. En måte er å registrere deg for kollisjonen på objektene selv. Den andre måten er å lytte globalt. Vi bruker global tilnærming i denne opplæringen.
I onCollision metoden, sjekker vi navnet egenskapene til objektene, satt en liten forsinkelse, og påkalle removeInvaderAndPlayerBullet funksjonen. Fordi vi ikke vet hva event.object1 og event.object2 vil peke på, må vi sjekke begge situasjoner derav de to motsatte hvis uttalelser.
Vi sender sammen noen parametere med timeren slik at vi kan identifisere playerBullet og inntrengeren innenfor removePlayerAndBullet funksjonen. Når du endrer egenskapene til et objekt i en kollisjon sjekk, bør du bruke en liten forsinkelse før du gjør det.