You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/ro/6-space-game/6-end-condition
softchris bde9da6dad
🌐 Update translations via Co-op Translator
1 month ago
..
solution 🌐 Update translations via Co-op Translator 3 months ago
your-work 🌐 Update translations via Co-op Translator 3 months ago
README.md 🌐 Update translations via Co-op Translator 1 month ago
assignment.md 🌐 Update translations via Co-op Translator 1 month ago

README.md

Construiește un Joc Spațial Partea 6: Final și Restart

Fiecare joc grozav are nevoie de condiții clare de finalizare și un mecanism de restart fluid. Ai construit un joc spațial impresionant cu mișcare, luptă și punctaj - acum este momentul să adaugi piesele finale care îl fac să pară complet.

Jocul tău rulează în prezent la nesfârșit, la fel ca sondele Voyager lansate de NASA în 1977 - încă călătorind prin spațiu după decenii. Deși acest lucru este în regulă pentru explorarea spațială, jocurile au nevoie de puncte finale definite pentru a crea experiențe satisfăcătoare.

Astăzi, vom implementa condiții corecte de câștig/pierdere și un sistem de restart. Până la sfârșitul acestei lecții, vei avea un joc finisat pe care jucătorii îl pot finaliza și relua, la fel ca jocurile arcade clasice care au definit acest mediu.

Test înainte de lecție

Test înainte de lecție

Înțelegerea condițiilor de finalizare ale jocului

Când ar trebui să se termine jocul tău? Această întrebare fundamentală a modelat designul jocurilor încă din era arcade. Pac-Man se termină când ești prins de fantome sau când cureți toate punctele, în timp ce Space Invaders se termină când extratereștrii ajung jos sau când îi distrugi pe toți.

Ca creator al jocului, tu definești condițiile de victorie și înfrângere. Pentru jocul nostru spațial, iată câteva abordări dovedite care creează un gameplay captivant:

  • N nave inamice au fost distruse: Este destul de comun ca, dacă împarți un joc în diferite niveluri, să fie necesar să distrugi N nave inamice pentru a finaliza un nivel.
  • Nava ta a fost distrusă: Există cu siguranță jocuri în care pierzi dacă nava ta este distrusă. O altă abordare comună este conceptul de vieți. De fiecare dată când nava ta este distrusă, pierzi o viață. Odată ce toate viețile au fost pierdute, pierzi jocul.
  • Ai colectat N puncte: O altă condiție comună de finalizare este să colectezi puncte. Modul în care obții punctele depinde de tine, dar este destul de comun să atribui puncte diverselor activități, cum ar fi distrugerea unei nave inamice sau colectarea obiectelor pe care acestea le lasă când sunt distruse.
  • Finalizarea unui nivel: Acest lucru poate implica mai multe condiții, cum ar fi distrugerea a X nave inamice, colectarea a Y puncte sau poate colectarea unui obiect specific.

Implementarea funcționalității de restart a jocului

Jocurile bune încurajează rejucabilitatea prin mecanisme de restart fluide. Când jucătorii finalizează un joc (sau sunt înfrânți), de multe ori vor să încerce din nou imediat - fie pentru a-și depăși scorul, fie pentru a-și îmbunătăți performanța.

Tetris exemplifică perfect acest lucru: când blocurile tale ajung în partea de sus, poți începe instantaneu un nou joc fără a naviga prin meniuri complicate. Vom construi un sistem de restart similar care resetează curat starea jocului și îi readuce pe jucători în acțiune rapid.

Reflecție: Gândește-te la jocurile pe care le-ai jucat. În ce condiții se termină și cum ești îndemnat să le reîncepi? Ce face ca experiența de restart să fie fluidă versus frustrantă?

Ce vei construi

Vei implementa funcțiile finale care transformă proiectul tău într-o experiență completă de joc. Aceste elemente disting jocurile finisate de prototipurile de bază.

Iată ce adăugăm astăzi:

  1. Condiție de victorie: Distruge toți inamicii și bucură-te de o celebrare pe măsură (merită!)
  2. Condiție de înfrângere: Rămâi fără vieți și confruntă-te cu un ecran de înfrângere
  3. Mecanism de restart: Apasă Enter pentru a începe din nou - pentru că un joc nu este niciodată suficient
  4. Gestionarea stării: Totul de la zero de fiecare dată - fără inamici rămași sau erori ciudate din jocul anterior

