You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/no/6-space-game/2-drawing-to-canvas
softchris a7d39944e9
🌐 Update translations via Co-op Translator
1 month ago
..
README.md 🌐 Update translations via Co-op Translator 1 month ago
assignment.md 🌐 Update translations via Co-op Translator 1 month ago

README.md

Bygg et romspill del 2: Tegn helten og monstre på lerretet

Canvas API er en av webutviklingens mest kraftfulle funksjoner for å lage dynamisk, interaktiv grafikk direkte i nettleseren din. I denne leksjonen skal vi forvandle det tomme HTML <canvas>-elementet til en spillverden fylt med helter og monstre. Tenk på lerretet som din digitale tegneflate der kode blir til visuelle elementer.

Vi bygger videre på det du lærte i forrige leksjon, og nå skal vi dykke inn i de visuelle aspektene. Du vil lære hvordan du laster inn og viser spillfigurer, posisjonerer elementer presist, og skaper det visuelle fundamentet for romspillet ditt. Dette bygger broen mellom statiske nettsider og dynamiske, interaktive opplevelser.

Ved slutten av denne leksjonen vil du ha en komplett spillscene med helteskipet ditt plassert riktig og fiendeformasjoner klare for kamp. Du vil forstå hvordan moderne spill gjengir grafikk i nettlesere og få ferdigheter til å lage dine egne interaktive visuelle opplevelser. La oss utforske canvas-grafikk og bringe romspillet ditt til live!

Quiz før leksjonen

Quiz før leksjonen

Canvas

Så hva er egentlig dette <canvas>-elementet? Det er HTML5s løsning for å lage dynamisk grafikk og animasjoner i nettlesere. I motsetning til vanlige bilder eller videoer som er statiske, gir canvas deg pikselnivå kontroll over alt som vises på skjermen. Dette gjør det perfekt for spill, datavisualiseringer og interaktiv kunst. Tenk på det som en programmerbar tegneflate der JavaScript blir penselen din.

Som standard ser et canvas-element ut som et tomt, transparent rektangel på siden din. Men det er her potensialet ligger! Den virkelige kraften kommer frem når du bruker JavaScript til å tegne former, laste inn bilder, lage animasjoner og få ting til å reagere på brukerinteraksjoner. Det ligner på hvordan de tidlige pionerene innen datagrafikk på Bell Labs på 1960-tallet måtte programmere hver piksel for å lage de første digitale animasjonene.

Les mer om Canvas API på MDN.

Slik blir det vanligvis deklarert som en del av sidens body:

<canvas id="myCanvas" width="200" height="100"></canvas>

Dette gjør koden:

  • Setter id-attributtet slik at du kan referere til dette spesifikke canvas-elementet i JavaScript
  • Definerer bredden i piksler for å kontrollere canvasets horisontale størrelse
  • Etablerer høyden i piksler for å bestemme canvasets vertikale dimensjoner

Tegne enkel geometri

Nå som du vet hva canvas-elementet er, la oss utforske hvordan man faktisk tegner på det! Canvas bruker et koordinatsystem som kanskje føles kjent fra matematikkundervisningen, men det er en viktig vri som er spesifikk for datagrafikk.

Canvas bruker kartesiske koordinater med en x-akse (horisontal) og en y-akse (vertikal) for å posisjonere alt du tegner. Men her er den viktige forskjellen: i motsetning til koordinatsystemet fra matematikkundervisningen, starter origo (0,0) i øvre venstre hjørne, med x-verdier som øker når du beveger deg mot høyre og y-verdier som øker når du beveger deg nedover. Denne tilnærmingen stammer fra tidlige dataskjermer der elektronstråler skannet fra topp til bunn, og gjorde øvre venstre hjørne til det naturlige startpunktet.

canvas sitt rutenett

Bilde fra MDN

For å tegne på canvas-elementet følger du den samme tretrinnsprosessen som danner grunnlaget for all canvas-grafikk. Når du har gjort dette noen ganger, blir det en vane:

  1. Få en referanse til canvas-elementet ditt fra DOM (akkurat som med andre HTML-elementer)
  2. Få 2D-renderingskonteksten dette gir deg alle tegneverktøyene
  3. Begynn å tegne! Bruk kontekstens innebygde metoder for å lage grafikken din

Slik ser det ut i kode:

// 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

La oss bryte dette ned steg for steg:

  • Vi henter canvas-elementet vårt ved hjelp av ID-en og lagrer det i en variabel
  • Vi får 2D-renderingskonteksten dette er verktøykassen vår full av tegnemetoder
  • Vi forteller canvas at vi vil fylle ting med rødt ved hjelp av fillStyle-egenskapen
  • Vi tegner et rektangel som starter i øvre venstre hjørne (0,0) og er 200 piksler bredt og høyt

