În această serie de tutori, vom învăța cum să creați un joc de shooter spațiu, la fel ca jocul clasic Space Defender. Citește mai departe!
În această versiune a Space Defender, jucătorul va trebui să-și apere spațiul prin împușcarea dușmanilor. De fiecare dată când jucătorul distruge cu succes un inamic, va câștiga puncte și atunci când jucătorul a ajuns la 20 sau 40 de puncte, arma lor va primi un upgrade. Pentru a amesteca lucrurile, acest joc va trimite pachete bonus care sunt în valoare de 5 puncte. Pentru a vedea jocul în acțiune, urmăriți videoclipul de mai sus.
În partea a 1 a acestei serii am învățat cum să configurați aplicația noastră, cum să folosim fonturi personalizate, cum să folosim un storyboard și cum să configuram meniul principal. În Partea 2 din această serie, vom învăța cum să creăm modul de joc al aplicației noastre. Deci sa începem!
Primul nostru pas este crearea unui nou fisier numit game.lua. Odată ce a fost creat, deschideți fișierul în editorul dvs. preferat.
Deoarece începem o nouă scenă, trebuie să cerem niște biblioteci. Vom folosi motorul de fizică integrat în Corona SDK pentru detectarea coliziunilor.
comanda locală = necesită ("storyboard") scena locală = storyboard.newScene () fizica locală = necesită ("fizica")
După configurarea bibliotecilor noastre, vom configura motorul de fizică. Setările de mai jos vor stabili gravitatea la 0 (la fel ca în spațiu) și vor seta iterațiile la 16. SetPositionIterations înseamnă că motorul va trece prin 16 poziții pe cadru. Orice mai mare decât 16 poate afecta negativ performanța jocului.
fizics.start () fizics.setGravitate (0, 0) fizica.setPositionIterații (16)
Deși acest pas nu este necesar pentru acest tutorial, este o practică bună de a "însuma" generatorul de numere aleatoare. Îmi place să folosesc timpul curent pentru a însămânța generatorul.
math.randomseed (os.time ())
Acum vom defini câteva variabile pentru jocul nostru. Fiecare variabilă are un comentariu în dreptul acestuia, explicând scopul variabilei.
ecran local, screenH, jumătateW, halfY = display.contentWidth, display.contentHeight, display.contentWidth * 0.5, display.contentHeight * 0.5 local gameover_returntomenu - înainte declard jocul nostru de peste buton - Configurați setările de joc motionx = 0; - variabilă pentru a deplasa caracterul de-a lungul axei y = 10; - Controlează viteza jucătoruluiScore = 0; - Seteaza jucatorul scor playerLives = 20; - Seteaza numarul de viata pentru jucator slowEnemySpeed = 2375; - Setează cât de repede se varsă navele albe pe ecran slowEnemySpawn = 2400; - Setează viteza de repornire a navei albă fastEnemySpeed = 1875; - Setează cât de repede se varsă navele verzi pe ecran rapidEnemySpawn = 1800; - Setează rata de reproducere a navelor verzi bulletSpeed = 325; - Seteaza cat de repede glontele traverseaza ecranul bulletSpawn = 250; - Setează rata de declanșare a bulletului
După crearea variabilelor, vom configura scena din interiorul funcției scena: createScene
. Dacă vă amintiți din Partea 1, această funcție este utilizată pentru a crea elemente vizuale și logica jocurilor. Într-o funcție ulterioară, vom apela la aceste funcții pentru a rula jocul.
În următorul cod, creăm scena: createScene
funcția și adăugarea fundalului și a pereților de sus / de jos. Ambii pereți sunt configurați ca obiecte fizice statice pentru a împiedica player-ul de a ieși din ecran.
funcția scena: createScene (eveniment) grup local = auto.view - Configurarea elementelor vizuale și a zidurilor locale bg = display.newImageRect ("images / BKG.png", 480, 320) bg.x = (0,0,0) topwall.alpha = 0,01 fizics.addBody (topwall, "static ") grup: inserați (topwall) local bottomwall = display.newRect (0,0, screenW, 20) bottomwall.y = 325 bottomwall: setFillColor (0,0,0) bottomwall.alpha = 0.01 physics.addBody static "): introduceți (inferior) sfârșitul
În interiorul aceluiași scena: createScene
funcție, dar după bottomwall
obiectul de afișare, vom adăuga încă patru obiecte de afișare. Iată o explicație a scopului fiecărui obiect.
btn_up
, btn_down
: Aceste obiecte de afișare vor acționa ca butoane în partea stângă a ecranului și fiecare obiect va deplasa nava în sus sau în jos, respectiv. Cu toate acestea, acestea nu sunt operabile până când nu am setat funcția de mutare.enemyHitBar
: Acest obiect de afișare este configurat ca un senzor și va reacționa numai la coliziuni fizice. Când reacționează la coliziuni, va elimina obiectul inamic și va scădea unul din viețile jucătorului.local btn_up = display.newRect (0,0,75,160) btn_up: setReferencePoint (display.TopLeftReferencePoint) btn_up.x, btn_up.y = 0,0; btn_up.alpha = 0.01 grup: inserați (btn_up) local btn_down = display.newRect (0,0,75,160) btn_down: setReferencePoint (display.BottomLeftReferencePoint) btn_down.x, btn_down.y = 0, screenH; btn_down.alpha = 0.01 grup: inserați (btn_down) local enemyHitBar = display.newRect (-20,0,20,320) enemyHitBar: setFillColor (0,0,0) enemyHitBar.name = "enemyHitBar" fizics.addBody (enemyHitBar, isSensor = true) grup: inserați (enemyHitBar)
Imediat după obiectul de afișare al adversaruluiHitBar, vom adăuga câteva elemente GUI pentru afișarea scorului jucătorului și a jucătorului. Vom afișa, de asemenea, un text pe ecran care spune "Deplasare în sus" și "Deplasare în jos" pentru a informa jucătorul în cazul în care trebuie să atingă pentru a muta nava în sus sau în jos.
local gui_score = display.newText ("Scor:" ... playerScore, 0,0, "Kemco Pixel", 16) gui_score: setReferencePoint (display.TopRightReferencePoint) gui_score.x = grupul screenW: inserați gui_lives = display.newText ("Locuieste:" ... jucatorViveste, 0,0, "Kemco Pixel", 16) gui_lives: setReferencePoint (display.BottomRightReferencePoint) gui_lives.x = ecranW gui_lives.y = ecranH grup: inserare gui_moveup = display.newText "Move Up", 0,050,100, "Kemco Pixel", 16) grup: inserați (gui_moveup) local gui_movedown = display.newText (" ) gui_movedown: setReferencePoint (afișare.BottomLeftReferencePoint) gui_movedown.y = ecranH grup: inserați (gui_movedown)
Apoi, vom adăuga nava jucătorului pe ecran. Nava va fi adăugată ca obiect fizic dinamic, astfel încât să poată reacționa la coliziuni cu alte obiecte fizice. Vom intra în profunzime în urma coliziunilor ulterioare în acest tutorial.
nava locală = display.newImageRect ("images / spaceShip.png", 29, 19) ship.x, ship.y = 75,35 shipname = nava physics.addBody (navă, "dynamic", friction = 0.5, bounce = 0) grup: inserați (navă)
Vă amintiți btn_up
și btn_down
obiectele afișate pe care le-am adăugat? Acum vom adăuga ascultători de evenimente la aceste obiecte pentru a ajuta la mutarea navei jucătorului. Cand btn_up
este atins, ne vom face variația vitezei negative și când btn_down
este atins vom face viteza noastră pozitivă. Făcând această variabilă pozitivă și negativă, ne spunem următoarea noastră funcție de a muta nava în sus sau în jos.
-- Când butonul de sus este atins, setați mișcarea pentru a muta funcția de navă btn_up: touch () motionx = -speed; end btn_up: addEventListener ("atinge", btn_up) - Atunci când butonul de jos este atins, setați mișcarea pentru a muta funcția de navă btn_down: touch () motionx = speed; end btn_down: addEventListener ("atingeți", btn_down)
După ce am adăugat ascultătorilor evenimentului nostru btn_up
și btn_down
obiecte de afișare, vom crea doi ascultători de evenimente runtime cu funcțiile lor respective. Aceste funcții se vor executa în fiecare cadru, iar funcția de captură cu funcții de rulare este aceea că trebuie să specificați când să le opriți. Vom acoperi asta mai târziu. Pentru moment, funcția stop va seta variabila MotionX
la 0 (deoarece niciun buton nu este atins) și moveguy
funcția va adăuga variabila MotionX
la nava noastră y
poziţie.
funcția stop local (eveniment) dacă event.phase == "a terminat" apoi motionx = 0; sfârșitul sfârșitului Runtime: addEventListener ("atingeți", opriți) - Această funcție va muta de fapt nava pe baza mișcării funcției locale motionguy (eveniment) ship.y = ship.y + motionx; sfârșitul runtime: addEventListener ("enterFrame", moveguy)
Până acum, avem nava noastră în mișcare, dar nu arde! Pentru ca nava să fie gata să tragă gloanțe, trebuie să creăm fireShip ()
funcţie. Această funcție va crea noi obiecte de afișare care reacționează la ciocnirile fizicii și această funcție va muta și obiectul pe ecran de la stânga la dreapta.
Pentru a face jocul mai interesant, vom permite jucătorului să tragă mai multe gloanțe atunci când ating un anumit punctaj. Când jucătorul ajunge la 20 de ani, nava va trage două gloanțe și când jucătorul ajunge la 40, nava va declanșa un al treilea glonț care trage în diagonală în jos.
funcția fireShip () bullet = display.newImageRect ("images / bullet.png", 13, 8) bullet.x = ship.x + 9 bullet.y = ship.y + 6 bullet: toFront bullet "fizica.addBody (bullet, isSensor = true) transition.to (bullet, time = bulletSpeed, x = 500, onComplete = function (self) self.parent: remove; ) dacă (playerScore> = 20), apoi secondBullet = display.newImageRect ("images / bullet.png", 13, 8) secondBullet.x = ship.x + 9 secondBullet.y = ship.y + ) secondBullet.name = "bullet" fizica.addBody (secondBullet, isSensor = true) transition.to (secondBullet, time = bulletSpeed, x = 500, onComplete = function (self) self.parent: remove; ()) end if (playerScore> = 40) apoi thirdBullet = display.newImageRect ("images / bullet.png", 13, 8) thirdBullet.x = ship.x + 9 thirdBullet.y = y + 12 treilea nivel: toFront () thirdBullet.name = "bullet" fizics.addBody (treaptaBullet, isSensor = true) transition.to (thirdBullet, time = bulletSpeed, x = 500, y = navă.y + 100, onComplete = funcție (auto) auto.parent: eliminare (auto); auto = zero; Sfârșit; )
După ce ne-am înființat corabia, trebuie să dăm jucătorului niște dușmani care să tragă! Vom crea două funcții diferite - createSlowEnemy ()
și createFastEnemy ()
. Ambele funcții vor crea un obiect de afișare a fizicii care se mișcă de la dreapta la stânga cu viteza inamicului, iar imaginea fiind singura diferență.
(de exemplu, imaginile / enemy.png, 32, 26) enemy.ro = 180 enemy.x = 500 enemy.y = math.random (10, screenH-10) enemy.name = "inamic" fizica.addBody (inamic, isSensor = true) transition.to (inamic, time = slowEnemySpeed, x = -20) end function createFastEnemy () enemy = display.newImageRect ("images / fastEnemy.png" , 32, 26) enemy.ro = 180 enemy.x = 500 enemy.y = math.random (10, screenH-10) enemy.name = "inamic" physics.addBody (inamic, isSensor = true). (inamicul, time = fastEnemySpeed, x = -20)
Apoi, vom crea pachete de bonus pentru ca jucătorul să se apuce în interiorul funcției createBonus ()
. createBonus ()
funcția va crea un obiecte de afișare fizică care se deplasează din dreapta spre stânga și fiecare pachet bonus pe care îl primește jucătorul, vor câștiga 5 puncte.
(bonusuri, bonusuri, bonusuri, bonusuri, bonusuri, bonusuri, bonusuri, bonusuri, bonusuri etc.) createBonus () bonus = display.newImageRect (" "bonus" fizica.addBody (bonus, isSensor = true) transition.to (bonus, time = 1475, x = -20, onComplete = function () display.remove bonus =
Următoarea noastră funcție este funcția updateLives (). Această funcție va fi apelată de fiecare dată când un inamic trece prin player pentru a da jucătorului obiectivul de a-și apăra partea laterală a spațiului. Dacă numărul de vieți este mai mare de 0, atunci această funcție va scade o viață și va actualiza textul pe ecran. În caz contrar, va avea ca rezultat un joc peste scenă.
În jocul de pe scenă, anulează toate cronometrele și eliminăm toți ascultătorii evenimentului nostru. Cu SDK-ul Corona, este foarte important să rețineți că trebuie să-i spuneți în mod explicit aplicației dvs. când să eliminați ascultătorii și cronometrele runtime (numai când cronometrul funcționează). După ce au fost eliminate, vom afișa un mesaj peste joc și vom permite jucătorului să revină la meniu.
funcția updateLives () dacă (playerLives> = 0), apoi playerLives = playerLives - 1 gui_lives.text = "Lives:" ... playerVezi gui_lives.x = screenW else timer.cancel (tmr_fireShip) timer.cancel (tmr_sendSlowEnemies) timer.cancel (tmr_sendSlowEnemies2 ) timer.cancel (tmr_sendFastEnemies) Timer.cancel (tmr_sendBonus) Timp de execuție: removeEventListener ("collision", onCollision) Runtime: removeEventListener ("enterFrame", moveguy) Runtime: removeEventListener gameover_message = display.newText ("Game Over!", 0,0, "Kemco Pixel", 32) gameover_message.x = jumătate W gameover_message.y = jumătate Y - 15 grup: insert (gameover_message) returnToMenuTouch (event) if (event. faza == "a început"), apoi storyboard.gotoScene ("meniu", "slideRight", "1000") sfârșitul final gameover_returntomenu = display.newText ("Return to Menu", 0.0, "Kemco Pixel", 28) gameover_returntomenu .x = jumătateW jocover_returntomenu.y = jumătateY + 35 gameover_returntomenu: addEventListener ("atingeți", returnToMenuTouch) grup: în sert (gameover_returntomenu) sfârșitul final
Suntem gata pentru funcția noastră finală în interiorul scenei noastre: createScene () function! Această funcție se va ocupa de toate detectările de coliziune prin compararea proprietății numele meu
de obiect1 la cel deținut de obiectul 2. Fiecare obiect este trecut ca parametru pentru această funcție sub numele de variabilă eveniment
.
Pentru a vă ușura, am distrus cele cinci cazuri de coliziune.
(event.object1.name == "bullet" și event.object2.name == "inamic"), apoi display.remove (event.object2) playerScore = playerScore + 1 elseif (event.object1.name == "inamic" și event.object2.name == "bullet"), apoi display.remove (event.object1) playerScore = playerScore + 1 elseif (event.object1.name == "ship" și event.object2.name = = "bonus"), apoi display.remove (event.object2) playerScore = playerScore + 5 elseif (event.object1.name == "inamic" și event.object2.name == "enemyHitBar"), apoi display.remove (event. object1) updateLives () elseif (event.object1.name == "enemyHitBar" și event.object2.name == "inamic") apoi display.remove (event.object2) updateLives () end gui_score.text = "Scorul:" ... playerScore gui_score.x = sfârșitul ecranului
Deoarece avem totul pregătit pentru jocul nostru, trebuie să facem totul să se miște! În interiorul funcției scena: enterScene ()
- amintiți-vă că enterScene
funcția este în afara createScene
functie - vom crea 5 cronometre si un ascultator runtime. Cronometrele vor trimite gloanțele, dușmanii și bonusurile, în timp ce ascultătorul runtime se va ocupa de detectarea coliziunilor.
(slowEnemySpawn, (slowEnemySpawn * 0.5), tmr_sendSlowEnemies2 = timer.performWithDelay (slowEnemySpawn + (slowEnemySpawn * 0.5), createSlowEnemy, 0) tmr_sendFastEnemies = timer.performWithDelay (rapidEnemySpawn, createFastEnemy, 0) tmr_sendBonus = timer.performWithDelay (2500, createBonus, 0) Durată de execuție: addEventListener (collision, onCollision)
Adăugarea finală (vă promit!) Este scena: destroyScene ()
funcția și ascultătorii evenimentelor de scenă. Funcția de distrugere a scenei va asigura că fizica este îndepărtată odată ce jucătorul părăsește scena. Ascultătorii evenimentului vor apela createScene
, enterScene
, și destroyScene
respectiv.
(scena) scena: addEventListener ("enterScene", scena) scena: addEventListener ("scriptura" distruge scena ", scenă)
Felicitări! Ați învățat despre o mulțime de lucruri, cum ar fi caracteristica storyboard Corona, fizica, coliziuni și multe altele! Acestea sunt abilități valoroase care pot fi aplicate la aproape orice joc și dacă doriți să construiți acest joc pentru dispozitivul dvs., recomand recomandarea oficială a documentelor Corona privind construirea dispozitivului.
Vă mulțumesc foarte mult pentru lectură! Dacă aveți întrebări, lăsați-le în comentariile de mai jos.