Începem

Să pregătim mediul de dezvoltare. Ar trebui să ai toate fișierele jocului spațial din lecțiile anterioare pregătite.

Proiectul tău ar trebui să arate cam așa:

-| assets
  -| enemyShip.png
  -| player.png
  -| laserRed.png
  -| life.png
-| index.html
-| app.js
-| package.json

Pornește serverul de dezvoltare:

cd your-work
npm start

Această comandă:

  • Rulează un server local pe http://localhost:5000
  • Servește fișierele corect
  • Se reîmprospătează automat când faci modificări

Deschide http://localhost:5000 în browserul tău și verifică dacă jocul funcționează. Ar trebui să poți să te miști, să tragi și să interacționezi cu inamicii. Odată confirmat, putem continua cu implementarea.

💡 Sfat util: Pentru a evita avertismentele în Visual Studio Code, declară gameLoopId în partea de sus a fișierului ca let gameLoopId; în loc să-l declari în funcția window.onload. Acest lucru urmează cele mai bune practici de declarare a variabilelor în JavaScript modern.

Pași de implementare

Pasul 1: Creează funcții de urmărire a condițiilor de finalizare

Avem nevoie de funcții care să monitorizeze când ar trebui să se termine jocul. La fel ca senzorii de pe Stația Spațială Internațională care monitorizează constant sistemele critice, aceste funcții vor verifica continuu starea jocului.

function isHeroDead() {
  return hero.life <= 0;
}

function isEnemiesDead() {
  const enemies = gameObjects.filter((go) => go.type === "Enemy" && !go.dead);
  return enemies.length === 0;
}

Ce se întâmplă în spatele scenei:

  • Verifică dacă eroul nostru a rămas fără vieți (au!)
  • Numără câți inamici sunt încă activi
  • Returnează true când câmpul de luptă este liber de inamici
  • Folosește logică simplă de tip adevărat/fals pentru a păstra lucrurile clare
  • Filtrează toate obiectele din joc pentru a găsi supraviețuitorii

Pasul 2: Actualizează gestionarea evenimentelor pentru condițiile de finalizare

Acum vom conecta aceste verificări ale condițiilor la sistemul de evenimente al jocului. De fiecare dată când are loc o coliziune, jocul va evalua dacă aceasta declanșează o condiție de finalizare. Acest lucru creează un feedback imediat pentru evenimentele critice ale jocului.

eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
    first.dead = true;
    second.dead = true;
    hero.incrementPoints();

    if (isEnemiesDead()) {
      eventEmitter.emit(Messages.GAME_END_WIN);
    }
});

eventEmitter.on(Messages.COLLISION_ENEMY_HERO, (_, { enemy }) => {
    enemy.dead = true;
    hero.decrementLife();
    if (isHeroDead())  {
      eventEmitter.emit(Messages.GAME_END_LOSS);
      return; // loss before victory
    }
    if (isEnemiesDead()) {
      eventEmitter.emit(Messages.GAME_END_WIN);
    }
});

eventEmitter.on(Messages.GAME_END_WIN, () => {
    endGame(true);
});
  
eventEmitter.on(Messages.GAME_END_LOSS, () => {
  endGame(false);
});

Ce se întâmplă aici:

  • Laserul lovește inamicul: Ambele dispar, primești puncte și verificăm dacă ai câștigat
  • Inamicul te lovește: Pierzi o viață și verificăm dacă mai ești în joc
  • Ordine inteligentă: Verificăm mai întâi înfrângerea (nimeni nu vrea să câștige și să piardă în același timp!)
  • Reacții instantanee: De îndată ce se întâmplă ceva important, jocul știe despre asta

Pasul 3: Adaugă noi constante pentru mesaje

Va trebui să adaugi noi tipuri de mesaje în obiectul constant Messages. Aceste constante ajută la menținerea consistenței și prevenirea greșelilor de scriere în sistemul de evenimente.

GAME_END_LOSS: "GAME_END_LOSS",
GAME_END_WIN: "GAME_END_WIN",

