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.
164 lines
4.4 KiB
164 lines
4.4 KiB
import "../../font.css";
|
|
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() {
|
|
const tip = document.createElement("div");
|
|
tip.className = "tip";
|
|
this.cardsContainer.appendChild(tip);
|
|
tip.addEventListener("click", (e) => {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
this.cardsContainer.removeChild(tip);
|
|
});
|
|
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();
|
|
}
|
|
}
|
|
|