În acest tutorial, voi explica pașii majori și fluxul de lucru pentru crearea unui joc simplu de supraviețuire spațială, bazat pe mecanicul gravitației explicat într-un tutorial anterior. Acest joc este scris în AS3 folosind FlashDevelop.
Utilizați tastele săgeată stânga și dreapta pentru a manevra nava dvs., tastele săgeată sus și jos pentru a mări sau a reduce dimensiunea câmpului magnetic pe care le produce și bara de spațiu pentru a inversa polaritatea. Colectați cristalele albe pentru a mări alimentarea cu combustibil - dar evitați cele roșii, deoarece acestea o folosesc. Nu atingeți o piatră sau jocul este terminat!
În acest tutorial, nu vom crea, de fapt, jocul complet afișat mai sus; vom începe pur și simplu, făcând o versiune foarte simplă cu grafică primitivă și un singur tip de obiect. Cu toate acestea, până la sfârșit, ar fi trebuit să fi învățat suficient pentru a putea să adăugați și alte caracteristici!
Jocul în sine este foarte simplu în starea sa actuală - aruncăm o privire la această critică pentru sfaturi despre cum poți să o iei dintr-o simplă demonstrație într-un joc complet!
Configurați un nou proiect AS3 în FlashDevelop și setați dimensiunile acestuia la 550x600px.
pachet [SWF (lățime = "550", înălțime = "600")] clasa publică principală se extinde Sprite
Există șase obiecte în particule pe care le puteți identifica de la jocul de mai sus:
Desigur, puteți adăuga în orice alt obiect pentru a face jocul mai interactiv sau pentru a adăuga o nouă caracteristică. Pentru acest tutorial vom face doar
Energie
ClasăDin obiectele pe care le-am identificat, patru dintre ele lucrează exact la fel: prin cădere de sus în jos.
Sunt:
În acest tutorial, vom face doar obiectele de "furnizare de energie", din cele patru de mai sus. Deci, să începem prin a crea aceste obiecte și a le face să cadă, cu o poziție și viteză aleatorii.
Începeți prin a crea un Energie
clasă:
pachet import flash.display.MovieClip; importul flash.events.Event; public class Energy extinde MovieClip private var rSpeed: Number = 0; funcția publică Energie (viteză: Număr) graphic.beginFill (0x321312); grafice.drawCircle (0, 0, 8); rSpeed = viteza; // vom numi aceasta functie publica fiecare cadru (): void this.y + = rSpeed; // viteza de rotație este legată de viteza de deplasare this.rotation + = rSpeed / 8;
GameScreen
ClasăAceastă clasă va controla în cele din urmă cele mai multe aspecte ale jocului nostru, inclusiv mișcarea jucătorului și bucla de joc.
Creați clasa:
pachet public class GameScreen extinde MovieClip funcția publică GameScreen ()
Asta e tot ce avem nevoie de acum.
Acum vom crea un exemplu de GameScreen
în Principal
:
pachet import flash.display.Sprite; importul flash.events.Event; [SWF (lățime = "550", înălțime = "600")] clasa publică principală extinde Sprite joc privat var: GameScreen; funcția publică Main (): void // nu afișează un dreptunghi galben pe ecran la startup stage.stageFocusRect = false; joc = nou GameScreen (); addChild (joc); // dă focalizare pe tastatură în ecranul de joc imediat stage.focus = joc;
De ce sa te deranjezi? În felul acesta, va fi mai ușor să adăugăm ecrane suplimentare mai târziu dacă vrem (ca un preloader, un ecran de titlu, un joc pe ecran ...).
Pentru a evita GameScreen
clasa devine prea mult o mizerie, vom folosi clase separate pentru a gestiona fiecare obiect.
Fiecare clasă de manager va conține toate funcțiile care se referă la și interacționează cu un anumit obiect. Iată-l EnergyManager
clasă:
pachet import flash.display.MovieClip; public class EnergyManager // acest Vector va stoca toate instanțele din clasa energetică private var energyList: Vector.privat var jocScreen: GameScreen; funcția publică EnergyManager (gs: GameScreen) gameScreen = gs; energyList = Vector nou. ;
Rețineți că solicităm ca o referință la GameScreen să fie transmisă constructorului și stocăm această referință într-o variabilă privată. De asemenea, am creat un vector pentru a stoca referințe la toate obiectele de energie.
Până în prezent clasa nu conține alte funcții; le vom adăuga mai târziu.
Adăugați funcția de mai jos pentru a crea energie, aceasta este doar o funcție; vom apela funcția mai târziu de la GameScreen
Clasă:
funcția publică createEnergy (număr: int): void var energy: Energy; pentru (var i: int = 0; i < number; i++) energy = new Energy(4); gameScreen.addEnergyToScreen(energy); energyList.push(energy); energy.x = Calculation.generateRandomValue(30, 520); energy.y = Calculation.generateRandomValue( -150, -20);
Creați o nouă sursă de energie cu o viteză de 4, adăugați-o în lista de afișare (prin GameScreen), adăugați-o în Vectorul tuturor obiectelor de energie pe care tocmai am creat-o și stabiliți poziția sa la un punct aleatoriu în anumite limite.
Calculation.generateRandomValue (#, #)
este o funcție statică pe care încă nu am scris-o, deci hai să facem asta acum. Creați o nouă clasă numită Calcul
și adăugați această funcție:
funcția publică statică generateRandomValue (min: Număr, max: Număr): Număr var randomValue: Număr = min + (Math.random () * (max - min)); return randomValue;
Această funcție va genera un număr aleator între cele două valori care îi sunt transmise. Pentru mai multe informații despre cum funcționează, consultați acest sfat rapid. Deoarece aceasta este o funcție statică, nu este nevoie să creați o instanță Calcul
pentru a le numi.
Ce este asta? addEnergyToScreen ()
funcţie? Nu am definit-o încă, deci hai să o facem acum. Adăugați acest lucru la GameScreen
:
funcția publică addEnergyToScreen (energie: energie): void addChild (energy);
Pur și simplu adaugă instanța de energie trecută în lista de afișare. Să facem, de asemenea, o funcție corespunzătoare pentru a îndepărta un obiect energetic dat de pe ecran:
funcția publică removeEnergyFromScreen (energy: Energy): void if (energy.parent == this) removeChild (energie);
Să setăm un cronometru care definește intervalul pentru fiecare reproducere. Acest cod intră GameScreen
's constructor funcția:
energyM = noul EnergyManager (acest lucru); // rețineți o trimitere la ecranul de joc var spawnTimer: Timer = nou Cronometru (3000, 0); spawnTimer.addEventListener (TimerEvent.TIMER, spawnEnergy); spawnTimer.start ();
Deci, la fiecare trei secunde, cronometrul va suna spawnEnergy ()
. Să scriem această funcție acum:
funcția privată spawnEnergy (e: TimerEvent): void energyM.createEnergy (4); // creați 4 energii
Să folosim un alt cerc mai mare pentru a reprezenta jucătorul. Simțiți-vă liber să importați o imagine pe care să o utilizați în schimb:
funcție publică Player () graphics.beginFill (0x7ebff1); graphics.drawCircle (0, 0, 20);
Adăugați acest cod la GameScreen
pentru a adăuga playerul pe ecran:
// în definiția variabilelor public var player: Player;
// în funcția constructor player = player nou; addChild (jucator); player.x = 275; player.y = 450;
Până acum, ar trebui să avem câteva consumabile de energie care să cadă câteva secunde, iar jucătorul care apare în mijlocul ecranului:
Există practic două moduri de a aplica mișcarea:
Adevărat
. În fiecare actualizare de cadre, este "dreapta în mișcare" Adevărat
, noi crestem valoarea x a obiectului. Folosind actualizarea directă a fiecărui cadru
- când tasta săgeată dreapta este apăsată, se spune unui obiect să se miște imediat, prin creșterea valorii sale x. A doua metodă nu duce la o mișcare ușoară atunci când cheia este presată continuu, dar prima metodă o face - deci vom folosi prima metodă.
Există trei pași simpli pentru a face acest lucru:
privat var moveRight: Boolean = false; privat var moveLeft: Boolean = false;
addEventListener (Event.ENTER_FRAME, actualizare); addEventListener (KeyboardEvent.KEY_DOWN, KeyDownHandler); addEventListener (KeyboardEvent.KEY_UP, KeyUpHandler); funcția privată KeyDownHandler (e: KeyboardEvent): void if (e.keyCode == Tastatură.RIGHT) moveRight = true; dacă (e.keyCode == Keyboard.LEFT) moveLeft = true; dacă (e.keyCode == Tastatură.SPACE) if (isGravityPushing == true) isGravityPushing = false; altfel isGravityPushing = true; funcția privată KeyUpHandler (e: KeyboardEvent): void if (e.keyCode == Tastatură.RIGHT) moveRight = false; dacă (e.keyCode == Keyboard.LEFT) moveLeft = false;
Nu uitați să creați mai întâi o funcție de ascultare de la evenimentul "introduceți cadrul", "actualizare":
// apelați această funcție în fiecare actualizare a funcției private (e: Event): void if (moveRight == true) player.x + = 6; dacă (moveLeft == true) player.x - = 6;
Păstrați player-ul în limitele ecranului:
dacă (player.x> = 525) moveRight = false; dacă (player.x <= 20) moveLeft = false;
Iată cum arată toate lucrurile:
pachet import flash.display.MovieClip; importul flash.events.Event; import flash.events.TimerEvent; import flash.ui.Keyboard; import flash.utils.Timer; import flash.events.KeyboardEvent; clasa publica GameScreen public var player: Player; private var energyM: EnergyManager; privat var moveRight: Boolean = false; privat var moveLeft: Boolean = false; privat var esteGravityPushing: Boolean = true; privat var returnPower: int = 0; private var scoreText: Text; private var totalScore: int = 0; scor privat var: Text; funcția publică GameScreen () scoreText = text nou ("Scor:"); addChild (scoreText); energyM = noul EnergyManager; var spawnTimer: Timer = nou Cronometru (3000, 0); spawnTimer.addEventListener (TimerEvent.TIMER, spawnEnergy); spawnTimer.start (); player = player nou; addChild (jucator); player.x = 275; player.y = 450; addEventListener (Event.ENTER_FRAME, actualizare); addEventListener (KeyboardEvent.KEY_DOWN, KeyDownHandler); addEventListener (KeyboardEvent.KEY_UP, KeyUpHandler); funcția privată KeyDownHandler (e: KeyboardEvent): void if (e.keyCode == Tastatură.RIGHT) moveRight = true; dacă (e.keyCode == Keyboard.LEFT) moveLeft = true; dacă (e.keyCode == Tastatură.SPACE) if (isGravityPushing == true) isGravityPushing = false; else dacă (isGravityPushing == false) isGravityPushing = true; funcția privată KeyUpHandler (e: KeyboardEvent): void if (e.keyCode == Tastatură.RIGHT) moveRight = false; dacă (e.keyCode == Keyboard.LEFT) moveLeft = false; actualizarea funcției private (e: Event): void if (player.x> = 525) moveRight = false; dacă (player.x <= 20) moveLeft = false; if (moveRight == true) player.x += 6; if (moveLeft == true) player.x -= 6;
În prezent, energia provoacă răsărare, dar nu se mișcă. Vom folosi GameScreen.update ()
pentru a le face să se miște, deoarece rulează fiecare cadru.
Adăugați acest cod la GameScreen.update ()
:
energyM.moveAll (); // va face ca fiecare obiect energetic sa se miste
Acum, desigur, trebuie să facem EnergyManager.moveAll ()
funcția, adăugați astfel la EnergyManager.as
:
funcția publică moveAll (): void pentru (var i: int = 0; i < energyList.length; i++) var energyS:Energy = energyList[i]; energyS.move();
Va trebui să verificăm coliziunea dintre fiecare obiect energetic și player. (Dacă dezvoltați jocul în continuare, va trebui să verificați acest lucru pentru asteroizi și consumatori de energie, dar nu pentru stele.)
Cel mai bun loc pentru a face față acestor verificări se află în interiorul EnergyManager
, a declanșat fiecare cadru de către GameScreen
.
Un lucru de luat în considerare: verificările de coliziune vor fi între două cercuri, deci hitTestObject ()
nu este ideal. În schimb, vom folosi metoda explicată în acest tutorial.
Putem scrie funcția după cum urmează:
controlul funcției publiceCollision (p: Player): int // energia transferată din cauza coliziunii var energyTransfer: int = 0; pentru (var i: int = 0; i < energyList.length; i++) var energyS:Energy = energyList[i]; var newX:Number = p.x - energyS.x; var newY:Number = p.y - energyS.y; var distance:Number = Math.sqrt(newX * newX + newY * newY); if (distance <= 28) gameScreen.removeEnergyFromScreen(energyS); energyList.splice(i, 1); // for this simple game, we'll always transfer 1 unit // but you could alter this based on speed of collision // or any other factor energyTransfer = 1; return energyTransfer;
Energys
este scurt pentru furnizarea de energie.Ați putea modifica linia 51 la energyTransfer + = 1
, pentru a permite jucătorului să absoarbă mai mult de un obiect de energie simultan. Depinde de tine - încercați și vedeți cum afectează jocul.
Trebuie să verificăm coliziunea fiecărui cadru, așa că ar trebui să sunăm la funcția de la care tocmai am scris GameScreen.update ()
.
În primul rând, trebuie să creăm o variabilă intregă pentru a stoca valoarea transferului de energie din funcția de detecție a coliziunii. Vom folosi această valoare pentru a crește energia navei și pentru a adăuga scorul jucătorului.
privat var returnPower: int = 0;
returnPower = energyM.checkCollision (jucător);
Înainte de a merge la crearea mecanicului de joc pentru funcțiile "Push" și "Pull" ale navei, aș dori să introduc conceptul de fizică pe care se bazează mecanicul.
Ideea este de a atrage obiectul spre jucator prin intermediul unui a forta. Legea lui Newton de Gravitație Universală ne dă o formulă matematică excelentă (și simplă) pe care o putem folosi pentru aceasta, unde forța este, desigur, forța gravitațională:
G este doar un număr, și îl putem pune la orice ne place. În mod similar, putem seta masele fiecărui obiect din joc la toate valorile pe care le plătim. Gravitatea are loc pe distanțe infinite, dar în jocul nostru vom avea un punct de decupare (marcat de cercul alb din demo de la începutul tutorialului).
Cele două lucruri importante pe care trebuie să le menționăm în legătură cu această formulă sunt:
Înainte de a începe codarea mecanicii jocului pentru funcțiile "Push" și "Pull", să vedem ce vrem să facem:
În esență, vrem ca A (playerul) să exercite o anumită forță pe B (un cristal) și să se deplaseze B spre A pe baza acelei forțe.
Ar trebui să revizuim câteva concepte:
Math.atan2 (B.y - A.y, B.x - A.x)
.B.x + = (forță * Math.cos (unghi));
B.y + = (forță * Math.sin (unghi));
Pentru mai multe informații, consultați tutorialele Gravity in Action și Trigonometry pentru dezvoltatorii de jocuri flash.
Pe baza explicației anterioare, putem prezenta o schiță pentru codul nostru care atrage fiecare cristal pe navă:
Cod simplu:
funcția publică gravitateaPull (p: Player): void pentru (var i: int = 0; i < energyList.length; i++) var energyS:Energy = energyList[i]; var nX:Number = (p.x - energyS.x); var nY:Number = (p.y - energyS.y); var angle:Number = Math.atan2(nY, nX); var r:Number = Math.sqrt(nX * nX + nY * nY); if (r <= 250) var f:Number = (4 * 50 * 10) / (r * r); energyS.x += f * Math.cos(angle); energyS.y += f * Math.sin(angle);
Iată o perioadă de timp care arată cum arată acest lucru:
Rețineți că energia se deplasează mai repede cu cât se apropie de navă, datorită termenului r-pătrat.
Putem pune în aplicare funcția de împingere doar făcând forța negativă:
funcția publică gravitateaPull (p: Player): void pentru (var i: int = 0; i < energyList.length; i++) var energyS:Energy = energyList[i]; var nX:Number = (p.x - energyS.x); var nY:Number = (p.y - energyS.y); var angle:Number = Math.atan2(nY, nX); var r:Number = Math.sqrt(nX * nX + nY * nY); if (r <= 250) var f:Number = (4 * 50 * 10) / (r * r); energyS.x -= f * Math.cos(angle); energyS.y -= f * Math.sin(angle);
Aici, obiectul se mișcă mai lent când se îndepărtează de player, deoarece forța devine mai slabă.
Bineînțeles că veți avea nevoie de această funcție pentru a rula fiecare cadru prin GameScreen
- dar înainte de aceasta, va trebui să folosim o funcție booleană pentru a comuta între cele două funcții:
privat var esteGravityPushing: Boolean = true; // apăsarea spațiului comută
Vom folosi adevărat pentru 'Push' și false pentru 'Pull'.
Interior KeyDownHandler ()
:
dacă (e.keyCode == Tastatură.SPACE) if (isGravityPushing == true) isGravityPushing = false; else dacă (isGravityPushing == false) isGravityPushing = true;
Ulterior, va trebui să verificați fiecare boolean. Adăugați acest lucru la Actualizați()
:
dacă (isGravityPushing == true) energyM.gravityPull (player); dacă (isGravityPushing == false) energyM.gravityPush (player);
S-ar putea să afli că mișcarea nu arată așa de drăguță. Aceasta se poate datora faptului că forța nu este destul de ideală sau din cauza termenului r-pătrat.
Aș vrea să modific formularea așa:
var f: Număr = (0,8 * 50 * 10) / r;
După cum puteți vedea, am redus valoarea lui "G" la 0,8 și am schimbat forța pentru a depinde pur și simplu de distanța dintre obiecte, mai degrabă decât de la distanța pătrată.
Încearcă-l și vezi dacă te bucuri de schimbare. Puteți oricând să o modificați oricum doriți.
Va trebui să afișăm un text pe ecran, pentru a afișa scorul și puterea rămasă a navei.
În acest scop, vom construi o clasă nouă, Text
:
pachet import flash.display.MovieClip; import flash.text.TextField; importul flash.events.Event; import flash.text.TextFormat; import flash.text.TextFormatAlign; public class Text extinde MovieClip public var _scoreText: TextField = new TextField (); funcția publică Text (șir: String) var myScoreFormat: TextFormat = new TextFormat (); // Format schimbabil myScoreFormat.size = 24; myScoreFormat.align = TextFormatAlign.LEFT; myScoreFormat.color = (0x131313); _scoreText.defaultTextFormat = myScoreFormat; _scoreText.text = string; addChild (_scoreText); funcția publică updateText (șir: String) _scoreText.text = string;
E foarte simplu; este practic un filmClip cu un câmp de text înăuntru.
Pentru a oferi jocului o provocare, vom face ca puterea navei să fie consumată încet, astfel încât jucătorul să colecteze obiecte energetice pentru a reîncărca.
Pentru a face puterea navei să apară pe nava însăși, putem adăuga pur și simplu o instanță Text
în lista de afișare a obiectului navei.
Declarați aceste variabile în cadrul Navă
clasă:
public var totalPower: Număr = 100; // nava pornește cu această putere privată var powerText: Text;
Va trebui să păstrăm cantitatea de energie (stocată și afișată) actualizată la fiecare cadru, deci adăugați această nouă funcție Jucător
:
În primul rând, în constructor:
// adăugați un nou obiect text dacă acesta nu există deja dacă (! powerText) powerText = text nou (String (int (totalPower))); addChild (powerText); powerText.x - = 20; // Ajustați poziția powerText.y - = 16;
Și apoi…
funcția publică updatePower (): void // fps = 24, deci aceasta reduce puterea cu 1 / sec totalPower - = 1/24; powerText.updateText (String (int (totalPower)));
Puterea va scădea la fiecare cadru cu 1/24 de unitate, ceea ce înseamnă că va scădea cu o unitate completă în fiecare secundă.
Trebuie să executați acest lucru în fiecare cadru, deci adăugați această linie GameScreen.update ()
:
player.updatePower ();
Când nava se ciocnește cu un obiect energetic, vrem să-i crească puterea.
În GameScreen.update ()
, adăugați linia evidențiată:
returnPower = energyM.checkCollision (jucător); player.totalPower + = returnPower;
Amintiți-vă că puteți modifica cât de multă putere este returnată în EnergyManager.checkCollision ()
funcţie.
Din nou, vom avea nevoie de clasa de text. De data aceasta, vom afișa "Scorul" și apoi valoarea.
Aici vom avea nevoie de alte trei variabile:
Declarați-le înăuntru GameScreen
clasă:
private var scoreText: Text; private var totalScore: int = 0; scor privat var: Text;
În constructor, adăugați acest cod:
scoreText = text nou ("Scor:"); addChild (scoreText); scor = text nou (String (totalScore)); addChild (scor); score.x = scoreText.x + 100; // Poziționați-l lângă textul "Scor:". score.y + = 2;
Acum, în Actualizați()
funcția, adăugați aceasta:
score.updateText (String (Scorul total));
Asta este - am creat o versiune de bază a jocului de mai sus!
Aruncați o privire (poate fi necesar să reîncărcați pagina):
Poate că doriți și un fundal cu o imagine încorporată și cu stele. Adăugați-o la dvs. Principal
clasă:
[Embed (sursă = "/ ... / lib /SpaceBackground.jpg")] // încorporați privat var backgroundImage: Class; // Această linie trebuie să apară imediat după încorporarea privată var bgImage: Bitmap = newImage (); privat var numOfStars: int = 70;
Acum creați Stea
clasă:
pachete de active import flash.display.MovieClip; importul flash.events.Event; public class Star extinde MovieClip private var speed: Number; funcție publică Star (alfa: număr, dimensiune: număr, viteză1: număr) graphic.beginFill (0xCCCCCC); grafice.drawCircle (0, 0, dimensiune); viteza = viteza1; // asigurați-vă că numiți această funcție privată a fiecărui cadru moveDown (): void this.y + = speed; dacă (this.y> = 600) this.y = 0;
În Principal()
constructor, adăugați-l pentru a crea stele:
pentru (var i: int = 0; i < numOfStars; i++) createStars();
Iată realitatea createStars ()
funcţie:
funcția privată createStars (): void var stea: Star = noua stea (Math.random (), Calculations.getRandomValue (1, 2), Calculations.getRandomValue (2, 5)); // aleatoriu alfa, mărimea și viteza addChild (stea); star.x = Calculations.getRandomValue (0, 550); star.y = Calculations.getRandomValue (0, 600);
Cu alfa aleatoare, dimensiune, poziție și viteză, poate fi generat un fond pseudo-3D.
Un cerc indicator al intervalului poate fi realizat prin crearea unui alt cerc și adăugarea acestuia în lista de afișare a navei, la fel cum ați adăugat textul indicatorului de alimentare. Asigurați-vă că cercul este centrat pe navă și are o rază egală cu aria de împingere / tragere a navei.
Adăugați transparanța (valoarea alfa) în cercul cu codul de mai jos:
graphics.beginFill (0xCCCCCC, 0.1);
Încercați să adăugați comenzi suplimentare care să mărească sau să micșoreze intervalul când sunt apăsate tastele săgeată sus și jos.
Sper că vă place acest tutorial! Vă rugăm să nu lăsați comentarii.
Următor →: Citiți această critică pentru un ghid pentru a lua Flux de la un demo simplu la un joc complet!