În cele de mai sus, am:

  • Adăugat constante pentru evenimentele de finalizare a jocului pentru a menține consistența
  • Folosit nume descriptive care indică clar scopul evenimentului
  • Urmat convenția de denumire existentă pentru tipurile de mesaje

Pasul 4: Implementarea controalelor de restart

Acum vei adăuga controale de tastatură care permit jucătorilor să reînceapă jocul. Tasta Enter este o alegere naturală, deoarece este asociată frecvent cu confirmarea acțiunilor și începerea unor jocuri noi.

Adaugă detectarea tastei Enter la listener-ul existent pentru evenimentele de apăsare a tastelor:

else if(evt.key === "Enter") {
   eventEmitter.emit(Messages.KEY_EVENT_ENTER);
}

Adaugă noua constantă de mesaj:

KEY_EVENT_ENTER: "KEY_EVENT_ENTER",

Ce trebuie să știi:

  • Extinde sistemul existent de gestionare a evenimentelor de tastatură
  • Folosește tasta Enter ca declanșator pentru restart, pentru o experiență intuitivă
  • Emite un eveniment personalizat pe care alte părți ale jocului îl pot asculta
  • Menține același model ca celelalte controale de tastatură

Pasul 5: Creează sistemul de afișare a mesajelor

Jocul tău trebuie să comunice clar rezultatele jucătorilor. Vom crea un sistem de mesaje care afișează stările de victorie și înfrângere folosind text colorat, similar interfețelor terminalelor primelor sisteme de calcul, unde verde indica succesul și roșu semnala erorile.

Creează funcția displayMessage():

function displayMessage(message, color = "red") {
  ctx.font = "30px Arial";
  ctx.fillStyle = color;
  ctx.textAlign = "center";
  ctx.fillText(message, canvas.width / 2, canvas.height / 2);
}

Pas cu pas, iată ce se întâmplă:

  • Setează dimensiunea și familia fontului pentru un text clar și ușor de citit
  • Aplică un parametru de culoare cu "roșu" ca implicit pentru avertismente
  • Centrează textul orizontal și vertical pe canvas
  • Folosește parametrii impliciți moderni din JavaScript pentru opțiuni flexibile de culoare
  • Utilizează contextul 2D al canvas-ului pentru redarea directă a textului

Creează funcția endGame():

function endGame(win) {
  clearInterval(gameLoopId);

  // Set a delay to ensure any pending renders complete
  setTimeout(() => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    if (win) {
      displayMessage(
        "Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew",
        "green"
      );
    } else {
      displayMessage(
        "You died !!! Press [Enter] to start a new game Captain Pew Pew"
      );
    }
  }, 200)  
}

Ce face această funcție:

  • Îngheață totul - fără nave sau lasere în mișcare
  • Ia o mică pauză (200ms) pentru a permite ultimului cadru să se finalizeze
  • Curăță ecranul și îl colorează în negru pentru un efect dramatic
  • Afișează mesaje diferite pentru câștigători și învinși
  • Codifică mesajele în culori - verde pentru bine, roșu pentru... ei bine, nu prea bine
  • Spune jucătorilor exact cum să reînceapă

Pasul 6: Implementarea funcționalității de resetare a jocului

Sistemul de resetare trebuie să curețe complet starea actuală a jocului și să inițializeze o sesiune nouă. Acest lucru asigură că jucătorii au un început curat, fără date rămase din jocul anterior.

Creează funcția resetGame():

function resetGame() {
  if (gameLoopId) {
    clearInterval(gameLoopId);
    eventEmitter.clear();
    initGame();
    gameLoopId = setInterval(() => {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.fillStyle = "black";
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      drawPoints();
      drawLife();
      updateGameObjects();
      drawGameObjects(ctx);
    }, 100);
  }
}

Să înțelegem fiecare parte:

  • Verifică dacă un loop de joc rulează în prezent înainte de resetare
  • Curăță loop-ul existent pentru a opri toate activitățile curente ale jocului
  • Elimină toate listener-ele de evenimente pentru a preveni scurgerile de memorie
  • Reinițializează starea jocului cu obiecte și variabile noi
  • Pornește un nou loop de joc cu toate funcțiile esențiale ale jocului
  • Menține același interval de 100ms pentru o performanță constantă a jocului

