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/4-collision-detection
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 4: Adăugarea unui Laser și Detectarea Coliziunilor

Quiz înainte de lecție

Quiz înainte de lecție

Gândește-te la momentul din Star Wars când torpilele protonice ale lui Luke au lovit portul de evacuare al Death Star. Acea detectare precisă a coliziunii a schimbat soarta galaxiei! În jocuri, detectarea coliziunilor funcționează la fel - determină când obiectele interacționează și ce se întâmplă în continuare.

În această lecție, vei adăuga arme laser jocului tău spațial și vei implementa detectarea coliziunilor. La fel cum planificatorii de misiuni NASA calculează traiectoriile navelor spațiale pentru a evita resturile, vei învăța să detectezi când obiectele din joc se intersectează. Vom împărți acest proces în pași ușor de gestionat care se construiesc unul pe celălalt.

La final, vei avea un sistem de luptă funcțional în care laserele distrug inamicii, iar coliziunile declanșează evenimente în joc. Aceste principii de coliziune sunt utilizate în tot, de la simulări fizice la interfețe web interactive.

Fă puțină cercetare despre primul joc pe calculator scris vreodată. Care era funcționalitatea sa?

Detectarea coliziunilor

Detectarea coliziunilor funcționează ca senzorii de proximitate de pe modulul lunar Apollo - verifică constant distanțele și declanșează alerte când obiectele se apropie prea mult. În jocuri, acest sistem determină când obiectele interacționează și ce ar trebui să se întâmple în continuare.

Abordarea pe care o vom folosi tratează fiecare obiect din joc ca un dreptunghi, similar modului în care sistemele de control al traficului aerian folosesc forme geometrice simplificate pentru a urmări aeronavele. Această metodă dreptunghiulară poate părea simplistă, dar este eficientă din punct de vedere computațional și funcționează bine pentru majoritatea scenariilor de joc.

Reprezentarea dreptunghiului

Fiecare obiect din joc are nevoie de limite de coordonate, similar modului în care roverul Mars Pathfinder și-a cartografiat locația pe suprafața marțiană. Iată cum definim aceste limite:

rectFromGameObject() {
  return {
    top: this.y,
    left: this.x,
    bottom: this.y + this.height,
    right: this.x + this.width
  }
}

Să descompunem acest lucru:

  • Marginea de sus: Este locul unde începe obiectul pe verticală (poziția sa y)
  • Marginea din stânga: Locul unde începe pe orizontală (poziția sa x)
  • Marginea de jos: Adaugă înălțimea la poziția y - acum știi unde se termină!
  • Marginea din dreapta: Adaugă lățimea la poziția x - și ai limitele complete

Algoritmul de intersecție

Detectarea intersecțiilor dreptunghiurilor folosește o logică similară modului în care telescopul spațial Hubble determină dacă obiectele cerești se suprapun în câmpul său vizual. Algoritmul verifică separarea:

function intersectRect(r1, r2) {
  return !(r2.left > r1.right ||
    r2.right < r1.left ||
    r2.top > r1.bottom ||
    r2.bottom < r1.top);
}

Testul de separare funcționează ca sistemele radar:

  • Este dreptunghiul 2 complet la dreapta dreptunghiului 1?
  • Este dreptunghiul 2 complet la stânga dreptunghiului 1?
  • Este dreptunghiul 2 complet sub dreptunghiul 1?
  • Este dreptunghiul 2 complet deasupra dreptunghiului 1?

Dacă niciuna dintre aceste condiții nu este adevărată, dreptunghiurile trebuie să se suprapună. Această abordare reflectă modul în care operatorii radar determină dacă două aeronave sunt la distanțe sigure.

Gestionarea ciclurilor de viață ale obiectelor

Când un laser lovește un inamic, ambele obiecte trebuie eliminate din joc. Totuși, ștergerea obiectelor în mijlocul unui ciclu poate cauza erori - o lecție învățată cu greu în sistemele informatice timpurii, cum ar fi Computerul de Ghidare Apollo. În schimb, folosim o abordare de "marcare pentru ștergere" care elimină în siguranță obiectele între cadre.

Iată cum marcăm ceva pentru eliminare:

// Mark object for removal
enemy.dead = true;

