17 KiB
Izgradnja svemirske igre, dio 4: Dodavanje lasera i otkrivanje sudara
Kviz prije predavanja
Sjetite se trenutka u Star Warsu kada su protonski torpedi Lukea pogodili ispušni otvor Zvijezde smrti. Ta precizna detekcija sudara promijenila je sudbinu galaksije! U igrama, detekcija sudara funkcionira na isti način - određuje kada objekti međusobno djeluju i što se događa nakon toga.
U ovoj lekciji dodat ćete lasersko oružje svojoj svemirskoj igri i implementirati detekciju sudara. Baš kao što NASA-ini planeri misija izračunavaju putanje svemirskih letjelica kako bi izbjegli krhotine, naučit ćete otkriti kada se objekti u igri presijecaju. Razložit ćemo to na korake koji se mogu lako pratiti.
Na kraju, imat ćete funkcionalni sustav borbe u kojem laseri uništavaju neprijatelje, a sudari pokreću događaje u igri. Isti principi detekcije sudara koriste se u svemu, od simulacija fizike do interaktivnih web sučelja.
✅ Malo istražite o prvoj računalnoj igri ikada napisanoj. Koja je bila njezina funkcionalnost?
Detekcija sudara
Detekcija sudara funkcionira poput senzora blizine na lunarnom modulu Apollo - stalno provjerava udaljenosti i pokreće upozorenja kada se objekti previše približe. U igrama, ovaj sustav određuje kada objekti međusobno djeluju i što bi se trebalo dogoditi.
Pristup koji ćemo koristiti tretira svaki objekt igre kao pravokutnik, slično kako sustavi za kontrolu zračnog prometa koriste pojednostavljene geometrijske oblike za praćenje zrakoplova. Ova metoda pravokutnika može se činiti osnovnom, ali je računalno učinkovita i dobro funkcionira za većinu scenarija u igrama.
Predstavljanje pravokutnika
Svaki objekt igre treba granice koordinata, slično kako je rover Mars Pathfinder mapirao svoju lokaciju na površini Marsa. Evo kako definiramo te granice koordinata:
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width
}
}
Razložimo ovo:
- Gornji rub: To je samo mjesto gdje vaš objekt počinje vertikalno (njegova y pozicija)
- Lijevi rub: Mjesto gdje počinje horizontalno (njegova x pozicija)
- Donji rub: Dodajte visinu na y poziciju - sada znate gdje završava!
- Desni rub: Dodajte širinu na x poziciju - i imate kompletne granice
Algoritam presijecanja
Otkrivanje presijecanja pravokutnika koristi logiku sličnu onoj kako svemirski teleskop Hubble određuje preklapanje nebeskih objekata u svom vidnom polju. Algoritam provjerava razdvojenost:
function intersectRect(r1, r2) {
return !(r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top);
}
Test razdvojenosti funkcionira poput radarskih sustava:
- Je li pravokutnik 2 potpuno desno od pravokutnika 1?
- Je li pravokutnik 2 potpuno lijevo od pravokutnika 1?
- Je li pravokutnik 2 potpuno ispod pravokutnika 1?
- Je li pravokutnik 2 potpuno iznad pravokutnika 1?
Ako nijedan od ovih uvjeta nije istinit, pravokutnici se moraju preklapati. Ovaj pristup odražava način na koji operateri radara određuju jesu li dva zrakoplova na sigurnoj udaljenosti.
Upravljanje životnim ciklusom objekata
Kada laser pogodi neprijatelja, oba objekta moraju biti uklonjena iz igre. Međutim, brisanje objekata usred petlje može uzrokovati rušenje - lekcija naučena na teži način u ranim računalnim sustavima poput Apollo Guidance Computer. Umjesto toga, koristimo pristup "označavanja za brisanje" koji sigurno uklanja objekte između okvira.
Evo kako označavamo nešto za uklanjanje:
// Mark object for removal
enemy.dead = true;
Zašto ovaj pristup funkcionira:
- Označavamo objekt kao "mrtav", ali ga ne brišemo odmah
- To omogućuje trenutnom okviru igre da se sigurno završi
- Nema rušenja zbog pokušaja korištenja nečega što je već uklonjeno!
Zatim filtriramo označene objekte prije sljedećeg ciklusa renderiranja:
gameObjects = gameObjects.filter(go => !go.dead);
Što ovo filtriranje radi:
- Stvara svježi popis samo s "živim" objektima
- Izbacuje sve što je označeno kao mrtvo
- Održava vašu igru glatkom
- Sprječava nakupljanje uništenih objekata u memoriji
Implementacija mehanike lasera
Projektili lasera u igrama funkcioniraju na istom principu kao fotonski torpedi u Zvjezdanim stazama - to su diskretni objekti koji putuju ravno dok ne udare u nešto. Svaki pritisak na razmaknicu stvara novi laserski objekt koji se kreće preko ekrana.
Da bi ovo funkcioniralo, trebamo koordinirati nekoliko različitih dijelova:
Ključne komponente za implementaciju:
- Stvaranje laserskih objekata koji se pojavljuju iz pozicije heroja
- Rukovanje unosom s tipkovnice za pokretanje stvaranja lasera
- Upravljanje kretanjem lasera i životnim ciklusom
- Implementacija vizualnog prikaza za laserske projektile
Implementacija kontrole brzine pucanja
Neograničene brzine pucanja preopteretile bi motor igre i učinile igru prelaganom. Pravi sustavi oružja suočavaju se sa sličnim ograničenjima - čak su i fazeri USS Enterprisea trebali vrijeme za ponovno punjenje između pucanja.
Implementirat ćemo sustav hlađenja koji sprječava prekomjerno pucanje, a istovremeno održava responzivne kontrole:
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
}
}
}
Kako sustav hlađenja funkcionira:
- Kada se stvori, oružje postaje "vruće" (ne može pucati još)
- Nakon isteka vremena, postaje "hladno" (spremno za pucanje)
- Prije pucanja provjeravamo: "Je li oružje hladno?"
- Ovo sprječava prekomjerno klikanje, a istovremeno održava responzivne kontrole
✅ Pogledajte lekciju 1 u seriji svemirske igre kako biste se podsjetili na sustave hlađenja.
Izgradnja sustava detekcije sudara
Proširit ćete postojeći kod svoje svemirske igre kako biste stvorili sustav detekcije sudara. Kao automatizirani sustav izbjegavanja sudara Međunarodne svemirske postaje, vaša igra će kontinuirano pratiti pozicije objekata i reagirati na presijecanja.
Počevši od koda iz prethodne lekcije, dodat ćete detekciju sudara s posebnim pravilima koja upravljaju interakcijama objekata.
💡 Pro Savjet: Sprite za laser već je uključen u vašu mapu s resursima i referenciran u vašem kodu, spreman za implementaciju.
Pravila sudara za implementaciju
Mehanika igre za dodavanje:
- Laser pogodi neprijatelja: Objekt neprijatelja se uništava kada ga pogodi laserski projektil
- Laser pogodi granicu ekrana: Laser se uklanja kada dosegne gornji rub ekrana
- Sudar neprijatelja i heroja: Oba objekta se uništavaju kada se presijeku
- Neprijatelj dosegne dno: Uvjet za kraj igre kada neprijatelji dosegnu donji rub ekrana
Postavljanje vašeg razvojnog okruženja
Dobre vijesti - već smo postavili većinu temelja za vas! Svi vaši resursi igre i osnovna struktura čekaju u podmapi your-work, spremni za dodavanje cool značajki sudara.
Struktura projekta
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| index.html
-| app.js
-| package.json
Razumijevanje strukture datoteka:
- Sadrži sve slike spriteova potrebne za objekte igre
- Uključuje glavni HTML dokument i JavaScript aplikacijsku datoteku
- Pruža konfiguraciju paketa za lokalni razvojni server
Pokretanje razvojnog servera
Navigirajte do svoje mape projekta i pokrenite lokalni server:
cd your-work
npm start
Ova sekvenca naredbi:
- Mijenja direktorij na vašu radnu mapu projekta
- Pokreće lokalni HTTP server na
http://localhost:5000 - Poslužuje vaše datoteke igre za testiranje i razvoj
- Omogućuje razvoj uživo s automatskim osvježavanjem
Otvorite svoj preglednik i idite na http://localhost:5000 kako biste vidjeli trenutno stanje svoje igre s prikazanim herojem i neprijateljima na ekranu.
Implementacija korak po korak
Kao sustavni pristup koji je NASA koristila za programiranje svemirske letjelice Voyager, implementirat ćemo detekciju sudara metodično, gradeći svaki komponent korak po korak.
1. Dodavanje granica sudara pravokutnika
Prvo, naučimo naše objekte igre kako opisati svoje granice. Dodajte ovu metodu svojoj klasi GameObject:
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width,
};
}
Ova metoda omogućuje:
- Stvara objekt pravokutnika s preciznim granicama koordinata
- Izračunava donje i desne rubove koristeći poziciju plus dimenzije
- Vraća objekt spreman za algoritme detekcije sudara
- Pruža standardizirano sučelje za sve objekte igre
2. Implementacija detekcije presijecanja
Sada kreirajmo našeg detektiva sudara - funkciju koja može reći kada se dva pravokutnika preklapaju:
function intersectRect(r1, r2) {
return !(
r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top
);
}
Ovaj algoritam funkcionira tako da:
- Testira četiri uvjeta razdvojenosti između pravokutnika
- Vraća
falseako je bilo koji uvjet razdvojenosti istinit - Ukazuje na sudar kada ne postoji razdvojenost
- Koristi logiku negacije za učinkovito testiranje presijecanja
3. Implementacija sustava za pucanje lasera
Evo gdje postaje uzbudljivo! Postavimo sustav za pucanje lasera.
Konstantne poruke
Prvo, definirajmo neke vrste poruka kako bi različiti dijelovi naše igre mogli međusobno komunicirati:
KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
Ove konstante omogućuju:
- Standardiziraju nazive događaja u cijeloj aplikaciji
- Omogućuju dosljednu komunikaciju između sustava igre
- Sprječavaju tipografske pogreške u registraciji rukovatelja događajima
Rukovanje unosom s tipkovnice
Dodajte detekciju pritiska razmaknice svom slušatelju događaja na tipkovnici:
} else if(evt.keyCode === 32) {
eventEmitter.emit(Messages.KEY_EVENT_SPACE);
}
Ovaj rukovatelj unosa:
- Detektira pritiske razmaknice koristeći keyCode 32
- Emitira standardiziranu poruku događaja
- Omogućuje odvojenu logiku pucanja
Postavljanje slušatelja događaja
Registrirajte ponašanje pucanja u svojoj funkciji initGame():
eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
if (hero.canFire()) {
hero.fire();
}
});
Ovaj slušatelj događaja:
- Reagira na događaje pritiska razmaknice
- Provjerava status hlađenja za pucanje
- Pokreće stvaranje lasera kada je dopušteno
Dodajte rukovanje sudarima za interakcije između lasera i neprijatelja:
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
});
Ovaj rukovatelj sudara:
- Prima podatke o događaju sudara s oba objekta
- Označava oba objekta za uklanjanje
- Osigurava pravilno čišćenje nakon sudara
4. Kreiranje klase Laser
Implementirajte laserski projektil koji se kreće prema gore i upravlja vlastitim životnim ciklusom:
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);
}
}
Ova implementacija klase:
- Proširuje GameObject za nasljeđivanje osnovne funkcionalnosti
- Postavlja odgovarajuće dimenzije za sprite lasera
- Stvara automatsko kretanje prema gore koristeći
setInterval() - Rukuje samouništenjem kada dosegne vrh ekrana
- Upravlja vlastitim vremenskim animacijama i čišćenjem
5. Implementacija sustava detekcije sudara
Kreirajte sveobuhvatnu funkciju za detekciju sudara:
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);
}
Ovaj sustav sudara:
- Filtrira objekte igre po tipu za učinkovito testiranje
- Testira svaki laser protiv svakog neprijatelja za presijecanja
- Emitira događaje sudara kada se otkriju presijecanja
- Čisti uništene objekte nakon obrade sudara
⚠️ Važno: Dodajte
updateGameObjects()u glavnu petlju igre uwindow.onloadkako biste omogućili detekciju sudara.
6. Dodavanje sustava hlađenja u klasu Hero
Poboljšajte klasu Hero s mehanikom pucanja i ograničenjem brzine:
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;
}
}
Razumijevanje poboljšane klase Hero:
- Inicijalizira timer hlađenja na nulu (spremno za pucanje)
- Stvara objekte lasera pozicionirane iznad herojske letjelice
- Postavlja period hlađenja kako bi spriječio prekomjerno pucanje
- Smanjuje timer hlađenja koristeći ažuriranja temeljena na intervalu
- Pruža provjeru statusa pucanja kroz metodu
canFire()
Testiranje vaše implementacije
Vaša svemirska igra sada ima kompletan sustav detekcije sudara i mehaniku borbe. 🚀 Testirajte ove nove mogućnosti:
- Navigirajte strelicama kako biste provjerili kontrole kretanja
- Pucajte lasere razmaknicom - primijetite kako sustav hlađenja sprječava prekomjerno klikanje
- Promatrajte sudare kada laseri pogode neprijatelje, pokrećući uklanjanje
- Provjerite čišćenje kako uništeni objekti nestaju iz igre
Uspješno ste implementirali sustav detekcije sudara koristeći iste matematičke principe koji vode navigaciju svemirskih letjelica i robotiku.
GitHub Copilot Agent izazov 🚀
Koristite Agent način za dovršavanje sljedećeg izazova:
Opis: Poboljšajte sustav detekcije sudara implementacijom power-upova koji se nasumično pojavljuju i pružaju privremene sposobnosti kada ih pokupi herojska letjelica.
Zadatak: Kreirajte klasu PowerUp koja proširuje GameObject i implementirajte detekciju sudara između heroja i power-upova. Dodajte najmanje dvije vrste power-upova: jedan koji povećava brzinu pucanja (smanjuje hlađenje) i drugi koji stvara privremeni štit. Uključite logiku za stvaranje power-upova u nasumičnim intervalima i pozicijama.
🚀 Izazov
Dodajte eksploziju! Pogledajte resurse igre u repozitoriju Space Art i pokušajte dodati eksploziju kada laser pogodi vanzemaljca.
Kviz nakon predavanja
Pregled i samostalno učenje
Eksperimentirajte s intervalima u svojoj igri do sada. Što se događa kada ih promijenite? Pročitajte više o JavaScript vremenskim događajima.
Zadatak
Izjava o odricanju odgovornosti:
Ovaj dokument je preveden pomoću AI usluge za prevođenje Co-op Translator. Iako nastojimo osigurati točnost, imajte na umu da automatski prijevodi mogu sadržavati pogreške ili netočnosti. Izvorni dokument na izvornom jeziku treba smatrati autoritativnim izvorom. Za ključne informacije preporučuje se profesionalni prijevod od strane ljudskog prevoditelja. Ne preuzimamo odgovornost za nesporazume ili pogrešne interpretacije nastale korištenjem ovog prijevoda.