|
|
1 month ago | |
|---|---|---|
| .. | ||
| solution | 3 months ago | |
| your-work | 3 months ago | |
| README.md | 1 month ago | |
| assignment.md | 1 month ago | |
README.md
Bouw een Ruimtegame Deel 6: Einde en Herstart
Elke geweldige game heeft duidelijke eindvoorwaarden en een soepel herstartmechanisme nodig. Je hebt al een indrukwekkende ruimtegame gebouwd met beweging, gevechten en scores - nu is het tijd om de laatste stukjes toe te voegen die het compleet maken.
Je game draait momenteel eindeloos, net zoals de Voyager-sondes die NASA in 1977 lanceerde - nog steeds reizend door de ruimte decennia later. Hoewel dat prima is voor ruimteverkenning, hebben games gedefinieerde eindpunten nodig om een bevredigende ervaring te creëren.
Vandaag gaan we win/verlies-voorwaarden en een herstartsysteem implementeren. Aan het einde van deze les heb je een gepolijste game die spelers kunnen voltooien en opnieuw kunnen spelen, net zoals de klassieke arcadegames die het medium hebben gedefinieerd.
Quiz voor de les
Begrijpen van Eindvoorwaarden in Games
Wanneer moet je game eindigen? Deze fundamentele vraag heeft het ontwerp van games gevormd sinds de vroege arcadeperiode. Pac-Man eindigt wanneer je wordt gepakt door geesten of alle stippen hebt verzameld, terwijl Space Invaders eindigt wanneer aliens de bodem bereiken of je ze allemaal vernietigt.
Als maker van de game bepaal jij de overwinning- en verliesvoorwaarden. Voor onze ruimtegame zijn hier bewezen benaderingen die zorgen voor boeiende gameplay:
NVijandelijke schepen zijn vernietigd: Het is vrij gebruikelijk dat je een level moet voltooien door een bepaald aantal vijandelijke schepen te vernietigen.- Je schip is vernietigd: Er zijn zeker games waarin je verliest als je schip wordt vernietigd. Een andere veelvoorkomende aanpak is het concept van levens. Elke keer dat je schip wordt vernietigd, verlies je een leven. Zodra alle levens verloren zijn, verlies je de game.
- Je hebt
Npunten verzameld: Een andere veelvoorkomende eindvoorwaarde is het verzamelen van punten. Hoe je punten verzamelt, is aan jou, maar het is vrij gebruikelijk om punten toe te kennen aan verschillende activiteiten, zoals het vernietigen van een vijandelijk schip of het verzamelen van items die worden gedropt wanneer ze worden vernietigd. - Voltooi een level: Dit kan verschillende voorwaarden omvatten, zoals
Xvijandelijke schepen vernietigd,Ypunten verzameld of misschien een specifiek item dat is verzameld.
Implementeren van Herstartfunctionaliteit
Goede games moedigen herhaalbaarheid aan door middel van soepele herstartmechanismen. Wanneer spelers een game voltooien (of verliezen), willen ze vaak meteen opnieuw proberen - of het nu is om hun score te verbeteren of hun prestaties te verbeteren.
Tetris is hier een perfect voorbeeld van: wanneer je blokken de bovenkant bereiken, kun je direct een nieuw spel starten zonder door complexe menu's te navigeren. We bouwen een vergelijkbaar herstartsysteem dat de game-status schoon reset en spelers snel weer in actie brengt.
✅ Reflectie: Denk aan de games die je hebt gespeeld. Onder welke voorwaarden eindigen ze, en hoe word je aangespoord om opnieuw te starten? Wat maakt een herstartervaring soepel versus frustrerend?
Wat je gaat bouwen
Je implementeert de laatste functies die je project transformeren tot een complete game-ervaring. Deze elementen onderscheiden gepolijste games van eenvoudige prototypes.
Dit voegen we vandaag toe:
- Overwinningsvoorwaarde: Vernietig alle vijanden en krijg een gepaste viering (je hebt het verdiend!)
- Verliesvoorwaarde: Raak je levens kwijt en zie een verlies-scherm
- Herstartmechanisme: Druk op Enter om meteen opnieuw te beginnen - want één spel is nooit genoeg
- Statusbeheer: Elke keer een schone lei - geen overgebleven vijanden of rare glitches van het vorige spel
Aan de slag
Laten we je ontwikkelomgeving voorbereiden. Je zou alle bestanden van je ruimtegame uit de vorige lessen klaar moeten hebben.
Je project zou er ongeveer zo uit moeten zien:
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| life.png
-| index.html
-| app.js
-| package.json
Start je ontwikkelserver:
cd your-work
npm start
Deze opdracht:
- Draait een lokale server op
http://localhost:5000 - Serveert je bestanden correct
- Vernieuwt automatisch wanneer je wijzigingen aanbrengt
Open http://localhost:5000 in je browser en controleer of je game draait. Je zou moeten kunnen bewegen, schieten en interactie hebben met vijanden. Zodra dit is bevestigd, kunnen we doorgaan met de implementatie.
💡 Pro Tip: Om waarschuwingen in Visual Studio Code te vermijden, declareer
gameLoopIdbovenaan je bestand alslet gameLoopId;in plaats van het te declareren binnen dewindow.onloadfunctie. Dit volgt moderne JavaScript variabele declaratie best practices.
Implementatiestappen
Stap 1: Maak Functies voor het Bijhouden van Eindvoorwaarden
We hebben functies nodig om te monitoren wanneer de game moet eindigen. Net zoals sensoren op het internationale ruimtestation die constant kritieke systemen monitoren, zullen deze functies continu de status van de game controleren.
function isHeroDead() {
return hero.life <= 0;
}
function isEnemiesDead() {
const enemies = gameObjects.filter((go) => go.type === "Enemy" && !go.dead);
return enemies.length === 0;
}
Wat er onder de motorkap gebeurt:
- Controleert of onze held geen levens meer heeft (au!)
- Telt hoeveel vijanden nog leven en actief zijn
- Geeft
trueterug wanneer het slagveld vrij is van vijanden - Gebruikt eenvoudige true/false logica om het overzichtelijk te houden
- Filtert door alle game-objecten om de overlevenden te vinden
Stap 2: Update Eventhandlers voor Eindvoorwaarden
Nu verbinden we deze conditiechecks met het event-systeem van de game. Elke keer dat er een botsing plaatsvindt, evalueert de game of dit een eindvoorwaarde activeert. Dit zorgt voor directe feedback bij kritieke game-events.
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);
});
Wat hier gebeurt:
- Laser raakt vijand: Beide verdwijnen, je krijgt punten, en we controleren of je hebt gewonnen
- Vijand raakt jou: Je verliest een leven, en we controleren of je nog in leven bent
- Slimme volgorde: We controleren eerst op verlies (niemand wil tegelijkertijd winnen en verliezen!)
- Directe reacties: Zodra er iets belangrijks gebeurt, weet de game het
Stap 3: Voeg Nieuwe Berichtconstanten Toe
Je moet nieuwe berichttypes toevoegen aan je Messages constant object. Deze constanten helpen consistentie te behouden en voorkomen typefouten in je event-systeem.
GAME_END_LOSS: "GAME_END_LOSS",
GAME_END_WIN: "GAME_END_WIN",
In het bovenstaande hebben we:
- Toegevoegd constanten voor game-einde events om consistentie te behouden
- Gebruikt beschrijvende namen die duidelijk het doel van het event aangeven
- Gevolgd de bestaande naamgevingsconventie voor berichttypes
Stap 4: Implementeer Herstartbediening
Nu voeg je toetsenbordbediening toe waarmee spelers de game kunnen herstarten. De Enter-toets is een logische keuze, omdat deze vaak wordt geassocieerd met het bevestigen van acties en het starten van nieuwe games.
Voeg detectie van de Enter-toets toe aan je bestaande keydown eventlistener:
else if(evt.key === "Enter") {
eventEmitter.emit(Messages.KEY_EVENT_ENTER);
}
Voeg de nieuwe berichtconstante toe:
KEY_EVENT_ENTER: "KEY_EVENT_ENTER",
Wat je moet weten:
- Breidt je bestaande toetsenbord event-handlingsysteem uit
- Gebruikt de Enter-toets als herstarttrigger voor intuïtieve gebruikerservaring
- Stuurt een aangepast event uit dat andere delen van je game kunnen beluisteren
- Behoudt hetzelfde patroon als je andere toetsenbordbedieningen
Stap 5: Maak het Berichtweergavesysteem
Je game moet resultaten duidelijk communiceren naar spelers. We maken een berichtensysteem dat overwinnings- en verliesstatussen weergeeft met kleurgecodeerde tekst, vergelijkbaar met de terminalinterfaces van vroege computersystemen waar groen succes aangaf en rood fouten signaleerde.
Maak de functie 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);
}
Stap voor stap, wat er gebeurt:
- Stelt de lettergrootte en -familie in voor duidelijke, leesbare tekst
- Past een kleurparameter toe met "rood" als standaard voor waarschuwingen
- Centreert de tekst horizontaal en verticaal op het canvas
- Gebruikt moderne JavaScript standaardparameters voor flexibele kleurkeuzes
- Benut de canvas 2D-context voor directe tekstweergave
Maak de functie 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)
}
Wat deze functie doet:
- Bevriest alles - geen bewegende schepen of lasers meer
- Neemt een korte pauze (200ms) om het laatste frame te laten tekenen
- Maakt het scherm schoon en kleurt het zwart voor een dramatisch effect
- Toont verschillende berichten voor winnaars en verliezers
- Kleurcodeert het nieuws - groen voor goed, rood voor... nou ja, niet zo goed
- Vertelt spelers precies hoe ze weer kunnen beginnen
Stap 6: Implementeer Game Reset Functionaliteit
Het resetsysteem moet de huidige game-status volledig opruimen en een nieuwe gamesessie initialiseren. Dit zorgt ervoor dat spelers een frisse start krijgen zonder overgebleven gegevens van het vorige spel.
Maak de functie 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);
}
}
Laten we elk onderdeel begrijpen:
- Controleert of er momenteel een game-loop actief is voordat er wordt gereset
- Maakt de bestaande game-loop leeg om alle huidige game-activiteit te stoppen
- Verwijdert alle eventlisteners om geheugenlekken te voorkomen
- Initialiseert de game-status opnieuw met nieuwe objecten en variabelen
- Start een nieuwe game-loop met alle essentiële gamefuncties
- Behoudt hetzelfde 100ms-interval voor consistente gameprestaties
Voeg de Enter-toets eventhandler toe aan je initGame() functie:
eventEmitter.on(Messages.KEY_EVENT_ENTER, () => {
resetGame();
});
Voeg de clear() methode toe aan je EventEmitter klasse:
clear() {
this.listeners = {};
}
Belangrijke punten om te onthouden:
- Verbindt het indrukken van de Enter-toets met de reset game-functionaliteit
- Registreert deze eventlistener tijdens de game-initialisatie
- Biedt een schone manier om alle eventlisteners te verwijderen bij het resetten
- Voorkomt geheugenlekken door eventhandlers tussen games te wissen
- Reset het listeners-object naar een lege status voor nieuwe initialisatie
Gefeliciteerd! 🎉
👽 💥 🚀 Je hebt met succes een complete game vanaf de basis opgebouwd. Net als de programmeurs die de eerste videogames in de jaren '70 creëerden, heb je regels code omgezet in een interactieve ervaring met goede game-mechanica en gebruikersfeedback. 🚀 💥 👽
Je hebt bereikt:
- Geïmplementeerd volledige win- en verliesvoorwaarden met gebruikersfeedback
- Gecreëerd een naadloos herstartsysteem voor continue gameplay
- Ontworpen duidelijke visuele communicatie voor gamestatussen
- Beheerd complexe game-statusovergangen en opruiming
- Samengesteld alle componenten tot een samenhangende, speelbare game
GitHub Copilot Agent Challenge 🚀
Gebruik de Agent-modus om de volgende uitdaging te voltooien:
Beschrijving: Verbeter de ruimtegame door een levelprogressiesysteem te implementeren met toenemende moeilijkheidsgraad en bonusfuncties.
Prompt: Maak een multi-level ruimtegame systeem waarbij elk level meer vijandelijke schepen heeft met verhoogde snelheid en gezondheid. Voeg een scorevermenigvuldiger toe die toeneemt met elk level, en implementeer power-ups (zoals snel schieten of een schild) die willekeurig verschijnen wanneer vijanden worden vernietigd. Voeg een levelvoltooiingsbonus toe en toon het huidige level op het scherm naast de bestaande score en levens.
Meer informatie over agent mode vind je hier.
🚀 Optionele Uitdaging voor Verbetering
Voeg Audio toe aan je Game: Verhoog de spelervaring door geluidseffecten toe te voegen! Overweeg om audio toe te voegen voor:
- Laser schoten wanneer de speler vuurt
- Vijandelijke vernietiging wanneer schepen worden geraakt
- Schade aan de held wanneer de speler geraakt wordt
- Overwinningsmuziek wanneer de game wordt gewonnen
- Verliesgeluid wanneer de game verloren is
Voorbeeld van audio-implementatie:
// 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();
}
Wat je moet weten:
- Maakt Audio-objecten voor verschillende geluidseffecten
- Reset de
currentTimeom snelle geluidseffecten mogelijk te maken - Behandelt autoplay-beleid van browsers door geluiden te activeren via gebruikersinteracties
- Beheert audiovolume en timing voor een betere game-ervaring
💡 Leermiddel: Verken deze audio sandbox om meer te leren over het implementeren van audio in JavaScript-games.
Quiz na de les
Review & Zelfstudie
Je opdracht is om een nieuw voorbeeldspel te maken, dus verken enkele interessante games om te zien wat voor soort game je zou kunnen bouwen.
Opdracht
Disclaimer:
Dit document is vertaald met behulp van de AI-vertalingsservice Co-op Translator. Hoewel we streven naar nauwkeurigheid, dient u zich ervan bewust te zijn dat geautomatiseerde vertalingen fouten of onnauwkeurigheden kunnen bevatten. Het originele document in de oorspronkelijke taal moet worden beschouwd als de gezaghebbende bron. Voor kritieke informatie wordt professionele menselijke vertaling aanbevolen. Wij zijn niet aansprakelijk voor eventuele misverstanden of verkeerde interpretaties die voortvloeien uit het gebruik van deze vertaling.