De ce funcționează această abordare:

  • Marcăm obiectul ca "mort", dar nu îl ștergem imediat
  • Acest lucru permite finalizarea în siguranță a cadrului curent al jocului
  • Fără erori cauzate de încercarea de a folosi ceva ce a fost deja eliminat!

Apoi filtrăm obiectele marcate înainte de următorul ciclu de redare:

gameObjects = gameObjects.filter(go => !go.dead);

Ce face acest filtru:

  • Creează o listă nouă doar cu obiectele "vii"
  • Elimină tot ce este marcat ca mort
  • Menține jocul funcțional fără probleme
  • Previne acumularea de obiecte distruse în memorie

Implementarea mecanicii laserului

Proiectilele laser din jocuri funcționează pe același principiu ca torpilele fotonice din Star Trek - sunt obiecte discrete care se deplasează în linie dreaptă până când lovesc ceva. Fiecare apăsare a tastei spațiu creează un nou obiect laser care se mișcă pe ecran.

Pentru ca acest lucru să funcționeze, trebuie să coordonăm câteva piese diferite:

Componente cheie de implementat:

  • Crearea obiectelor laser care apar din poziția eroului
  • Gestionarea intrării de la tastatură pentru a declanșa crearea laserului
  • Administrarea mișcării și ciclului de viață al laserului
  • Implementarea reprezentării vizuale pentru proiectilele laser

Implementarea controlului ratei de tragere

Ratele de tragere nelimitate ar suprasolicita motorul jocului și ar face jocul prea ușor. Sistemele reale de arme se confruntă cu constrângeri similare - chiar și fazerele navei USS Enterprise aveau nevoie de timp pentru a se reîncărca între focuri.

Vom implementa un sistem de răcire care previne spam-ul de focuri rapide, menținând în același timp controalele receptive:

class Cooldown {
  constructor(time) {
    this.cool = false;
    setTimeout(() => {
      this.cool = true;
    }, time);
  }
}

class Weapon {
  constructor() {
    this.cooldown = null;
  }
  
  fire() {
    if (!this.cooldown || this.cooldown.cool) {
      // Create laser projectile
      this.cooldown = new Cooldown(500);
    } else {
      // Weapon is still cooling down
    }
  }
}

Cum funcționează sistemul de răcire:

  • Când este creată, arma începe "fierbinte" (nu poate trage încă)
  • După perioada de așteptare, devine "rece" (gata de tragere)
  • Înainte de a trage, verificăm: "Este arma rece?"
  • Acest lucru previne spam-ul de clicuri, menținând în același timp controalele receptive

Consultă lecția 1 din seria de jocuri spațiale pentru a-ți aminti despre sistemele de răcire.

Construirea sistemului de detectare a coliziunilor

Vei extinde codul existent al jocului spațial pentru a crea un sistem de detectare a coliziunilor. La fel ca sistemul automat de evitare a coliziunilor al Stației Spațiale Internaționale, jocul tău va monitoriza continuu pozițiile obiectelor și va răspunde la intersecții.

Pornind de la codul lecției anterioare, vei adăuga detectarea coliziunilor cu reguli specifice care guvernează interacțiunile obiectelor.

💡 Sfat util: Sprite-ul laser este deja inclus în folderul de resurse și referit în codul tău, gata de implementare.

Reguli de coliziune de implementat

Mecanici de joc de adăugat:

  1. Laserul lovește inamicul: Obiectul inamic este distrus când este lovit de un proiectil laser
  2. Laserul lovește marginea ecranului: Laserul este eliminat când ajunge la marginea de sus a ecranului
  3. Coliziunea între inamic și erou: Ambele obiecte sunt distruse când se intersectează
  4. Inamicul ajunge jos: Condiție de sfârșit de joc când inamicii ajung la marginea de jos a ecranului

Configurarea mediului de dezvoltare

Vești bune - am pregătit deja cea mai mare parte a bazei pentru tine! Toate resursele jocului și structura de bază sunt gata în subfolderul your-work, pregătite pentru a adăuga funcțiile interesante de coliziune.

Structura proiectului

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

Înțelegerea structurii fișierelor:

  • Conține toate imaginile sprite necesare pentru obiectele jocului
  • Include documentul principal HTML și fișierul aplicației JavaScript
  • Oferă configurația pachetului pentru serverul local de dezvoltare

Pornirea serverului de dezvoltare

Navighează la folderul proiectului și pornește serverul local:

cd your-work
npm start

