Dags att prova på något riktigt. Vi ska bygga ett matchningsspel där spelaren kan dra bilder på djur till deras namn.
Det mesta för spelet finns redan i arbetsmaterialet för labben, uppgiften är att implementera drag and drop logiken som skall få spelet att fungera.
Logiken kommer att fungera på följande sätt:
- När spelet startar slumpas tre olika djur fram och visas som bilder.
- Användaren kan dra bilderna till rätt isländska namn.
- Om användaren släpper bilden på rätt namn, markeras det som rätt och bilden kan inte dras mer.
- För att avgöra rätt eller fel, jämförs djurets engelska namn (lagrat i
data-idpå bilden) med namnets id (lagrat idata-idpå namnrutan).
0 - Förberedelser
Skapa en ny mapp lab-6d och ladda ner startmaterialet (lab6d.zip). Packa upp filerna i mappen. Du ska ha fått de vanliga filerna samt två nya mappar img och audio med bilder och ljudfiler.
- Öppna mappen i VS Code, och öppna
index.htmlmed live-server. - Kolla igenom html- och CSS-filerna för att förstå hur sidan är uppbyggd och vilka css-klasser som finns för visuell feedback.
1 - Initiera spelet
Spelet går ut på att användaren får tre olika slumpade djur som hen skall dra till deras isländska namn.
Följande saker behöver hända när spelet startar:
- Slumpa fram 3 olika djur och uppdatera användargränssnittet (de tre bildelementen) med dessa djur. Vi behöver sätta
src(för att visa rätt bild) ochdata-id(för att i spel-logiken veta vilket djur det är). - Göra bilderna dragbara. (dvs
dragstartochdragendlyssnare). - Göra namnrutorna till dropzoner. (dvs koppla
dragover,drop,dragenterochdragleavelyssnare).
Slumpa och uppdatera bilderna
Vi har en array med engelska namn: ["cat", "cow", "dog", "horse", "pig", "sheep"]. Vi behöver välja 3 unika.
Tips Om du har svårt att tänka ut en lösning, börja med att göra på ett enklare sätt, t.ex. genom att bara ta de tre första namnen i arrayen eller slumpa tre namn utan att bry dig om att de kan bli dubbletter..
Därefter hämtar vi bildelementen, och för varje bild sätter vi src till rätt bildfil och data-id till djurets namn.
Förslag på lösning
/* solution.js */
const englishNames = ["cat", "cow", "dog", "horse", "pig", "sheep"];
function initGame() {
const selectedNames = [];
// 1. Slumpa 3 unika namn
while (selectedNames.length < 3) {
const randomIndex = Math.floor(Math.random() * englishNames.length);
const randomName = englishNames[randomIndex];
if (!selectedNames.includes(randomName)) {
selectedNames.push(randomName);
}
}
// 2. Uppdatera bilderna
const images = document.querySelectorAll("#draggables-container img");
for (let index = 0; index < selectedNames.length; index++) {
const img = images[index];
img.src = `img/${selectedNames[index]}.png`;
img.dataset.id = selectedNames[index];
// TODO: Koppla dragstart och dragend
}
// TODO: Koppla dropzoner (se nästa del)
}
initGame();
Spelet bör nu visa tre slumpade djurbilder när sidan laddas:

Gör bilderna dragbara
Lägg till event listeners för dragstart och dragend på varje bild i loopen där du uppdaterar bilderna.
Förslag på lösning
Lägg till detta i slutet av loopen som uppdaterar bilderna:
img.addEventListener("dragstart", onDragStart);
img.addEventListener("dragend", onDragEnd);
Lägg till funktionerna onDragStart och onDragEnd och en variabel för att hålla reda på elementet som dras utanför initGame:
let draggedElement = null; // Hålla reda på vad vi drar
function onDragStart(e) {
draggedElement = e.target;
draggedElement.classList.add("dragging");
}
function onDragEnd(e) {
draggedElement.classList.remove("dragging");
draggedElement = null;
}
Gör namnrutorna till dropzoner
Dropzonerna (namnen) finns redan i HTML:en och har klassen .name-box.
Vi behöver loopa igenom dem och lägga till händelsehanterare för drag and drop. Gör detta i slutet av initGame.
- I
dragenterochdragleavevill vi ge visuell feedback genom att lägga till/ta bort klassendrag-over. - I
dragoverbehöver vi anropae.preventDefault()för att tillåta släpp.
Förslag på lösning
I slutet av initGame:
const dropzones = document.querySelectorAll(".name-box");
for (const zone of dropzones) {
zone.addEventListener("dragover", onDragOver);
zone.addEventListener("drop", onDrop);
zone.addEventListener("dragenter", onDragEnter);
zone.addEventListener("dragleave", onDragLeave);
}
Utanför initGame, lägg till funktionerna:
function onDragOver(e) {
// TODO: tillåt endast släpp om namnet inte redan är använt
e.preventDefault();
}
function onDragEnter(e) {
// TODO: ge endast visuell feedback om namnet inte redan är använt
e.target.classList.add("drag-over");
}
function onDragLeave(e) {
e.target.classList.remove("drag-over");
}
function onDrop(e) {
// TODO: implementera drop-logik
}
3 - Drop-Logik
Nu till själva matchningen i onDrop.
Följande saker behöver hända när ett djur släpps på en zon:
- Vi behöver jämföra det dragna djurets id med zonens id. Om de är lika är det rätt matchning.
- djurets id finns som data-attribut på elementet som dras (
draggedElement.dataset.id) - zonens id finns som data-attribut på namn-rutan (
e.target.dataset.id) - Vid rätt matchning:
- Lägg till klassen
correctpå zonen. - Inaktivera det dragna djuret (sätt
draggable = falseoch lägg till klassenmatched).
- Lägg till klassen
- Vid fel matchning:
- Lägg till klassen
incorrectpå zonen, och ta bort den efter 500ms (användsetTimeout).
- Lägg till klassen
- djurets id finns som data-attribut på elementet som dras (
- Vi behöver ta bort
drag-overfrån zonen, eftersom vi är klara med dragningen.
Förslag på lösning
function onDrop(e) {
const zone = e.target;
zone.classList.remove("drag-over");
const draggedId = draggedElement.dataset.id;
const zoneId = zone.dataset.id;
if (draggedId === zoneId) {
// Rätt matchning!
zone.classList.add("correct");
// Inaktivera det dragna elementet
draggedElement.draggable = false;
draggedElement.classList.add("matched");
} else {
// Fel matchning
zone.classList.add("incorrect");
setTimeout(() => {
zone.classList.remove("incorrect");
}, 500);
}
}
Fixa till visuell feedback i dragover och dragenter
I onDragOver och onDragEnter, vill vi endast ge visuell feedback om zonen inte redan är markerad som korrekt (dvs har klassen correct).
Förslag på lösning
function onDragOver(e) {
if (!e.target.classList.contains("correct")) {
e.preventDefault();
}
}
function onDragEnter(e) {
if (!e.target.classList.contains("correct")) {
e.target.classList.add("drag-over");
}
}
4 - Utmaning: Lägg till ljud
För en extra utmaning kan du lägga till ljud som spelas upp när användaren gör en rätt matchning.
- I arbetsmaterialet finns en mapp
audiomed ljudfiler för varje djur, t.ex.cat.mp3,dog.mp3osv. - Lägg in ett audio-element någonstans i html-filen (du kan sätta
display: nonepå det i CSS så att det inte syns). - Vid drop, sätt
srcpå audio-elementet till rätt ljudfil och anropaplay().