Am să vă conduc prin crearea unui joc shooter / platformer inspirat de Megaman. Ne vom concentra mai mult pe aspectele de fotografiere ale gameplay-ului decât pe platformă. În acest tutorial voi folosi Construct 2 ca instrument pentru a face jocul, dar voi explica logica folosind pseudocod pentru a putea urma acest tutorial în orice limbă sau motor de alegerea dvs..
postări asemănatoarePentru a vă concentra asupra implementării gameplay-ului, nu voi explica fiecare caracteristică Construct 2; Am de gând să presupun că știți elementele de bază, cum ar fi încărcarea unui sprite, coliziune de bază sau sunete de redare. Cu asta a spus, să începem jocul.
În primul rând, trebuie să avem sprites pentru jocul nostru. Din fericire, Opengameart ne-a acoperit cu minunata lor colectie de arta legala a jocurilor. Avem nevoie de patru seturi de sprite; un erou, un dușman și plăci pentru platforme.
Pentru a le folosi în Construct 2, am recolta spritele eroului în cadre individuale folosind GIMP.
Voi folosi comportamentul platformei Construct 2 pentru restul tutorialului, astfel încât să mă pot concentra pe partea de fotografiere și AI a jocului, care a fost punctul central al acestui tutorial.
Dacă lucrați într-o altă limbă sau dacă doriți să implementați o mișcare de platformă de bază în loc să utilizați comportamentul încorporat. Trebuie doar să utilizați codul din această secțiune dacă nu utilizați comportamentul built-in al lui Construct 2.
Pentru a începe, trebuie să luăm în considerare trei moduri în care eroul nostru se poate mișca; mergeți la dreapta, mergeți la stânga sau săriți. Fiecare cadru, actualizăm simularea jocului.
număr moveSpeed = 50; actualizare funcție () moveHero ();
Pentru a actualiza caracterul jucătorului, implementăm mișcarea de bază cum ar fi:
funcția moveHero () // player-ul apasă această tastă dacă (keyDown (KEY_LEFT)) hero.x - = moveSpeed * deltaTime; hero.animate ( "walkLeft"); dacă (keyDown (KEY_RIGHT)) hero.x + = moveSpeed * deltaTime; hero.animate ( "walkRight"); dacă (keyDown (KEY_UP)) hero.jump (); hero.animate ( "salt"); // o cheie care a fost doar neprimită dacă (keyReleased (KEY_LEFT)) hero.animate ("standLeft"); dacă (keyReleased (KEY_RIGHT)) hero.animate ("standRight");
Eu folosesc o altă funcție de a face jumping, deoarece săriturile nu sunt doar o chestiune de schimbare a valorii y, ci și de calcul al gravității. De asemenea, vom avea o funcție care ascultă dacă o cheie a fost eliberată sau nu, pentru a readuce animația eroului nostru la o animație în picioare.
Hai să vorbim despre cum să faci saltul jucătorului. Eroul va trebui să știe dacă el în prezent sărit sau nu, și, de asemenea, dacă în prezent se încadrează sau nu. Deci, vom declara două noi variabile: isJumping and isFalling. Implicit, ambele sunt false, ceea ce înseamnă că eroul se află pe o platformă.
Pentru a efectua un salt, trebuie mai întâi să verificăm dacă ambele valori sunt sau nu false și apoi să facem isJump true.
Funcția salt () if (! IsJumping &&! IsFalling) isJumping = True
Pentru ca eroul să poată sări, avem nevoie de o variabilă numită jumpPower și gravitație. Valoarea implicită a lui jumpPower este de -20 și gravitatea este 1. Logica este de a adăuga valoarea puterii de salt la poziția Y a eroului și de a adăuga valoarea gravitației pentru a-și pierde puterea.
Facem asta la fiecare bifăm. Poate că aceasta nu este cea mai realistă fizică a gravitării, dar jocurile nu trebuie să fie realiste, trebuie doar să fie credibile, de aceea unele jocuri au un salt super și un salt dublu. Codul de mai jos aparține funcției de actualizare.
Dacă (isJumping || isFalling) hero.y + = hero.jumpPower; hero.jumpPower + = ero gravitate; // în cele din urmă puterea de salt va fi mai mare decât zero și asta înseamnă că eroul scade dacă (hero.jumpPower> = 0) isJumping = False; isFalling = True; // pentru a opri căderea, faceți ceva când eroul se suprapune pe platformă dacă (hero.isOverlapping (platforma1)) // platform1 este platforma pe care eroul nostru poate pasi pe // resetează variabila la valoarea implicită isJumping = False; isFalling = False; hero.jumpPower = -20; și apoi există căderea liberă atunci când jucătorul cade peste marginea unei platforme dacă (! hero.isOverlapping (platform1) && hero.jumpPower < 0 && !isJumping) // !hero.isOverlapping(platform1) checks whether or not our hero is standing on a platform // and if jumpPower is less than zero and the player is not currently jumping, then that means // he's falling // setting these two values like this will make the player fall. hero.jumpPower = 0; isFalling = true;
Construcția comportamentului construit din platforma 2 reproduce exemplul de mai sus, care îi este oferit doar ajutorul celor care lucrează într-o altă limbă.
Acum vine partea de fotografiere a jocului. În seria Megaman există trei tipuri de fotografii: fotografii normale, fotografii încărcate și focuri de energie ale șefului.
Fotografiile normale sunt auto-explicative. Imaginile încărcate sunt fotografii care sunt încărcate mai întâi înainte de lansare, aceste fotografii încărcate sunt în două tipuri: jumătate încărcate și încărcate complet. Aceste atacuri încărcate sunt mai puternice decât fotografiile normale, iar încărcarea complet devine cea mai puternică.
Boss-urile de energie sunt fotografii cu puterea pe care jucătorul le-a dobândit după ce a învins fiecare șef. Daunele sunt aceleași cu cele normale, dar au proprietăți speciale pe care nu le au.
Acum, când știm tipul fiecărui tip, să începem să le facem. Mai intai sa vedem logica in spatele modului in care folosim fiecare lovitura. Aici presupunem că butonul Z de pe tastatură este folosit pentru a trage o lovitură. Vom implementa două comportamente diferite:
Acum, să începem să codificăm. Pentru că eroul nostru poate trage la stânga și la dreapta, trebuie să știm în ce direcție se află în prezent. Să declarăm o nouă variabilă numită cu care se confruntă, care stochează o valoare de șir dacă eroul este orientat spre stânga sau spre dreapta.
String cu care se confruntă = "dreapta"; // în ce direcție eroul se confruntă în prezent cu funcția moveHero () // playerul apasă această tastă dacă (keyDown (KEY_LEFT)) hero.x - = moveSpeed * deltaTime; hero.animate ( "walkLeft"); față = "stânga"; dacă (keyDown (KEY_RIGHT)) hero.x + = moveSpeed * deltaTime; hero.animate ( "walkRight"); cu care se confruntă = "dreapta"; // ... continuarea funcției moveHero () merge aici funcția update () // ... codul de actualizare pe care l-am scris anterior merge aici ... // player apăsați această tastă o dată dacă (keyPressed (KEY_Z)) if == "dreapta") hero.animate ("Trage"); // vom adăuga funcția de fotografiere mai târziu altfel dacă (cu care se confruntă == "stânga") hero.animate ("Shoot"); hero.mirrorSprite (); // această funcție împinge sprite orizontal dacă (keyReleased (KEY_Z)) if (cu care se confruntă == "dreapta") hero.animate ("standRight"); altfel dacă (cu care se confruntă == "stânga") hero.animate ("standLeft"); hero.mirrorSprite (); // trebuie să sunăm din nou pentru că sprite a fost oglindită // dacă nu oglindim din nou sprite, standLeft va arăta ca standright
Înainte de a trage un glonț, trebuie să ne uităm la proprietățile pe care bulletul le are:
Aceste proprietăți vor diferi pentru fiecare glonț. În special, proprietatea asupra energiei va fi diferită. Proprietatea unghiului este în mod normal numai una dintre cele două valori; dacă glonțul este împușcat în dreapta sau în stânga, cu excepția cazului în care este un glonț energetic de șef care poate fi împușcat într-un unghi unic.
Variantele vor fi discutate mai târziu, așa că acum voi acoperi numai fotografii de bază. Următoarea este codul care împușcă un glonț.
// în primul rând, vom crea o funcție care creează o nouă funcție de tragere a glonțului (stringTToSprite, numărul bulletPower, numărul bulletSpeed, numărul bulletAngle) myBullet = nou Bullet (pathToSprite); myBullet.power = bulletPower; // clasa sau obiectul glonțului are două variabile private care o mută în funcție de unghiul său // mai multe explicații la aceste două linii necesită mai multă matematică, așa că am ales să nu explic // presupun că motorul ales are o modalitate de a muta obiect în funcție de unghiul său ySpeed = Math.sin (bulletAngle) * bulletSpeed; xSpeed = Math.cos (bulletAngle) * bulletSpeed; // aceasta este funcția de clasă bullet care se numește fiecare cadru, aceasta mișcă glonțul în funcție de funcția unghiului moveBullet () x + = xSpeed * deltaTime; y + = ySpeed * deltaTime; // și aceasta este modificarea actualizării funcției anterioare () funcția update () // ... codul de actualizare pe care l-am scris anterior merge aici ... // player apăsați această tastă o dată dacă (keyPressed (KEY_Z)) if ( cu care se confruntă == "dreapta") hero.animate ("Shoot"); hero.shoot ("cale / spre / sprite.png", 10, 400, 0); altfel dacă (cu care se confruntă == "stânga") hero.animate ("Shoot"); hero.mirrorSprite (); // această funcție învârte spirale hero.shoot orizontal ("path / to / sprite.png", 10, 400, 180); // unghiul este de 180, astfel încât glonțul merge la stânga // ... continuarea codului de actualizare merge aici ...
Unele gloante pot fi mai puternice decât altele. Pentru a crea o fotografie încărcată, avem nevoie de o variabilă numită chargeTime, care va crește în fiecare secundă pe care jucătorul o deține în jos și va reveni la zero atunci când glonțul este declanșat. Modificările aduse codului de actualizare sunt următoarele:
// jucatorul a lansat doar tasta z daca (keyReleased (KEY_Z)) if (chargedTime> 0 && chargedTime <= 5) if (facing == "right") hero.animate("Shoot"); hero.shoot("path/to/halfChargedBullet.png", 20, 400, 0); chargedTime = 0; else if (facing == "left") hero.animate("Shoot"); hero.mirrorSprite(); // this function flips the sprite horizontally hero.shoot("path/to/halfChargedBullet.png", 20, 400, 180); chargedTime = 0; else if (chargedTime > 5) dacă (cu care se confruntă == "dreapta") hero.animate ("Shoot"); hero.shoot ("cale / spre / fullChargedBullet.png", 40, 400, 0); chargedTime = 0; altfel dacă (cu care se confruntă == "stânga") hero.animate ("Shoot"); hero.mirrorSprite (); // această funcție învârte spirala orizontală hero.shoot ("path / to / fullChargedBullet.png", 40, 400, 180); chargedTime = 0; dacă (cu care se confruntă == "dreapta") hero.animate ("standRight"); altfel dacă (cu care se confruntă == "stânga") hero.animate ("standLeft"); hero.mirrorSprite (); // trebuie să sunăm din nou pentru că sprite a fost oglindită // dacă nu oglindim din nou sprite, standLeft va arăta ca standright // playerul apasă această tastă dacă (keyDown (KEY_Z)) // aceasta este funcția care adaugă valoarea încărcatăTime în fiecare secundă // acest bloc de cod cheie va fi rulat în fiecare cadru, care este mai mic de o secundă // motorul ales trebuie să aibă o modalitate de a spune dacă o secundă a trecut sau nu addChargedTime ();
Noul nostru personaj erou mișcă stânga, dreapta și sări în funcție de intrarea noastră și, de asemenea, împușcă gloanțe, fie că este normal, jumătate încărcat sau complet încărcat.
Acum avem un erou controlabil. Să o numim Xeon din simplitate. El poate efectua câteva mișcări de bază cum ar fi mersul pe jos, sărituri și împușcături. Grozav! Dar ce bun este abilitatea de a trage fără să trageți ceva, nu? De aceea de data aceasta vom face primul nostru inamic.
Să proiectăm atributele inamicului nostru înainte să începem să îl codificăm.
Sănătate: Câte sănătăți au inamicul nostru determină cât de multe focuri (și ce fel) sunt necesare pentru ao distruge.
Putere: Puterea de atac a inamicii, cât de mult se face cu jucătorii noștri.
ShotAngle: în ce direcție inamicul împușcă glonțul, acesta poate fi la stânga sau la dreapta ori oriunde vrem.
Asta e ceea ce avem nevoie pentru inamicul nostru, acum să facem clasa / obiectul inamic.
Clasa / obiectul Enemy este cam la fel ca și clasa / obiectul jucătorului, cu excepția faptului că inamicul nu asculta intrarea jucătorului. Din acest motiv trebuie să înlocuim părțile în care eroul ascultă intrarea jucătorului, la inamicul AI / logică.
Pentru început, hai să ne ocupăm de focalizarea de bază a inamicului. Inamicul va trage la jucator cand va vedea jucatorul.
Pentru a determina dacă inamicul "vede" jucătorul, va trebui să definim o variabilă pentru obiectul inamic denumit confruntat, care este un șir care stochează una din cele două valori, "stânga" sau "dreapta".
Vrăjmașul are, de asemenea, nevoie de un fel de vizibilitate, de aceea vom face o altă variabilă numită gamă. Dacă jucătorul se află în acest interval, atunci inamicul "vede" jucătorul. Pseudocodul este după cum urmează:
funcția boolean checkSees () if (cu care se confruntă == "stânga" && hero.x> = gama enemy.x) return true; dacă (cu care se confruntă == "dreapta" && hero.x <= enemy.x + range) return true; return false;
checkSees () funcție
Poate că ați observat ceva în acest pseudocod: nu ia în considerare poziția eroului, deci inamicul va trage încă la erou chiar dacă sunt la platforme cu diferite înălțimi.
Deocamdată, acest lucru va fi suficient, deoarece realizarea unui algoritm de vizualizare este în afara scopului acestui tutorial. În jocul propriu, ați putea dori să adăugați o toleranță Y în acea funcție mai sus, care va verifica dacă poziția eroului y se află între două puncte care definesc înălțimile inamicului.
Pseudocodul pentru filmarea inamicului este următorul:
// poate fi în actualizare () sau în altă parte care este executată la fiecare actualizare a funcției de cadru () if (checkSees ()) shoot ("path / to / bulletSprite.png", enemyPower, 400, shotAngle);
După cum puteți vedea, funcția inamicului shoot () este similară cu cea a jucătorului. Este nevoie de calea spritei, puterea de atac, viteza glonțului și unghiul de fotografiere ca parametri.
Când trece inamicul de la stânga spre dreapta? Pentru eroul nostru, folosim inputul jucatorului pentru a schimba directia cu care se confrunta eroul nostru. Pentru vrăjmașul nostru avem două opțiuni: folosiți un fel de temporizator pentru a comuta direcția cu care se confruntă la fiecare câteva secunde, în timp ce dușmanul trebuie să stea liniștit sau să aibă dușmanul să meargă într-un anumit loc și apoi să schimbe direcția spre care se îndreaptă și apoi să meargă într-un alt loc pentru a comuta din nou direcția îndreptată spre față.
Această a doua metodă poate fi folosită ca un AI de patrulare. Desigur, putem face ca dușmanul să meargă într-o direcție și să nu se întoarcă niciodată.
Pseudocodul pentru prima metodă este după cum urmează:
funcția de comutareAI () // elapsedTime () este o funcție care contează câte secunde a trecut de la resetarea valorii sale // Presupun că motorul ales are acest tip de funcționalitate dacă (elapsedTime ()> 4.0) if == "stânga") facing = "right"; shotAngle = 0; dacă (cu care se confruntă == "dreapta") facing = "left"; shotAngle = 180; enemy.mirrorSprite (); // de asemenea, flip sprite orizontal resetTime (); // resetează timpul care se numără în timpul scurs ()
Pentru a face AI de patrulare, trebuie să facem două obiecte invizibile care se află la capătul celor două căi de patrulă a dușmanului și să facă inamicul să se miște într-un alt mod dacă se ciocnește cu ei.
Acum, să scriem pseudocodul nostru pentru patrulatul AI al inamicului:
funcția de patrulareAI () if (cu care se confruntă == "dreapta") walkRight (); // același cu cel din playerul / clasa if (collidesWith (rightPatrolBorder)) facing = "left"; enemy.mirrorSprite (); dacă (cu care se confruntă == "stânga") walkLeft (); dacă (collidesWith (leftPatrolBorder)) facing = "right"; enemy.mirrorSprite ();
După aceasta, inamicul va patrula între două puncte, așa cum ne dorește.
Pentru a configura care AI utilizează inamicul, vom adăuga încă o variabilă cu un tip de șir pentru inamicul nostru: inamicul AI. Acest lucru va determina ce AI să utilizeze fiecare cadru, așa cum este cazul:
dacă (enemyAI == "comutarea") switchingAI (); altfel dacă (enemyAI == "patrolling") patrollingAI ();
Desigur, puteți adăuga mai multe tipuri de inamici AI, dacă doriți.
Hai să vedem cum putem face variante împușcate atât pentru jucător, cât și pentru inamic. Facem variații împușcate schimbând două lucruri: unghiul de tragere și numărul de focuri de armă.
În acest fel putem face o simplă lovire cu bullet sau o împușcătură cu trei focuri de armă. Înainte de a face acest lucru, vom face o altă variabilă a obiectului / clasei inamice numit shotAI, care este un șir. Vom folosi acest lucru în checkSees () verificând dacă blocul, în cazul în care inamicul împușcă. Modificările aduse blocului de cod vor fi următoarele:
// poate fi în actualizare () sau în altă parte executată în fiecare actualizare a funcției de cadru () if (checkSees ()) if (shotAI == "simplu") shoot / , 400, shotAngle); dacă (shotAI == "threeBullets") shootThreeBullets ();
Bineînțeles, numele AI și felul în care ar fi fost împușcat dușmanul sunt pe cont propriu, acesta este doar un exemplu.
Acum, hai să adâncim mai mult în ceea ce este în interiorul funcției shootThreeBullets ().
Funcție shootThreeBullets () if (cu care se confruntă == "dreapta") shoot ("cale / spre / bulletSprite.png", enemyPower, 400, 0); // acest glonț merge direct la filmarea corectă ("cale / spre / bulletSprite.png", enemyPower, 400, 330); // aceasta crește cu 30 de grade ("cale / spre / bulletSprite.png", enemyPower, 400, 30); // aceasta se reduce cu 30 de grade dacă (cu care se confruntă == "stânga") trage ("cale / spre / bulletSprite.png", enemyPower, 400, 180); // acest glonț merge direct spre stânga ("cale / spre / bulletSprite.png", enemyPower, 400, 210); // aceasta crește până la 30 grade ("cale / spre / bulletSprite.png", enemyPower, 400, 150); // aceasta scade cu 30 de grade
Dacă nu sunteți sigur de ce 0 merge la dreapta și 180 merge spre stânga, este pentru că direcția de 0 grade merge direct în partea dreaptă a ecranului, 90 de grade se îndreaptă spre partea inferioară a ecranului și așa mai departe până când acesta lovește 360 de grade. Odată ce știi ce valoare merge acolo, poți să-ți creezi propria varianță.
De asemenea, putem face o variabilă shotAI pentru player, dar prefer să o numim selectatăShot, deoarece jucătorul nostru va alege glonțul în loc să fie programat de la început. T
el logică în megaman este de fiecare dată când megaman învinge un sef, el devine puterea de șef ca o nouă lovitură. Voi încerca să recreez această logică. Pentru a face acest lucru avem nevoie de o matrice care conține fotografii, inclusiv fotografii normale. Pseudocodul este astfel:
var shotArr = ["normalShot", "boss1", "boss2"]; var shotIndex = 0; var selectShot = "normalShot"; function update () // acesta este un bloc de cod în funcția de actualizare a jucătorului în cazul în care jucătorul trage un glont // această funcție schimbă glonțul pe care playerul îl trage changeBullet (); // player apăsați această tastă o dată dacă (keyPressed (KEY_Z)) if (cu care se confruntă == "dreapta") hero.animate ("Shoot"); dacă (selectShot == "normalShot") hero.shoot ("cale / spre / sprite.png", 10, 400, 0); altceva dacă (selectedShot == "boss1") // adaugă coduri pentru a fotografia tipul de film pe care la primit după ce a învins pe boss 1 changeBullet () // modifică shotIndex bazat pe butonul apăsat dacă (keyPressed (KEY_E)) shotIndex + = 1; dacă (keyPressed (KEY_Q)) shotIndex - = 1; // remediați shotIndex dacă este în afara matricei dacă (shotIndex == shotArr.length) shotIndex = 0; dacă (shotIndex < 0) shotIndex = shotArr.length -- 1; selectedShot = shotArr[shotIndex];
Trebuie să ținem evidența a două noi variabile:
Vom împinge noi elemente la shotArr când jucătorul înfrânge un șef.
La fel ca inamicul trageThreeBullet (), poti fi creativ si sa-ti creezi propriile variante. Deoarece acesta este glontul eroului, să-i dăm ceva special.
Să facem un tip de lovitură pentru a fi eficient împotriva unui șef specific, astfel încât acesta să trateze mai multe daune. Pentru a face acest lucru, vom crea o variabilă pentru obiectul bullet numit strongAgainst că este o altă variabilă de tip șir care conține numele șefului căruia acest glonț este eficient împotriva. Vom adăuga acest lucru se ocupă mai mult de funcționalitatea daunelor atunci când vom discuta partea de seful a jocului.
Acesta este locul în care toate variantele împușcate pe care le facem încep cu adevărat să conteze. Acesta este locul în care eroul nostru dăunează și ucide inamicului, iar invers.
Pentru a începe, hai să facem o variabilă atât pentru obiectul erou, cât și pentru inamic, numit sănătate care este un int, și o altă variabilă doar pentru eroul numit vieți. Să aruncăm o privire la pseudocodul:
dacă (bullet.collidesWith (erou)) hero.health - = bullet.power; createExplosion (); // pentru moment nu avem o sprite explozivă, așa că acesta va acționa ca un memento / / verifica dacă eroul este mort dacă (hero.health <= 0) hero.lives -= 1; // decreases hero's total number of lives. destroyHero();
Vom face acelasi pseudocod pentru a distruge inamicii, asa cum sunt:
dacă (bullet.collidesWith (inamic)) enemy.health - = bullet.power; createExplosion (); dacă (inamicul <= 0) destroyEnemy();
Acum, dacă l-aș lăsa la asta, atunci nu ar fi interesant. Deci, voi face un sprite dreptunghi în colțul din stânga sus al ecranului care acționează ca bară de sănătate a eroului nostru.
Durata barului de sănătate se va schimba în funcție de starea de sănătate a eroului nostru. Formula pentru schimbarea duratei barului de sănătate este următoarea:
// acesta este în funcția de actualizare healthBar.width = (hero.health / hero.maxHealth) * 100;
Avem nevoie de încă o variabilă pentru eroul nostru numit maxHealth; eroul nostru este deplină pentru sănătate. Pentru moment, această valoare nu poate fi schimbată, dar poate că în viitor putem crea un element care să mărească cantitatea de maxHealth a eroului.
Acum că am creat eroul nostru, inamicul și variațiile împușcate, trebuie să facem mai multe nivele și șefi.
Pentru a avea mai multe niveluri înseamnă că la un moment dat jocul va ajunge la unul sau mai multe puncte de control care comută jocul de la nivelul 1-1 la nivelul 1-2 până la nivelul 1-3 și așa mai departe până când ajung la șeful.
Când jucătorul moare undeva în nivelul 1-2, el sau ea nu trebuie să redea tot drumul înapoi de la începutul nivelului 1-1. Cum mă fac asta? Mai intai vom face nivelul, nu voi explica prea mult despre proiectarea nivelului, dar aici este nivelul de exemplu in Construct 2.
Imaginea din colțul din stânga sus este stratul HUD. Se va defila, urmând eroul când se va juca jocul.
Un sprite pe care ar trebui să-l acordați atenție este sprite verde în partea dreaptă superioară a nivelului. Acesta este punctul de control în acest nivel când eroul se ciocnește cu el vom transfera jocul la nivelul 1-2.
Pentru a gestiona mai multe niveluri avem nevoie de trei variabile: currentLevel, levelName și nextLevel.
Variabila currentLevel este creată în obiectul / clasa eroului. LevelName este creat în obiectul scena (nivel) pentru fiecare nivel. Variabila nextLevel este creată în obiectul sprite verde.
Logica este după cum urmează: când eroul se ciocnește cu sprite verde (eu îl numesc greenDoor), vom schimba nivelul nostru la scena jocului în care levelName este aceeași cu variabila nextLevel. După schimbarea nivelului, vom modifica valoarea variabilei curentă a eroului la aceeași valoare ca nivelul nivelelor de joc. Iată pseudocodul:
// aceasta este funcția de actualizare a jocului dacă (hero.collidesWith (greenDoor)) changeLevelTo (greenDoor.nextLevel);
Aici este pseudocodul pentru a vă ocupa de momentul în care nivelul următor este încărcat și gata de redare.
// aceasta este funcția care este declanșată atunci când nivelul nou este încărcat funcția onStart () hero.currentLevel = scene.LevelName; hero.x = startPos.x; hero.y = startPos.y;
Acum, că am schimbat la un nou nivel, voi explica sprite-ul portocaliu din spatele eroului nostru în imaginea de design de nivel de mai sus. Acest sprite portocaliu este un obiect pe care îl numesc startPos. Se utilizează pentru a marca poziția de pornire a fiecărui nivel.
Ne referim la acest obiect atunci când eroul tocmai a schimbat nivelurile sau a murit, astfel încât să știm unde să-l facem.
Iată pseudocodul pentru manipulare când eroul moare:
// funcția care este declanșată atunci când eroul este distrus Funcția onDestroyed () // reinvie eroul dacă eroul încă mai are viața. Dacă hero.live> 0) var newHero = eroul nou (); newHero.x = startPos.x; newHero.y = startPos.y;
Acum putem avea nivele multiple și putem, de asemenea, respinge eroul după ce moare.
Puteți crea cât mai multe niveluri pe care le doriți, sau poate creați chiar și două obiecte greenDoor într-un nivel care unul dintre ele se întoarce la nivelul 1-1 dacă jucătorul rezolvă un puzzle greșit.
În cele din urmă este timpul să pună în aplicare seful în sine. Pentru a face un nivel de sef este la fel de simplu ca a face un alt nivel care va da naștere unui sef în loc de dușmani obișnuiți.
Partea greu este crearea AI pentru șef, deoarece fiecare șef va avea un AI unic. Deci, pentru a fi ușor de înțeles și duplicat pentru o mulțime de șefi, voi face ca șeful AI să fie dependent de timpul după ce au fost făcute. Ceea ce inseamna ca vor face A pentru x secunde, apoi se vor schimba la B pentru y secunde, apoi se vor face C pentru z secunde inainte de a reveni la A. Pseudocodul va arata cam asa:
// acest cod se află în interiorul funcției de actualizare a șefului, deci este executat la fiecare cadru dacă (elapsedTime ()> 2.0) // dacă blocul este executat timp de 3 secunde, deoarece diferența de timp cu blocul if < secunde. BossShot1 (); // varianta de împușcare care trebuie executată de această dată altceva (elapsedTime ()> 5.0) bossShot2 (); altfel dacă (elapsedTime ()> 6.0) bossShot3 (); dacă (elapsedTime ()> 7.0) // resetați timpul astfel încât șeful să execute prima acțiune din nou resetsTime ();
Definiția functonilor împușcați de șefi este mai jos. Simțiți-vă liber să-l schimbați pentru a se potrivi ceea ce doriți pentru o luptă seful:
funcția bossShot1 () // o simplă lovitură dreaptă bossEnemy.shoot ("cale / spre / bullet / sprite.png", bossPower, 400, shotAngle); // shotAngle este 180 funcția bossShot2 () // o gloanțe cu trei direcții împușcate bossEnemy.shoot ("cale / spre / bullet / sprite.png", bossPower, 400, shotAngle); bossEnemy.shoot ("cale / spre / bullet / sprite.png", bossPower, 400, shotAngle + 30); bossEnemy.shoot ("cale / spre / bullet / sprite.png", bossPower, 400, shotAngle - 30); funcția bossShot3 () // pentru aceasta, voi face un cerc împușcat, astfel că gloanțele vor forma un cerc pentru (var i = 0; i <= 9; i++) bossEnemy.shoot(