Canvas API fokuserer mest på 2D-former, men du kan også tegne 3D-elementer på en nettside; for dette kan du bruke WebGL API.

Du kan tegne mange forskjellige ting med Canvas API, som:

  • Geometriske former, vi har allerede vist hvordan man tegner et rektangel, men det er mye mer du kan tegne.
  • Tekst, du kan tegne tekst med hvilken som helst font og farge du ønsker.
  • Bilder, du kan tegne et bilde basert på en bildefil som en .jpg eller .png for eksempel.

Prøv det! Du vet hvordan du tegner et rektangel, kan du tegne en sirkel på en side? Ta en titt på noen interessante Canvas-tegninger på CodePen. Her er et særlig imponerende eksempel.

Last inn og tegn et bilde

Å tegne grunnleggende former er nyttig for å komme i gang, men de fleste spill trenger faktiske bilder! Figurer, bakgrunner og teksturer er det som gir spillene visuell appell. Å laste inn og vise bilder på canvas fungerer annerledes enn å tegne geometriske former, men det er enkelt når du forstår prosessen.

Vi må lage et Image-objekt, laste inn bildefilen vår (dette skjer asynkront, altså "i bakgrunnen"), og deretter tegne det på canvas når det er klart. Denne tilnærmingen sikrer at bildene dine vises riktig uten å blokkere applikasjonen mens de lastes inn.

Grunnleggende bildeinnlasting

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!');
};

Dette skjer i koden:

  • Vi lager et helt nytt Image-objekt for å holde figuren eller teksturen vår
  • Vi forteller det hvilken bildefil som skal lastes inn ved å sette kildebanen
  • Vi lytter etter load-hendelsen slik at vi vet nøyaktig når bildet er klart til bruk

En bedre måte å laste inn bilder på

Her er en mer robust måte å håndtere bildeinnlasting på som profesjonelle utviklere ofte bruker. Vi pakker bildeinnlastingen inn i en funksjon basert på Promise denne tilnærmingen, som ble populær da JavaScript Promises ble standard i ES6, gjør koden din mer organisert og håndterer feil elegant:

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);
  }
}

Hva vi har gjort her:

  • Pakket inn all bildeinnlastingslogikken i en Promise for bedre håndtering
  • Lagt til feilhåndtering som faktisk forteller oss når noe går galt
  • Brukt moderne async/await-syntaks fordi det er så mye enklere å lese
  • Inkludert try/catch-blokker for å håndtere eventuelle innlastingsproblemer på en smidig måte

Når bildene dine er lastet inn, er det faktisk ganske enkelt å tegne dem på canvas:

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);
  }
}

La oss gå gjennom dette steg for steg:

  • Vi laster inn både helten og monsterbildene i bakgrunnen ved hjelp av await
  • Vi henter canvas-elementet vårt og får den 2D-renderingskonteksten vi trenger
  • Vi posisjonerer heltebildet midt i sentrum ved hjelp av litt rask koordinatmatematikk
  • Vi plasserer monsterbildet i øvre venstre hjørne for å starte fiendeformasjonen
  • Vi fanger opp eventuelle feil som kan oppstå under innlasting eller rendering

Nå er det tid for å begynne å bygge spillet ditt

Nå skal vi sette alt sammen for å lage det visuelle fundamentet for romspillet ditt. Du har en solid forståelse av canvas-grunnleggende og bildeinnlastingsteknikker, så denne praktiske delen vil veilede deg gjennom å bygge en komplett spillskjerm med riktig plasserte figurer.

Hva du skal bygge

Du skal lage en nettside med et Canvas-element. Det skal vise en svart skjerm 1024*768. Vi har gitt deg to bilder:

  • Helteskip

    Helteskip

  • 5*5 monstre

    Monsterskip

Anbefalte trinn for å starte utviklingen

Finn startfilene som er laget for deg i your-work-undermappen. Prosjektstrukturen din bør inneholde:

your-work/
├── assets/
│   ├── enemyShip.png
│   └── player.png
├── index.html
├── app.js
└── package.json

Dette jobber du med:

  • Spillfigurer ligger i assets/-mappen slik at alt holder seg organisert
  • Din hoved-HTML-fil setter opp canvas-elementet og gjør alt klart
  • En JavaScript-fil der du skal skrive all magien for spillrendering
  • En package.json som setter opp en utviklingsserver slik at du kan teste lokalt

Åpne denne mappen i Visual Studio Code for å begynne utviklingen. Du trenger et lokalt utviklingsmiljø med Visual Studio Code, NPM og Node.js installert. Hvis du ikke har npm satt opp på datamaskinen din, slik installerer du det.