Această secvență de comenzi:

  • Schimbă directorul către folderul proiectului tău de lucru
  • Pornește un server HTTP local pe http://localhost:5000
  • Servește fișierele jocului pentru testare și dezvoltare
  • Permite dezvoltarea live cu reîncărcare automată

Deschide browserul și navighează la http://localhost:5000 pentru a vedea starea actuală a jocului tău cu eroul și inamicii redați pe ecran.

Implementare pas cu pas

La fel ca abordarea sistematică folosită de NASA pentru a programa nava spațială Voyager, vom implementa detectarea coliziunilor metodic, construind fiecare componentă pas cu pas.

1. Adaugă limitele de coliziune ale dreptunghiului

Mai întâi, să învățăm obiectele din joc cum să-și descrie limitele. Adaugă această metodă la clasa GameObject:

rectFromGameObject() {
    return {
      top: this.y,
      left: this.x,
      bottom: this.y + this.height,
      right: this.x + this.width,
    };
  }

Această metodă realizează:

  • Creează un obiect dreptunghiular cu coordonate precise ale limitelor
  • Calculează marginile de jos și de dreapta folosind poziția plus dimensiunile
  • Returnează un obiect gata pentru algoritmii de detectare a coliziunilor
  • Oferă o interfață standardizată pentru toate obiectele din joc

2. Implementarea detectării intersecțiilor

Acum să creăm detectivul nostru de coliziuni - o funcție care poate spune când două dreptunghiuri se suprapun:

function intersectRect(r1, r2) {
  return !(
    r2.left > r1.right ||
    r2.right < r1.left ||
    r2.top > r1.bottom ||
    r2.bottom < r1.top
  );
}

Acest algoritm funcționează prin:

  • Testează patru condiții de separare între dreptunghiuri
  • Returnează false dacă orice condiție de separare este adevărată
  • Indică coliziunea când nu există separare
  • Folosește logica de negație pentru testarea eficientă a intersecțiilor

3. Implementarea sistemului de tragere cu laser

Acum lucrurile devin interesante! Să configurăm sistemul de tragere cu laser.

Constante de mesaje

Mai întâi, să definim câteva tipuri de mesaje pentru ca diferite părți ale jocului să comunice între ele:

KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",

Aceste constante oferă:

  • Standardizează numele evenimentelor în întreaga aplicație
  • Permite comunicarea consistentă între sistemele jocului
  • Previne greșelile de tipar în înregistrarea handlerelor de evenimente
Gestionarea intrării de la tastatură

Adaugă detectarea tastei spațiu la listener-ul de evenimente pentru taste:

} else if(evt.keyCode === 32) {
  eventEmitter.emit(Messages.KEY_EVENT_SPACE);
}

Acest handler de intrare:

  • Detectează apăsările tastei spațiu folosind keyCode 32
  • Emite un mesaj de eveniment standardizat
  • Permite logica de tragere decuplată
Configurarea listener-ului de evenimente

Înregistrează comportamentul de tragere în funcția initGame():

eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
 if (hero.canFire()) {
   hero.fire();
 }
});

Acest listener de evenimente:

  • Răspunde la evenimentele tastei spațiu
  • Verifică starea de răcire a tragerii
  • Declanșează crearea laserului când este permis

Adaugă gestionarea coliziunilor pentru interacțiunile laser-inamic:

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

Acest handler de coliziuni:

  • Primește datele evenimentului de coliziune cu ambele obiecte
  • Marchează ambele obiecte pentru eliminare
  • Asigură curățarea corespunzătoare după coliziune

4. Creează clasa Laser

Implementează un proiectil laser care se mișcă în sus și își gestionează propriul ciclu de viață:

class Laser extends GameObject {
  constructor(x, y) {
    super(x, y);
    this.width = 9;
    this.height = 33;
    this.type = 'Laser';
    this.img = laserImg;
    
    let id = setInterval(() => {
      if (this.y > 0) {
        this.y -= 15;
      } else {
        this.dead = true;
        clearInterval(id);
      }
    }, 100);
  }
}

Această implementare a clasei:

  • Extinde GameObject pentru a moșteni funcționalitatea de bază
  • Setează dimensiuni adecvate pentru sprite-ul laserului
  • Creează mișcare automată în sus folosind setInterval()
  • Gestionează autodistrugerea când ajunge la marginea de sus a ecranului
  • Administrează propriul timp de animație și curățare

