17 KiB
Vytvorenie vesmírnej hry, časť 4: Pridanie lasera a detekcia kolízií
Kvíz pred prednáškou
Spomeňte si na moment v Star Wars, keď Lukeove protónové torpéda zasiahli výfukový port Hviezdnej smrti. Táto presná detekcia kolízie zmenila osud galaxie! V hrách funguje detekcia kolízií rovnako - určuje, kedy objekty interagujú a čo sa stane ďalej.
V tejto lekcii pridáte laserové zbrane do svojej vesmírnej hry a implementujete detekciu kolízií. Rovnako ako plánovači misií NASA vypočítavajú trajektórie kozmických lodí, aby sa vyhli troskám, naučíte sa detekovať, keď sa herné objekty pretínajú. Rozdelíme to na zvládnuteľné kroky, ktoré na seba nadväzujú.
Na konci budete mať funkčný bojový systém, kde lasery ničia nepriateľov a kolízie spúšťajú herné udalosti. Tieto princípy detekcie kolízií sa používajú vo všetkom, od simulácií fyziky až po interaktívne webové rozhrania.
✅ Urobte si malý prieskum o úplne prvej počítačovej hre, ktorá bola kedy napísaná. Aká bola jej funkčnosť?
Detekcia kolízií
Detekcia kolízií funguje ako senzory blízkosti na lunárnom module Apollo - neustále kontroluje vzdialenosti a spúšťa upozornenia, keď sa objekty dostanú príliš blízko. V hrách tento systém určuje, kedy objekty interagujú a čo by sa malo stať ďalej.
Prístup, ktorý použijeme, považuje každý herný objekt za obdĺžnik, podobne ako systémy riadenia leteckej dopravy používajú zjednodušené geometrické tvary na sledovanie lietadiel. Tento obdĺžnikový prístup sa môže zdať základný, ale je výpočtovo efektívny a funguje dobre vo väčšine herných scenárov.
Reprezentácia obdĺžnika
Každý herný objekt potrebuje hranice súradníc, podobne ako rover Mars Pathfinder mapoval svoju polohu na povrchu Marsu. Tu je spôsob, ako definujeme tieto hranice súradníc:
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width
}
}
Rozdelenie na časti:
- Horný okraj: To je miesto, kde váš objekt začína vertikálne (jeho y pozícia)
- Ľavý okraj: Miesto, kde začína horizontálne (jeho x pozícia)
- Spodný okraj: Pridajte výšku k y pozícii - teraz viete, kde končí!
- Pravý okraj: Pridajte šírku k x pozícii - a máte kompletné hranice
Algoritmus prekrývania
Detekcia prekrývania obdĺžnikov používa logiku podobnú tomu, ako Hubbleov vesmírny teleskop určuje, či sa nebeské objekty prekrývajú vo svojom zornom poli. Algoritmus kontroluje oddelenie:
function intersectRect(r1, r2) {
return !(r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top);
}
Test oddelenia funguje ako radarové systémy:
- Je obdĺžnik 2 úplne napravo od obdĺžnika 1?
- Je obdĺžnik 2 úplne naľavo od obdĺžnika 1?
- Je obdĺžnik 2 úplne pod obdĺžnikom 1?
- Je obdĺžnik 2 úplne nad obdĺžnikom 1?
Ak žiadna z týchto podmienok nie je pravdivá, obdĺžniky sa musia prekrývať. Tento prístup odráža spôsob, akým operátori radaru určujú, či sú dve lietadlá v bezpečnej vzdialenosti.
Správa životného cyklu objektov
Keď laser zasiahne nepriateľa, oba objekty musia byť odstránené z hry. Avšak mazanie objektov počas cyklu môže spôsobiť pády - lekcia, ktorú sa ťažko naučili v skorých počítačových systémoch, ako je Apollo Guidance Computer. Namiesto toho používame prístup "označiť na odstránenie", ktorý bezpečne odstraňuje objekty medzi snímkami.
Tu je spôsob, ako niečo označiť na odstránenie:
// Mark object for removal
enemy.dead = true;
Prečo tento prístup funguje:
- Označíme objekt ako "mŕtvy", ale neodstránime ho hneď
- To umožňuje aktuálnemu hernému cyklu bezpečne skončiť
- Žiadne pády z pokusu použiť niečo, čo už neexistuje!
Potom pred ďalším cyklom vykreslenia odfiltrujeme označené objekty:
gameObjects = gameObjects.filter(go => !go.dead);
Čo toto filtrovanie robí:
- Vytvára nový zoznam iba so "živými" objektmi
- Vyhadzuje všetko označené ako mŕtve
- Udržuje vašu hru plynulú
- Zabraňuje pamäťovému preťaženiu z hromadenia zničených objektov
Implementácia mechaniky lasera
Laserové projektily v hrách fungujú na rovnakom princípe ako fotónové torpéda v Star Treku - sú to diskrétne objekty, ktoré sa pohybujú po priamke, kým niečo zasiahnu. Každé stlačenie medzerníka vytvorí nový laserový objekt, ktorý sa pohybuje po obrazovke.
Aby to fungovalo, musíme koordinovať niekoľko rôznych častí:
Kľúčové komponenty na implementáciu:
- Vytvoriť laserové objekty, ktoré sa objavia z pozície hrdinu
- Spracovať vstup z klávesnice na spustenie vytvorenia lasera
- Spravovať pohyb a životný cyklus lasera
- Implementovať vizuálne zobrazenie laserových projektilov
Implementácia kontroly rýchlosti streľby
Neobmedzené rýchlosti streľby by preťažili herný engine a urobili hru príliš jednoduchou. Skutočné zbraňové systémy čelia podobným obmedzeniam - dokonca aj fázer USS Enterprise potreboval čas na dobitie medzi výstrelmi.
Implementujeme systém ochladenia, ktorý zabráni nadmernému strieľaniu a zároveň zachová citlivé ovládanie:
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
}
}
}
Ako funguje ochladenie:
- Pri vytvorení je zbraň "horúca" (ešte nemôže strieľať)
- Po uplynutí časového limitu sa stane "chladnou" (pripravená na streľbu)
- Pred streľbou kontrolujeme: "Je zbraň chladná?"
- To zabraňuje spamovaniu kliknutím a zároveň zachováva citlivé ovládanie
✅ Pozrite si lekciu 1 zo série vesmírnych hier, aby ste si pripomenuli systém ochladenia.
Budovanie systému detekcie kolízií
Rozšírite existujúci kód svojej vesmírnej hry, aby ste vytvorili systém detekcie kolízií. Rovnako ako automatizovaný systém vyhýbania sa kolíziám Medzinárodnej vesmírnej stanice, vaša hra bude neustále monitorovať polohy objektov a reagovať na ich prekrývanie.
Na základe kódu z predchádzajúcej lekcie pridáte detekciu kolízií s konkrétnymi pravidlami, ktoré riadia interakcie objektov.
💡 Tip: Sprite lasera je už zahrnutý vo vašom priečinku s aktívami a je referencovaný vo vašom kóde, pripravený na implementáciu.
Pravidlá kolízií na implementáciu
Herné mechaniky na pridanie:
- Laser zasiahne nepriateľa: Objekt nepriateľa je zničený, keď ho zasiahne laserový projektil
- Laser zasiahne hranicu obrazovky: Laser je odstránený, keď dosiahne horný okraj obrazovky
- Kolízia nepriateľa a hrdinu: Oba objekty sú zničené, keď sa prekrývajú
- Nepriateľ dosiahne spodok: Stav konca hry, keď nepriatelia dosiahnu spodok obrazovky
Nastavenie vývojového prostredia
Dobrá správa - väčšinu základov sme už pre vás pripravili! Všetky vaše herné aktíva a základná štruktúra čakajú v podpriečinku your-work, pripravené na pridanie skvelých funkcií detekcie kolízií.
Štruktúra projektu
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| index.html
-| app.js
-| package.json
Porozumenie štruktúre súborov:
- Obsahuje všetky obrázky sprite potrebné pre herné objekty
- Zahŕňa hlavný HTML dokument a JavaScript aplikáciu
- Poskytuje konfiguráciu balíka pre lokálny vývojový server
Spustenie vývojového servera
Prejdite do svojho priečinka projektu a spustite lokálny server:
cd your-work
npm start
Táto sekvencia príkazov:
- Zmení adresár na váš pracovný priečinok projektu
- Spustí lokálny HTTP server na
http://localhost:5000 - Poskytne vaše herné súbory na testovanie a vývoj
- Umožní živý vývoj s automatickým načítaním
Otvorte svoj prehliadač a prejdite na http://localhost:5000, aby ste videli aktuálny stav svojej hry s vykresleným hrdinom a nepriateľmi na obrazovke.
Implementácia krok za krokom
Rovnako ako systematický prístup, ktorý NASA použila na programovanie kozmickej lode Voyager, implementujeme detekciu kolízií metodicky, budujúc každý komponent krok za krokom.
1. Pridanie hraníc kolízie obdĺžnika
Najprv naučíme naše herné objekty, ako popísať svoje hranice. Pridajte túto metódu do svojej triedy GameObject:
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width,
};
}
Táto metóda dosahuje:
- Vytvára objekt obdĺžnika s presnými hranicami súradníc
- Vypočíta spodné a pravé okraje pomocou pozície plus rozmery
- Vracia objekt pripravený na algoritmy detekcie kolízií
- Poskytuje štandardizované rozhranie pre všetky herné objekty
2. Implementácia detekcie prekrývania
Teraz vytvoríme nášho detektíva kolízií - funkciu, ktorá dokáže povedať, kedy sa dva obdĺžniky prekrývajú:
function intersectRect(r1, r2) {
return !(
r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top
);
}
Tento algoritmus funguje takto:
- Testuje štyri podmienky oddelenia medzi obdĺžnikmi
- Vracia
false, ak je pravdivá akákoľvek podmienka oddelenia - Indikuje kolíziu, keď neexistuje žiadne oddelenie
- Používa negáciu logiky na efektívne testovanie prekrývania
3. Implementácia systému streľby laserom
Tu sa veci stávajú vzrušujúce! Nastavíme systém streľby laserom.
Konštanty správ
Najprv definujeme niektoré typy správ, aby rôzne časti našej hry mohli spolu komunikovať:
KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
Tieto konštanty poskytujú:
- Štandardizujú názvy udalostí v celej aplikácii
- Umožňujú konzistentnú komunikáciu medzi hernými systémami
- Zabraňujú preklepom pri registrácii obsluhy udalostí
Spracovanie vstupu z klávesnice
Pridajte detekciu stlačenia medzerníka do svojho poslucháča udalostí klávesnice:
} else if(evt.keyCode === 32) {
eventEmitter.emit(Messages.KEY_EVENT_SPACE);
}
Tento obslužný program vstupu:
- Detekuje stlačenie medzerníka pomocou keyCode 32
- Vysiela štandardizovanú správu o udalosti
- Umožňuje oddelenú logiku streľby
Nastavenie poslucháča udalostí
Zaregistrujte správanie streľby vo svojej funkcii initGame():
eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
if (hero.canFire()) {
hero.fire();
}
});
Tento poslucháč udalostí:
- Reaguje na udalosti stlačenia medzerníka
- Kontroluje stav ochladenia streľby
- Spúšťa vytvorenie lasera, keď je to povolené
Pridajte spracovanie kolízií pre interakcie laser-nepriateľ:
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
});
Tento obslužný program kolízií:
- Prijíma údaje o udalostiach kolízie s oboma objektmi
- Označuje oba objekty na odstránenie
- Zabezpečuje správne vyčistenie po kolízii
4. Vytvorenie triedy Laser
Implementujte laserový projektil, ktorý sa pohybuje nahor a spravuje svoj vlastný životný cyklus:
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);
}
}
Táto implementácia triedy:
- Rozširuje GameObject na zdedenie základnej funkčnosti
- Nastavuje vhodné rozmery pre sprite lasera
- Vytvára automatický pohyb nahor pomocou
setInterval() - Spracováva samodeštrukciu pri dosiahnutí vrcholu obrazovky
- Spravuje vlastné časovanie animácie a vyčistenie
5. Implementácia systému detekcie kolízií
Vytvorte komplexnú funkciu detekcie kolízií:
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);
}
Tento systém kolízií:
- Filtruje herné objekty podľa typu na efektívne testovanie
- Testuje každý laser proti každému nepriateľovi na prekrývanie
- Vysiela udalosti kolízie, keď sa prekrývanie zistí
- Čistí zničené objekty po spracovaní kolízií
⚠️ Dôležité: Pridajte
updateGameObjects()do hlavného herného cyklu vwindow.onload, aby ste umožnili detekciu kolízií.
6. Pridanie systému ochladenia do triedy Hero
Vylepšite triedu Hero o mechaniku streľby a obmedzenie rýchlosti:
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;
}
}
Porozumenie vylepšenej triedy Hero:
- Inicializuje časovač ochladenia na nulu (pripravený na streľbu)
- Vytvára laserové objekty umiestnené nad loďou hrdinu
- Nastavuje obdobie ochladenia na zabránenie rýchlej streľby
- Znižuje časovač ochladenia pomocou aktualizácií založených na intervaloch
- Poskytuje kontrolu stavu streľby cez metódu
canFire()
Testovanie vašej implementácie
Vaša vesmírna hra teraz obsahuje kompletnú detekciu kolízií a mechaniku boja. 🚀 Otestujte tieto nové schopnosti:
- Navigujte pomocou šípok na overenie ovládania pohybu
- Strieľajte lasery medzerníkom - všimnite si, ako ochladenie zabraňuje spamovaniu kliknutím
- Pozorujte kolízie, keď lasery zasiahnu nepriateľov, čo spustí ich odstránenie
- Overte vyčistenie, keď zničené objekty zmiznú z hry
Úspešne ste implementovali systém detekcie kolízií pomocou rovnakých matematických princípov, ktoré riadia navigáciu kozmických lodí a robotiku.
Výzva GitHub Copilot Agent 🚀
Použite režim Agent na splnenie nasledujúcej výzvy:
Popis: Vylepšite systém detekcie kolízií implementáciou power-upov, ktoré sa náhodne objavujú a poskytujú dočasné schopnosti, keď ich hrdinská loď získa.
Výzva: Vytvorte triedu PowerUp, ktorá rozširuje GameObject, a implementujte detekciu kolízií medzi hrdinom a power-upmi. Pridajte aspoň dva typy power-upov: jeden, ktorý zvyšuje rýchlosť streľby (znižuje ochladenie), a druhý, ktorý vytvára dočasný št
Zrieknutie sa zodpovednosti:
Tento dokument bol preložený pomocou služby AI prekladu Co-op Translator. Hoci sa snažíme o presnosť, prosím, berte na vedomie, že automatizované preklady môžu obsahovať chyby alebo nepresnosti. Pôvodný dokument v jeho rodnom jazyku by mal byť považovaný za autoritatívny zdroj. Pre kritické informácie sa odporúča profesionálny ľudský preklad. Nenesieme zodpovednosť za akékoľvek nedorozumenia alebo nesprávne interpretácie vyplývajúce z použitia tohto prekladu.