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.
 
 

155 lines
4.1 KiB

import "./flipper.css";
function importAll(r) {
let obj = {};
r.keys().forEach((key) => {
obj[key.replace("./", "").replace(".png", "")] = r(key);
});
return obj;
}
const images = importAll(require.context("./", false, /\.(png|jpe?g|svg)$/));
const cardNames = "abcdefghabcdefgh";
export default class Game {
duration = 1000;
constructor({ containerId, onLose, onWon }) {
Object.assign(this, {
container: document.getElementById(containerId),
onLose,
onWon,
});
this.addBg();
this.init();
}
init() {
Object.assign(this, {
steps: 40,
score: 0,
});
this.shuffleCards();
this.update();
}
update() {
this.scoreEl.textContent = this.score;
this.stepEl.textContent = this.steps;
}
setSize() {
Object.assign(this, {
width: this.container.clientWidth,
height: this.container.clientHeight,
});
this.scoreEl.style.fontSize = (this.width / 2160) * 100 + "px";
this.scoreEl.style.lineHeight = (this.width / 2160) * 116 + "px";
this.stepEl.style.fontSize = (this.width / 2160) * 100 + "px";
this.stepEl.style.lineHeight = (this.width / 2160) * 116 + "px";
}
addBg() {
this.scoreEl = document.createElement("div");
this.scoreEl.className = "meta l";
this.stepEl = document.createElement("div");
this.stepEl.className = "meta r";
const bg = document.createElement("div");
bg.className = "flipper";
this.cardsContainer = bg;
this.container.appendChild(bg);
this.setSize();
bg.appendChild(this.scoreEl);
bg.appendChild(this.stepEl);
this.resizeListener = window.addEventListener("resize", () => {
this.setSize();
});
this.cards = Array.from(cardNames).map((name) => {
const url = images[name];
const card = document.createElement("div");
card.className = "card";
card.setAttribute("data-name", name);
const front = document.createElement("div");
front.className = "front";
front.style.backgroundImage = `url(${url})`;
card.appendChild(front);
const back = document.createElement("div");
back.className = "back";
card.appendChild(back);
return card;
});
this.cards.forEach((card) => {
this.cardsContainer.appendChild(card);
});
this.cards.forEach((card) => {
card.addEventListener("click", this.flip.bind(this, card));
});
}
pause() {}
resume() {}
restart() {
this.init();
}
dispose() {
window.removeEventListener("resize", this.resizeListener);
}
shuffleCards() {
this.cards.forEach((card) => {
const randomNumber = Math.floor(Math.random() * this.cards.length) + 1;
card.classList.remove("has-match");
card.classList.remove("flipped");
setTimeout(() => {
card.style.order = `${randomNumber}`;
}, 400);
});
}
checkAllCards() {
if (this.cards.every((card) => card.classList.contains("has-match"))) {
this.onWon && this.onWon();
setTimeout(() => {
this.restart();
}, this.duration);
}
}
stopEvent() {
this.cardsContainer.classList.add("no-event");
setTimeout(() => {
this.cardsContainer.classList.remove("no-event");
}, this.duration);
}
checkIfMatched(firstCard, secondCard) {
if (firstCard.dataset.name === secondCard.dataset.name) {
this.score += 20;
firstCard.classList.remove("flipped");
secondCard.classList.remove("flipped");
firstCard.classList.add("has-match");
secondCard.classList.add("has-match");
this.checkAllCards();
} else {
setTimeout(() => {
firstCard.classList.remove("flipped");
secondCard.classList.remove("flipped");
}, this.duration);
}
}
flip(selectedCard) {
this.steps--;
if (this.steps < 0) {
this.onLose && this.onLose();
this.restart();
}
selectedCard.classList.add("flipped");
const flippedCards = this.cards.filter((card) =>
card.classList.contains("flipped")
);
if (flippedCards.length === 2) {
this.stopEvent();
this.checkIfMatched(flippedCards[0], flippedCards[1]);
}
this.update();
}
}