5. Implementarea sistemului de detectare a coliziunilor

Creează o funcție cuprinzătoare de detectare a coliziunilor:

function updateGameObjects() {
  const enemies = gameObjects.filter(go => go.type === 'Enemy');
  const lasers = gameObjects.filter(go => go.type === "Laser");
  
  // Test laser-enemy collisions
  lasers.forEach((laser) => {
    enemies.forEach((enemy) => {
      if (intersectRect(laser.rectFromGameObject(), enemy.rectFromGameObject())) {
        eventEmitter.emit(Messages.COLLISION_ENEMY_LASER, {
          first: laser,
          second: enemy,
        });
      }
    });
  });

  // Remove destroyed objects
  gameObjects = gameObjects.filter(go => !go.dead);
}

Acest sistem de coliziuni:

  • Filtrează obiectele din joc după tip pentru testare eficientă
  • Testează fiecare laser împotriva fiecărui inamic pentru intersecții
  • Emite evenimente de coliziune când sunt detectate intersecții
  • Curăță obiectele distruse după procesarea coliziunilor

⚠️ Important: Adaugă updateGameObjects() la bucla principală a jocului în window.onload pentru a activa detectarea coliziunilor.

6. Adaugă sistemul de răcire la clasa Hero

Îmbunătățește clasa Hero cu mecanici de tragere și limitarea ratei de tragere:

class Hero extends GameObject {
  constructor(x, y) {
    super(x, y);
    this.width = 99;
    this.height = 75;
    this.type = "Hero";
    this.speed = { x: 0, y: 0 };
    this.cooldown = 0;
  }
  
  fire() {
    gameObjects.push(new Laser(this.x + 45, this.y - 10));
    this.cooldown = 500;

    let id = setInterval(() => {
      if (this.cooldown > 0) {
        this.cooldown -= 100;
      } else {
        clearInterval(id);
      }
    }, 200);
  }
  
  canFire() {
    return this.cooldown === 0;
  }
}

Înțelegerea clasei Hero îmbunătățite:

  • Inițializează temporizatorul de răcire la zero (gata de tragere)
  • Creează obiecte laser poziționate deasupra navei eroului
  • Setează perioada de răcire pentru a preveni tragerea rapidă
  • Scade temporizatorul de răcire folosind actualizări bazate pe intervale
  • Oferă verificarea stării de tragere prin metoda canFire()

Testarea implementării

Jocul tău spațial are acum un sistem complet de detectare a coliziunilor și mecanici de luptă. 🚀 Testează aceste noi funcționalități:

  • Navighează cu tastele săgeți pentru a verifica controalele de mișcare
  • Trage lasere cu tasta spațiu - observă cum sistemul de răcire previne spam-ul de clicuri
  • Observă coliziunile când laserele lovesc inamicii, declanșând eliminarea
  • Verifică curățarea pe măsură ce obiectele distruse dispar din joc

Ai implementat cu succes un sistem de detectare a coliziunilor folosind aceleași principii matematice care ghidează navigația navelor spațiale și robotica.

Provocarea Agentului GitHub Copilot 🚀

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

Descriere: Îmbunătățește sistemul de detectare a coliziunilor prin implementarea unor power-up-uri care apar aleator și oferă abilități temporare atunci când sunt colectate de nava eroului.

Prompt: Creează o clasă PowerUp care extinde GameObject și implementează detectarea coliziunilor între erou și power-up-uri. Adaugă cel puțin două tipuri de power-up-uri: unul care crește rata de tragere (reduce perioada de răcire) și altul care creează un scut temporar. Include logica de apariție care creează power-up-uri la intervale și poziții aleatorii.


🚀 Provocare

Adaugă o explozie! Aruncă o privire la resursele jocului din repo-ul Space Art și încearcă să adaugi o explozie când laserul lovește un extraterestru.

Quiz după lecție

Quiz după lecție

Recapitulare & Studiu individual

Experimentează cu intervalele din jocul tău de până acum. Ce se întâmplă când le modifici? Citește mai multe despre evenimentele de temporizare în JavaScript.

Temă

Explorează coliziunile


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 un specialist uman. Nu ne asumăm responsabilitatea pentru neînțelegerile sau interpretările greșite care pot apărea din utilizarea acestei traduceri.