Adaugă handler-ul pentru tasta Enter în funcția initGame():

eventEmitter.on(Messages.KEY_EVENT_ENTER, () => {
  resetGame();
});

Adaugă metoda clear() în clasa EventEmitter:

clear() {
  this.listeners = {};
}

Puncte cheie de reținut:

  • Conectează apăsarea tastei Enter la funcționalitatea de resetare a jocului
  • Înregistrează acest listener de evenimente în timpul inițializării jocului
  • Oferă o modalitate curată de a elimina toate listener-ele de evenimente între jocuri
  • Previne scurgerile de memorie prin curățarea handler-elor de evenimente între jocuri
  • Resetează obiectul listener-elor la o stare goală pentru o inițializare proaspătă

Felicitări! 🎉

👽 💥 🚀 Ai reușit să construiești un joc complet de la zero. La fel ca programatorii care au creat primele jocuri video în anii '70, ai transformat linii de cod într-o experiență interactivă cu mecanici de joc și feedback pentru utilizatori. 🚀 💥 👽

Ai realizat:

  • Implementarea condițiilor complete de câștig și pierdere cu feedback pentru utilizatori
  • Crearea unui sistem de restart fluid pentru o experiență continuă de joc
  • Proiectarea unei comunicări vizuale clare pentru stările jocului
  • Gestionarea tranzițiilor complexe ale stării jocului și curățarea acestuia
  • Asamblarea tuturor componentelor într-un joc coerent și jucabil

Provocarea Agentului GitHub Copilot 🚀

Folosește modul Agent pentru a finaliza următoarea provocare:

Descriere: Îmbunătățește jocul spațial prin implementarea unui sistem de progresie pe niveluri cu dificultate crescută și funcții bonus.

Prompt: Creează un sistem de joc pe mai multe niveluri, în care fiecare nivel are mai multe nave inamice cu viteză și sănătate crescute. Adaugă un multiplicator de punctaj care crește cu fiecare nivel și implementează power-up-uri (cum ar fi foc rapid sau scut) care apar aleatoriu când inamicii sunt distruși. Include un bonus pentru finalizarea nivelului și afișează nivelul curent pe ecran alături de scorul și viețile existente.

Află mai multe despre modul agent aici.

🚀 Provocare opțională de îmbunătățire

Adaugă sunet jocului tău: Îmbunătățește experiența de joc prin implementarea efectelor sonore! Ia în considerare adăugarea de sunet pentru:

  • Focurile de laser când jucătorul trage
  • Distrugerea inamicilor când navele sunt lovite
  • Deteriorarea eroului când jucătorul este lovit
  • Muzică de victorie când jocul este câștigat
  • Sunet de înfrângere când jocul este pierdut

Exemplu de implementare audio:

// Create audio objects
const laserSound = new Audio('assets/laser.wav');
const explosionSound = new Audio('assets/explosion.wav');

// Play sounds during game events
function playLaserSound() {
  laserSound.currentTime = 0; // Reset to beginning
  laserSound.play();
}

Ce trebuie să știi:

  • Creează obiecte Audio pentru diferite efecte sonore
  • Resetează currentTime pentru a permite efecte sonore rapide
  • Gestionează politicile de autoplay ale browserului prin declanșarea sunetelor din interacțiuni ale utilizatorului
  • Administrează volumul și sincronizarea audio pentru o experiență mai bună de joc

💡 Resursă de învățare: Explorează acest sandbox audio pentru a învăța mai multe despre implementarea audio în jocurile JavaScript.

Test după lecție

Test după lecție

Recapitulare & Studiu individual

Tema ta este să creezi un joc nou, așa că explorează câteva dintre jocurile interesante existente pentru a vedea ce tip de joc ai putea construi.

Temă

Construiește un joc de probă


Declinare de responsabilitate:
Acest document a fost tradus folosind serviciul de traducere AI Co-op Translator. Deși ne străduim să asigurăm acuratețea, vă rugăm să fiți conștienți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa natală ar trebui considerat sursa autoritară. Pentru informații critice, se recomandă traducerea profesională realizată de oameni. Nu ne asumăm responsabilitatea pentru eventualele neînțelegeri sau interpretări greșite care pot apărea din utilizarea acestei traduceri.