17 KiB
Ustvari vesoljsko igro, 4. del: Dodajanje laserja in zaznavanje trkov
Predavanje - kviz
Pomislite na trenutek v Vojni zvezd, ko so protonski torpedi Lukea zadeli izpušni kanal Zvezde smrti. To natančno zaznavanje trka je spremenilo usodo galaksije! V igrah zaznavanje trkov deluje na enak način - določa, kdaj objekti medsebojno vplivajo in kaj se zgodi potem.
V tej lekciji boste svoji vesoljski igri dodali lasersko orožje in implementirali zaznavanje trkov. Tako kot načrtovalci misij pri NASA-i izračunajo trajektorije vesoljskih plovil, da se izognejo ostankom, se boste naučili zaznati, kdaj se objekti v igri prekrivajo. Razdelili bomo to na obvladljive korake, ki se gradijo drug na drugem.
Na koncu boste imeli delujoč bojni sistem, kjer laserji uničujejo sovražnike, trki pa sprožijo dogodke v igri. Ti isti principi zaznavanja trkov se uporabljajo v vsem, od simulacij fizike do interaktivnih spletnih vmesnikov.
✅ Naredite malo raziskave o prvi računalniški igri, ki je bila kdaj napisana. Kakšna je bila njena funkcionalnost?
Zaznavanje trkov
Zaznavanje trkov deluje kot senzorji bližine na lunarnem modulu Apollo - nenehno preverja razdalje in sproži opozorila, ko se objekti preveč približajo. V igrah ta sistem določa, kdaj objekti medsebojno vplivajo in kaj naj se zgodi potem.
Pristop, ki ga bomo uporabili, obravnava vsak objekt v igri kot pravokotnik, podobno kot sistemi za nadzor zračnega prometa uporabljajo poenostavljene geometrijske oblike za sledenje letalom. Ta metoda s pravokotniki se morda zdi osnovna, vendar je računsko učinkovita in dobro deluje v večini scenarijev iger.
Predstavitev pravokotnika
Vsak objekt v igri potrebuje meje koordinat, podobno kot je rover Mars Pathfinder kartiral svojo lokacijo na površju Marsa. Tukaj je, kako definiramo te meje koordinat:
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width
}
}
Razčlenimo to:
- Zgornji rob: To je točno tam, kjer se vaš objekt začne vertikalno (njegova y pozicija)
- Levi rob: Kjer se začne horizontalno (njegova x pozicija)
- Spodnji rob: Dodajte višino k y poziciji - zdaj veste, kje se konča!
- Desni rob: Dodajte širino k x poziciji - in imate celotno mejo
Algoritem za prekrivanje
Zaznavanje prekrivanja pravokotnikov uporablja logiko, podobno kot Hubbleov vesoljski teleskop določa, ali se nebesni objekti prekrivajo v njegovem vidnem polju. Algoritem preverja ločitev:
function intersectRect(r1, r2) {
return !(r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top);
}
Test ločitve deluje kot radarski sistemi:
- Ali je pravokotnik 2 popolnoma desno od pravokotnika 1?
- Ali je pravokotnik 2 popolnoma levo od pravokotnika 1?
- Ali je pravokotnik 2 popolnoma pod pravokotnikom 1?
- Ali je pravokotnik 2 popolnoma nad pravokotnikom 1?
Če noben od teh pogojev ni resničen, se pravokotniki morajo prekrivati. Ta pristop odraža, kako radarski operaterji določajo, ali sta dve letali na varni razdalji.
Upravljanje življenjskega cikla objektov
Ko laser zadene sovražnika, je treba oba objekta odstraniti iz igre. Vendar pa lahko brisanje objektov med zanko povzroči zrušitve - lekcija, ki so se je naučili na težek način v zgodnjih računalniških sistemih, kot je Apollo Guidance Computer. Namesto tega uporabljamo pristop "označi za brisanje", ki varno odstrani objekte med okvirji.
Tukaj je, kako nekaj označimo za odstranitev:
// Mark object for removal
enemy.dead = true;
Zakaj ta pristop deluje:
- Objekt označimo kot "mrtvega", vendar ga ne izbrišemo takoj
- To omogoča varno dokončanje trenutnega okvirja igre
- Brez zrušitev zaradi poskusov uporabe nečesa, kar je že odstranjeno!
Nato filtriramo označene objekte pred naslednjim ciklom upodabljanja:
gameObjects = gameObjects.filter(go => !go.dead);
Kaj to filtriranje naredi:
- Ustvari svež seznam samo z "živimi" objekti
- Odstrani vse, kar je označeno kot mrtvo
- Ohranja nemoteno delovanje igre
- Preprečuje kopičenje uničenih objektov v pomnilniku
Implementacija laserske mehanike
Laserski projektili v igrah delujejo po istem principu kot fotonski torpedi v Zvezdnih stezah - so ločeni objekti, ki potujejo v ravnih linijah, dokler ne zadenejo nečesa. Vsak pritisk na preslednico ustvari nov laserski objekt, ki se premika po zaslonu.
Da bi to delovalo, moramo uskladiti nekaj različnih delov:
Ključne komponente za implementacijo:
- Ustvarjanje laserskih objektov, ki se pojavijo na poziciji junaka
- Obravnava vnosa s tipkovnice za sprožitev ustvarjanja laserja
- Upravljanje gibanja laserja in življenjskega cikla
- Implementacija vizualne predstavitve laserskih projektilov
Implementacija nadzora hitrosti streljanja
Neomejene hitrosti streljanja bi preobremenile igralni motor in naredile igro prelahko. Pravi orožni sistemi se soočajo s podobnimi omejitvami - tudi fazerji USS Enterprise so potrebovali čas za ponovno polnjenje med streli.
Implementirali bomo sistem ohlajanja, ki preprečuje prekomerno streljanje, hkrati pa ohranja odzivne 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 deluje ohlajanje:
- Ko je ustvarjeno, je orožje "vroče" (še ne more streljati)
- Po preteku časovnega obdobja postane "hladno" (pripravljeno za streljanje)
- Pred streljanjem preverimo: "Ali je orožje hladno?"
- To preprečuje prekomerno streljanje, hkrati pa ohranja odzivnost kontrol
✅ Oglejte si lekcijo 1 v seriji vesoljske igre, da se spomnite o sistemih ohlajanja.
Gradnja sistema za zaznavanje trkov
Razširili boste obstoječo kodo svoje vesoljske igre, da ustvarite sistem za zaznavanje trkov. Tako kot avtomatizirani sistem za izogibanje trkom na Mednarodni vesoljski postaji bo vaša igra neprestano spremljala pozicije objektov in se odzivala na prekrivanja.
Začeli bomo s kodo iz prejšnje lekcije in dodali zaznavanje trkov s specifičnimi pravili, ki urejajo interakcije med objekti.
💡 Koristen nasvet: Sprite za laser je že vključen v vašo mapo z viri in referenciran v vaši kodi, pripravljen za implementacijo.
Pravila za zaznavanje trkov
Mehanika igre za dodajanje:
- Laser zadene sovražnika: Sovražni objekt je uničen, ko ga zadene laserski projektil
- Laser zadene mejo zaslona: Laser se odstrani, ko doseže zgornji rob zaslona
- Trk sovražnika in junaka: Oba objekta sta uničena, ko se prekrivata
- Sovražnik doseže dno: Pogoj za konec igre, ko sovražniki dosežejo spodnji rob zaslona
Priprava razvojnega okolja
Dobra novica - večino osnov smo že pripravili za vas! Vsi vaši viri igre in osnovna struktura vas čakajo v podmapi your-work, pripravljeni za dodajanje kul funkcij zaznavanja trkov.
Struktura projekta
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| index.html
-| app.js
-| package.json
Razumevanje strukture datotek:
- Vsebuje vse slike sprite, potrebne za objekte igre
- Vključuje glavni HTML dokument in datoteko JavaScript aplikacije
- Ponuja konfiguracijo paketa za lokalni razvojni strežnik
Zagon razvojnega strežnika
Pomaknite se do mape projekta in zaženite lokalni strežnik:
cd your-work
npm start
Ta zaporedje ukazov:
- Spremeni mapo na vašo delovno mapo projekta
- Zažene lokalni HTTP strežnik na
http://localhost:5000 - Postreže datoteke vaše igre za testiranje in razvoj
- Omogoča razvoj v živo z avtomatskim osveževanjem
Odprite brskalnik in se pomaknite na http://localhost:5000, da si ogledate trenutno stanje igre z junakom in sovražniki, upodobljenimi na zaslonu.
Korak za korakom implementacija
Tako kot sistematičen pristop, ki ga je NASA uporabila za programiranje vesoljskega plovila Voyager, bomo zaznavanje trkov implementirali metodično, gradili vsak komponent korak za korakom.
1. Dodajte meje trkov pravokotnikov
Najprej naučimo naše objekte v igri, kako opisati svoje meje. Dodajte to metodo v svoj razred GameObject:
rectFromGameObject() {
return {
top: this.y,
left: this.x,
bottom: this.y + this.height,
right: this.x + this.width,
};
}
Ta metoda omogoča:
- Ustvari objekt pravokotnika s točnimi mejami koordinat
- Izračuna spodnje in desne robove z uporabo pozicije plus dimenzij
- Vrne objekt, pripravljen za algoritme zaznavanja trkov
- Ponuja standardiziran vmesnik za vse objekte igre
2. Implementirajte zaznavanje prekrivanja
Zdaj ustvarimo našega detektiva trkov - funkcijo, ki lahko pove, kdaj se dva pravokotnika prekrivata:
function intersectRect(r1, r2) {
return !(
r2.left > r1.right ||
r2.right < r1.left ||
r2.top > r1.bottom ||
r2.bottom < r1.top
);
}
Ta algoritem deluje tako, da:
- Preverja štiri pogoje ločitve med pravokotniki
- Vrne
false, če je kateri koli pogoj ločitve resničen - Indicira trk, ko ni ločitve
- Uporablja logiko negacije za učinkovito testiranje prekrivanja
3. Implementirajte sistem streljanja laserjev
Tukaj postane zanimivo! Nastavimo sistem streljanja laserjev.
Konstantne sporočilne vrednosti
Najprej definirajmo nekaj vrst sporočil, da se lahko različni deli naše igre medsebojno sporazumevajo:
KEY_EVENT_SPACE: "KEY_EVENT_SPACE",
COLLISION_ENEMY_LASER: "COLLISION_ENEMY_LASER",
COLLISION_ENEMY_HERO: "COLLISION_ENEMY_HERO",
Te konstante omogočajo:
- Standardizirajo imena dogodkov po celotni aplikaciji
- Omogočajo dosledno komunikacijo med sistemi igre
- Preprečujejo tipkarske napake pri registraciji obdelovalcev dogodkov
Obdelava vnosa s tipkovnice
Dodajte zaznavanje pritiska na preslednico v vaš poslušalec dogodkov na tipkovnici:
} else if(evt.keyCode === 32) {
eventEmitter.emit(Messages.KEY_EVENT_SPACE);
}
Ta obdelovalec vnosa:
- Zazna pritiske na preslednico z uporabo keyCode 32
- Oddaja standardizirano sporočilo dogodka
- Omogoča ločeno logiko streljanja
Nastavitev poslušalca dogodkov
Registrirajte vedenje streljanja v funkciji initGame():
eventEmitter.on(Messages.KEY_EVENT_SPACE, () => {
if (hero.canFire()) {
hero.fire();
}
});
Ta poslušalec dogodkov:
- Reagira na dogodke pritiska na preslednico
- Preverja status ohlajanja streljanja
- Sproži ustvarjanje laserja, ko je to dovoljeno
Dodajte obdelavo trkov za interakcije med laserjem in sovražnikom:
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
});
Ta obdelovalec trkov:
- Prejme podatke o dogodku trka z obema objektoma
- Označi oba objekta za odstranitev
- Zagotovi pravilno čiščenje po trku
4. Ustvarite razred Laser
Implementirajte laserski projektil, ki se premika navzgor in upravlja svoj življenjski cikel:
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);
}
}
Ta implementacija razreda:
- Razširi GameObject za podedovanje osnovne funkcionalnosti
- Nastavi ustrezne dimenzije za sprite laserja
- Ustvari samodejno gibanje navzgor z uporabo
setInterval() - Obravnava samouničenje ob dosegi vrha zaslona
- Upravlja svoj čas animacije in čiščenje
5. Implementirajte sistem zaznavanja trkov
Ustvarite celovit sistem za zaznavanje trkov:
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);
}
Ta sistem zaznavanja trkov:
- Filtrira objekte igre po vrsti za učinkovito testiranje
- Preverja vsak laser proti vsakemu sovražniku za prekrivanja
- Oddaja dogodke trkov, ko so prekrivanja zaznana
- Čisti uničene objekte po obdelavi trkov
⚠️ Pomembno: Dodajte
updateGameObjects()v glavno zanko igre vwindow.onload, da omogočite zaznavanje trkov.
6. Dodajte sistem ohlajanja v razred Hero
Izboljšajte razred Hero z mehaniko streljanja in omejevanjem hitrosti:
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;
}
}
Razumevanje izboljšanega razreda Hero:
- Inicializira časovnik ohlajanja na nič (pripravljen za streljanje)
- Ustvari laserske objekte, postavljene nad ladjo junaka
- Nastavi obdobje ohlajanja za preprečevanje prekomernega streljanja
- Zmanjšuje časovnik ohlajanja z uporabo posodobitev na osnovi intervalov
- Omogoča preverjanje statusa streljanja prek metode
canFire()
Testiranje vaše implementacije
Vaša vesoljska igra zdaj vključuje popolno zaznavanje trkov in mehaniko bojevanja. 🚀 Preizkusite te nove funkcionalnosti:
- Premikajte se s puščičnimi tipkami, da preverite kontrole gibanja
- Streljajte laserje s preslednico - opazite, kako ohlajanje preprečuje prekomerno streljanje
- Opazujte trke, ko laserji zadenejo sovražnike, kar sproži odstranitev
- Preverite čiščenje, ko uničeni objekti izginejo iz igre
Uspešno ste implementirali sistem zaznavanja trkov z uporabo istih matematičnih principov, ki usmerjajo navigacijo vesoljskih plovil in robotike.
GitHub Copilot Agent izziv 🚀
Uporabite način Agent za dokončanje naslednjega izziva:
Opis: Izboljšajte sistem zaznavanja trkov z implementacijo dodatkov, ki se naključno pojavijo in junaku prinesejo začasne sposobnosti, ko jih pobere.
Navodilo: Ustvarite razred PowerUp, ki razširi GameObject, in implementirajte zaznavanje trkov med junakom in dodatki. Dodajte vsaj dve vrsti dodatkov: enega, ki poveča hitrost streljanja (zmanjša čas ohlajanja), in drugega, ki ustvari začasni ščit. Vključite logiko za pojavljanje dodatkov v naključnih intervalih in pozicijah.
🚀 Izziv
Dodajte eksplozijo! Oglejte si vire igre v repozitoriju Space Art in poskusite dodati eksplozijo, ko laser zadene vesoljca.
Kviz po predavanju
Pregled in samostojno učenje
Eksperimentirajte z intervali v svoji igri do sedaj. Kaj se zgodi, ko jih spremenite? Preberite več o časovnih dogodkih v JavaScriptu.
Naloga
Omejitev odgovornosti:
Ta dokument je bil preveden z uporabo storitve za prevajanje AI Co-op Translator. Čeprav si prizadevamo za natančnost, vas prosimo, da upoštevate, da lahko avtomatizirani prevodi vsebujejo napake ali netočnosti. Izvirni dokument v njegovem maternem jeziku naj se šteje za avtoritativni vir. Za ključne informacije priporočamo profesionalni človeški prevod. Ne odgovarjamo za morebitne nesporazume ali napačne razlage, ki izhajajo iz uporabe tega prevoda.