16 KiB
Bygg ett rymdspel del 2: Rita hjälten och monster på canvasen
Canvas API är en av webbens mest kraftfulla funktioner för att skapa dynamisk, interaktiv grafik direkt i din webbläsare. I denna lektion kommer vi att förvandla det tomma HTML-<canvas>-elementet till en spelvärld fylld med hjältar och monster. Tänk på canvasen som din digitala ritbräda där kod blir visuellt.
Vi bygger vidare på det du lärde dig i föregående lektion, och nu dyker vi in i de visuella aspekterna. Du kommer att lära dig hur man laddar och visar spelgrafik, positionerar element exakt och skapar den visuella grunden för ditt rymdspel. Detta bygger bron mellan statiska webbsidor och dynamiska, interaktiva upplevelser.
I slutet av denna lektion kommer du att ha en komplett spelscen med ditt hjälteskepp korrekt placerat och fiendformationer redo för strid. Du kommer att förstå hur moderna spel renderar grafik i webbläsare och få färdigheter att skapa dina egna interaktiva visuella upplevelser. Låt oss utforska canvasgrafik och ge liv åt ditt rymdspel!
Quiz före lektionen
Canvasen
Så vad är egentligen detta <canvas>-element? Det är HTML5:s lösning för att skapa dynamisk grafik och animationer i webbläsare. Till skillnad från vanliga bilder eller videor som är statiska, ger canvasen dig kontroll på pixelnivå över allt som visas på skärmen. Detta gör den perfekt för spel, datavisualiseringar och interaktiv konst. Tänk på det som en programmerbar rityta där JavaScript blir din pensel.
Som standard ser ett canvas-element ut som en tom, transparent rektangel på din sida. Men det är där potentialen ligger! Dess verkliga kraft framträder när du använder JavaScript för att rita former, ladda bilder, skapa animationer och få saker att reagera på användarinteraktioner. Det liknar hur de tidiga datagrafikpionjärerna på Bell Labs på 1960-talet var tvungna att programmera varje pixel för att skapa de första digitala animationerna.
✅ Läs mer om Canvas API på MDN.
Så här deklareras det vanligtvis, som en del av sidans body:
<canvas id="myCanvas" width="200" height="100"></canvas>
Vad denna kod gör:
- Sätter attributet
idså att du kan referera till detta specifika canvas-element i JavaScript - Definierar bredden i pixlar för att kontrollera canvasens horisontella storlek
- Fastställer höjden i pixlar för att bestämma canvasens vertikala dimensioner
Rita enkel geometri
Nu när du vet vad canvas-elementet är, låt oss utforska hur man faktiskt ritar på det! Canvasen använder ett koordinatsystem som kanske känns bekant från matematiklektionerna, men det finns en viktig twist som är specifik för datagrafik.
Canvasen använder kartesiska koordinater med en x-axel (horisontell) och en y-axel (vertikal) för att positionera allt du ritar. Men här är den viktiga skillnaden: till skillnad från koordinatsystemet från matematikklassen börjar origo (0,0) i det övre vänstra hörnet, med x-värden som ökar när du rör dig åt höger och y-värden som ökar när du rör dig nedåt. Detta tillvägagångssätt går tillbaka till tidiga datorskärmar där elektronstrålar skannade från topp till botten, vilket gjorde det övre vänstra hörnet till den naturliga startpunkten.
Bild från MDN
För att rita på canvas-elementet följer du samma trestegsprocess som utgör grunden för all canvasgrafik. När du har gjort detta några gånger blir det en vana:
- Hämta en referens till ditt canvas-element från DOM (precis som med andra HTML-element)
- Hämta 2D-renderingskontexten – detta ger alla ritmetoder
- Börja rita! Använd kontextens inbyggda metoder för att skapa din grafik
Så här ser det ut i kod:
// Step 1: Get the canvas element
const canvas = document.getElementById("myCanvas");
// Step 2: Get the 2D rendering context
const ctx = canvas.getContext("2d");
// Step 3: Set fill color and draw a rectangle
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, 200, 200); // x, y, width, height
Låt oss bryta ner detta steg för steg:
- Vi hämtar vårt canvas-element med dess ID och lagrar det i en variabel
- Vi hämtar 2D-renderingskontexten – detta är vår verktygslåda full av ritmetoder
- Vi berättar för canvasen att vi vill fylla saker med rött med egenskapen
fillStyle - Vi ritar en rektangel som börjar i det övre vänstra hörnet (0,0) som är 200 pixlar bred och hög
✅ Canvas API fokuserar mest på 2D-former, men du kan också rita 3D-element på en webbplats; för detta kan du använda WebGL API.
Du kan rita alla möjliga saker med Canvas API, som:
- Geometriska former, vi har redan visat hur man ritar en rektangel, men det finns mycket mer du kan rita.
- Text, du kan rita text med valfritt typsnitt och färg.
- Bilder, du kan rita en bild baserad på en bildfil som en .jpg eller .png till exempel.
✅ Prova! Du vet hur man ritar en rektangel, kan du rita en cirkel på en sida? Ta en titt på några intressanta canvasritningar på CodePen. Här är ett särskilt imponerande exempel.
Ladda och rita en bildfil
Att rita grundläggande former är användbart för att komma igång, men de flesta spel behöver riktiga bilder! Sprites, bakgrunder och texturer är det som ger spel deras visuella attraktionskraft. Att ladda och visa bilder på canvasen fungerar annorlunda än att rita geometriska former, men det är enkelt när du väl förstår processen.
Vi behöver skapa ett Image-objekt, ladda vår bildfil (detta sker asynkront, vilket betyder "i bakgrunden"), och sedan rita den på canvasen när den är redo. Detta tillvägagångssätt säkerställer att dina bilder visas korrekt utan att blockera din applikation medan de laddas.
Grundläggande bildladdning
const img = new Image();
img.src = 'path/to/my/image.png';
img.onload = () => {
// Image loaded and ready to be used
console.log('Image loaded successfully!');
};
Vad som händer i denna kod:
- Vi skapar ett helt nytt Image-objekt för att hålla vår sprite eller textur
- Vi berättar vilken bildfil som ska laddas genom att ange källvägen
- Vi lyssnar på load-händelsen så vi vet exakt när bilden är redo att användas
Ett bättre sätt att ladda bilder
Här är ett mer robust sätt att hantera bildladdning som professionella utvecklare ofta använder. Vi kommer att kapsla in bildladdningen i en Promise-baserad funktion – detta tillvägagångssätt, populärt när JavaScript Promises blev standard i ES6, gör din kod mer organiserad och hanterar fel smidigt:
function loadAsset(path) {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = path;
img.onload = () => {
resolve(img);
};
img.onerror = () => {
reject(new Error(`Failed to load image: ${path}`));
};
});
}
// Modern usage with async/await
async function initializeGame() {
try {
const heroImg = await loadAsset('hero.png');
const monsterImg = await loadAsset('monster.png');
// Images are now ready to use
} catch (error) {
console.error('Failed to load game assets:', error);
}
}
Vad vi har gjort här:
- Kapslat in all bildladdningslogik i en Promise så vi kan hantera det bättre
- Lagt till felhantering som faktiskt berättar när något går fel
- Använt modern async/await-syntax eftersom det är så mycket lättare att läsa
- Inkluderat try/catch-block för att smidigt hantera eventuella laddningsproblem
När dina bilder är laddade är det faktiskt ganska enkelt att rita dem på canvasen:
async function renderGameScreen() {
try {
// Load game assets
const heroImg = await loadAsset('hero.png');
const monsterImg = await loadAsset('monster.png');
// Get canvas and context
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// Draw images to specific positions
ctx.drawImage(heroImg, canvas.width / 2, canvas.height / 2);
ctx.drawImage(monsterImg, 0, 0);
} catch (error) {
console.error('Failed to render game screen:', error);
}
}
Låt oss gå igenom detta steg för steg:
- Vi laddar både våra hjälte- och monsterbilder i bakgrunden med await
- Vi hämtar vårt canvas-element och får den 2D-renderingskontext vi behöver
- Vi positionerar hjältebilden precis i mitten med lite snabb koordinatmatematik
- Vi placerar monsterbilden i det övre vänstra hörnet för att starta vår fiendformation
- Vi fångar eventuella fel som kan uppstå under laddning eller rendering
Nu är det dags att börja bygga ditt spel
Nu ska vi sätta ihop allt för att skapa den visuella grunden för ditt rymdspel. Du har en solid förståelse för canvasens grunder och tekniker för bildladdning, så denna praktiska sektion kommer att guida dig genom att bygga en komplett spelskärm med korrekt placerade sprites.
Vad du ska bygga
Du ska bygga en webbsida med ett canvas-element. Det ska rendera en svart skärm 1024*768. Vi har tillhandahållit två bilder:
Rekommenderade steg för att börja utvecklingen
Leta upp startfilerna som har skapats åt dig i undermappen your-work. Din projektstruktur bör innehålla:
your-work/
├── assets/
│ ├── enemyShip.png
│ └── player.png
├── index.html
├── app.js
└── package.json
Vad du arbetar med:
- Spelsprites finns i mappen
assets/så att allt hålls organiserat - Din huvudsakliga HTML-fil ställer in canvas-elementet och förbereder allt
- En JavaScript-fil där du skriver all din spelrenderingsmagi
- En package.json som sätter upp en utvecklingsserver så att du kan testa lokalt
Öppna denna mapp i Visual Studio Code för att börja utvecklingen. Du behöver en lokal utvecklingsmiljö med Visual Studio Code, NPM och Node.js installerat. Om du inte har npm installerat på din dator, så här installerar du det.
Starta din utvecklingsserver genom att navigera till mappen your-work:
cd your-work
npm start
Detta kommando gör några riktigt coola saker:
- Startar en lokal server på
http://localhost:5000så att du kan testa ditt spel - Serverar alla dina filer korrekt så att din webbläsare kan ladda dem
- Övervakar dina filer för ändringar så att du kan utveckla smidigt
- Ger dig en professionell utvecklingsmiljö för att testa allt
💡 Obs: Din webbläsare kommer att visa en tom sida initialt – det är förväntat! När du lägger till kod, uppdatera din webbläsare för att se dina ändringar. Denna iterativa utvecklingsmetod liknar hur NASA byggde Apollo-styrdatorn – genom att testa varje komponent innan den integrerades i det större systemet.
Lägg till kod
Lägg till den nödvändiga koden i your-work/app.js för att slutföra följande uppgifter:
-
Rita en canvas med svart bakgrund
💡 Så här gör du: Hitta TODO i
/app.jsoch lägg till bara två rader. Ställ inctx.fillStyletill svart, använd sedanctx.fillRect()som börjar vid (0,0) med dina canvasdimensioner. Enkelt! -
Ladda speltexturer
💡 Så här gör du: Använd
await loadAsset()för att ladda dina spelare- och fiendbilder. Spara dem i variabler så att du kan använda dem senare. Kom ihåg – de kommer inte att visas förrän du faktiskt ritar dem! -
Rita hjälteskeppet i mitten längst ner
💡 Så här gör du: Använd
ctx.drawImage()för att positionera din hjälte. För x-koordinaten, provacanvas.width / 2 - 45för att centrera det, och för y-koordinaten användcanvas.height - canvas.height / 4för att placera det i det nedre området. -
Rita en 5×5 formation av fiendeskepp
💡 Så här gör du: Hitta funktionen
createEnemiesoch sätt upp en nästlad loop. Du kommer att behöva göra lite matematik för avstånd och positionering, men oroa dig inte – jag visar dig exakt hur!
Först, fastställ konstanter för korrekt layout av fiendformationen:
const ENEMY_TOTAL = 5;
const ENEMY_SPACING = 98;
const FORMATION_WIDTH = ENEMY_TOTAL * ENEMY_SPACING;
const START_X = (canvas.width - FORMATION_WIDTH) / 2;
const STOP_X = START_X + FORMATION_WIDTH;
Låt oss bryta ner vad dessa konstanter gör:
- Vi sätter 5 fiender per rad och kolumn (ett snyggt 5×5 rutnät)
- Vi definierar hur mycket utrymme som ska finnas mellan fiender så att de inte ser trånga ut
- Vi beräknar hur bred vår hela formation kommer att vara
- Vi räknar ut var vi ska börja och sluta så att formationen ser centrerad ut
Sedan skapar vi nästlade loopar för att rita fiendformationen:
for (let x = START_X; x < STOP_X; x += ENEMY_SPACING) {
for (let y = 0; y < 50 * 5; y += 50) {
ctx.drawImage(enemyImg, x, y);
}
}
Vad denna nästlade loop gör:
- Den yttre loopen rör sig från vänster till höger över vår formation
- Den inre loopen går från topp till botten för att skapa snygga rader
- Vi ritar varje fiendesprite vid de exakta x,y-koordinater vi har beräknat
- Allt hålls jämnt fördelat så att det ser professionellt och organiserat ut
Resultat
Det färdiga resultatet bör se ut så här:
Lösning
Försök att lösa det själv först, men om du fastnar, ta en titt på en lösning
GitHub Copilot Agent-utmaning 🚀
Använd Agent-läget för att slutföra följande utmaning:
Beskrivning: Förbättra din rymdspelscanvas genom att lägga till visuella effekter och interaktiva element med hjälp av Canvas API-teknikerna du har lärt dig.
Uppmaning: Skapa en ny fil som heter enhanced-canvas.html med en canvas som visar animerade stjärnor i bakgrunden, en pulserande hälsobar för hjälteskeppet och fiendeskepp som långsamt rör sig nedåt. Inkludera JavaScript-kod som ritar blinkande stjärnor med slumpmässiga positioner och opacitet, implementerar en hälsobar som ändrar färg baserat på hälsotillstånd (grön > gul > röd), och animerar fiendeskepp att röra sig nedåt på skärmen i olika hastigheter.
Läs mer om agent-läge här.
🚀 Utmaning
Du har lärt dig att rita med det 2D-fokuserade Canvas API; ta en titt på WebGL API, och försök att rita ett 3D-objekt.
Quiz efter lektionen
Granskning & Självstudier
Lär dig mer om Canvas API genom att läsa om det.
Uppgift
Ansvarsfriskrivning:
Detta dokument har översatts med hjälp av AI-översättningstjänsten Co-op Translator. Även om vi strävar efter noggrannhet, bör det noteras att automatiserade översättningar kan innehålla fel eller felaktigheter. Det ursprungliga dokumentet på dess ursprungliga språk bör betraktas som den auktoritativa källan. För kritisk information rekommenderas professionell mänsklig översättning. Vi ansvarar inte för eventuella missförstånd eller feltolkningar som uppstår vid användning av denna översättning.