Start utviklingsserveren din ved å navigere til your-work-mappen:

cd your-work
npm start

Denne kommandoen gjør noen ganske kule ting:

  • Starter opp en lokal server på http://localhost:5000 slik at du kan teste spillet ditt
  • Serverer alle filene dine riktig slik at nettleseren din kan laste dem inn korrekt
  • Overvåker filene dine for endringer slik at du kan utvikle jevnt
  • Gir deg et profesjonelt utviklingsmiljø for å teste alt

💡 Merk: Nettleseren din vil vise en blank side i starten det er forventet! Når du legger til kode, oppdater nettleseren for å se endringene dine. Denne iterative utviklingstilnærmingen ligner på hvordan NASA bygde Apollo-styringsdatamaskinen testet hver komponent før den ble integrert i det større systemet.

Legg til kode

Legg til nødvendig kode i your-work/app.js for å fullføre følgende oppgaver:

  1. Tegn et canvas med svart bakgrunn

    💡 Slik gjør du det: Finn TODO i /app.js og legg til bare to linjer. Sett ctx.fillStyle til svart, og bruk deretter ctx.fillRect() som starter på (0,0) med canvas-dimensjonene dine. Enkelt!

  2. Last inn spillteksturer

    💡 Slik gjør du det: Bruk await loadAsset() for å laste inn spiller- og fiendebildene dine. Lagre dem i variabler slik at du kan bruke dem senere. Husk de vil ikke vises før du faktisk tegner dem!

  3. Tegn helteskipet i midten nederst

    💡 Slik gjør du det: Bruk ctx.drawImage() for å posisjonere helten din. For x-koordinaten, prøv canvas.width / 2 - 45 for å sentrere det, og for y-koordinaten bruk canvas.height - canvas.height / 4 for å plassere det nederst.

  4. Tegn en 5×5 formasjon av fiendeskip

    💡 Slik gjør du det: Finn createEnemies-funksjonen og sett opp en nestet løkke. Du må gjøre litt matematikk for avstand og posisjonering, men ikke bekymre deg jeg viser deg nøyaktig hvordan!

Først, etabler konstanter for riktig oppsett av fiendeformasjonen:

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;

La oss bryte ned hva disse konstantene gjør:

  • Vi setter 5 fiender per rad og kolonne (et fint 5×5 rutenett)
  • Vi definerer hvor mye plass vi skal ha mellom fiendene slik at de ikke ser trange ut
  • Vi beregner hvor bred hele formasjonen vår vil være
  • Vi finner ut hvor vi skal starte og stoppe slik at formasjonen ser sentrert ut

Deretter, lag nestede løkker for å tegne fiendeformasjonen:

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);
  }
}

Dette gjør den nestede løkken:

  • Den ytre løkken beveger seg fra venstre til høyre over formasjonen vår
  • Den indre løkken går fra topp til bunn for å lage pene rader
  • Vi tegner hver fiendesprite på de nøyaktige x,y-koordinatene vi har beregnet
  • Alt holder seg jevnt fordelt slik at det ser profesjonelt og organisert ut

Resultat

Det ferdige resultatet skal se slik ut:

Svart skjerm med en helt og 5×5 monstre

Løsning

Prøv å løse det selv først, men hvis du står fast, kan du ta en titt på en løsning.


GitHub Copilot Agent-utfordring 🚀

Bruk Agent-modus for å fullføre følgende utfordring:

Beskrivelse: Forbedre romspillet ditt ved å legge til visuelle effekter og interaktive elementer ved hjelp av Canvas API-teknikkene du har lært.

Oppgave: Lag en ny fil kalt enhanced-canvas.html med et canvas som viser animerte stjerner i bakgrunnen, en pulserende helsebjelke for helteskipet, og fiendeskip som sakte beveger seg nedover. Inkluder JavaScript-kode som tegner blinkende stjerner ved hjelp av tilfeldige posisjoner og opasitet, implementerer en helsebjelke som endrer farge basert på helsenivå (grønn > gul > rød), og animerer fiendeskipene til å bevege seg nedover skjermen med forskjellige hastigheter.

Lær mer om agent-modus her.

🚀 Utfordring

Du har lært om tegning med den 2D-fokuserte Canvas API; ta en titt på WebGL API, og prøv å tegne et 3D-objekt.

Quiz etter leksjonen

Quiz etter leksjonen

Gjennomgang og selvstudium

Lær mer om Canvas API ved å lese om det.

Oppgave

Utforsk Canvas API


Ansvarsfraskrivelse:
Dette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten Co-op Translator. Selv om vi streber etter nøyaktighet, vær oppmerksom på at automatiserte oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør anses som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.