JSFiddle - React, Tailwind, and code Playground
by leenie
HTML
<div class="entire_container">
<div class="overlay-text visible">
Klicke, um zu starten
<span class="overlay-text-small">Finde die acht Paare rechtzeitig!</span>
</div>
<div id="game-over-text" class="overlay-text">
GAME OVER
<span class="overlay-text-small">Du hast die Paare leider nicht gefunden. Klicke erneut, um zu starten.</span>
</div>
<div id="victory-text" class="overlay-text">
GEWONNEN!
<span class="overlay-text-small">
Ein kleines Geschenk für dich:<br>
Code: kleinessouvenir<br><br>
Klicke, um neuzustarten.</span>
</div>
<div class="game-container">
<div class="game-info-container">
<div class="game-info">
Zeit <span id="time-remaining"></span>
</div>
<div class="game-info">
Umgedreht <span id="flips">0</span>
</div>
</div>
<div class="card">
<div class="card-back card-face">
<img class="back-image" src="https://imgur.com/mj7g45P.png">
</div>
<div class="card-front card-face">
<img class="card-value" src="https://imgur.com/cz6MRAp.png">
</div>
</div>
<div class="card">
<div class="card-back card-face">
<img class="back-image" src="https://imgur.com/mj7g45P.png">
</div>
<div class="card-front card-face">
<img class="card-value" src="https://imgur.com/cz6MRAp.png">
</div>
</div>
<div class="card">
<div class="card-back card-face">
<img class="back-image" src="https://imgur.com/mj7g45P.png">
</div>
<div class="card-front card-face">
<img class="card-value" src="https://imgur.com/T9HAA4L.png">
</div>
</div>
<div class="card">
<div class="card-back card-face">
<img class="back-image" src="https://imgur.com/mj7g45P.png">
</div>
<div class="card-front card-face">
<img class="card-value" src="https://imgur.com/T9HAA4L.png">
</div>
</div>
<div class="card">
...
CSS
* {
box-sizing: border-box;
}
.entire_container {
position: relative;
overflow: hidden;
background: url(https://business24-agenturbelmediag.netdna-ssl.com/wp-content/uploads/2014/05/Sand-StudioSmart-Shutterstock.com_.jpg);
width: 960px;
height: 500px;
}
.game-info-container {
grid-column: 1 / -1;
display: flex;
justify-content: space-between;
}
.game-info {
font-family: Arial, serif;
color: #000;
font-size: 30px;
}
.game-container {
display: grid;
grid-template-columns: repeat(4, auto);
grid-gap: 10px;
margin: 50px;
justify-content: center;
perspective: 500px;
}
.card {
position: relative;
height: 80px;
width: 125px;
}
.card:hover {
cursor: pointer;
}
.card-face {
position: absolute;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
backface-visibility: hidden;
border-radius: 12px;
transition: transform 500ms ease-in-out;
}
.card.visible .card-back {
transform: rotateY(-180deg);
}
.card.visible .card-front {
transform: rotateY(0);
}
.card.matched .card-value {
animation: dance 1s linear 1 500ms;
}
.overlay-text {
display: none;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
justify-content: center;
align-items: center;
z-index: 100;
color: #fff;
font-family: Arial, serif;
cursor: pointer;
}
.overlay-text-small {
font-size: 20px;
text-align: center;
padding: 0px 50px;
animation: overlay-grow-small 500ms forwards;
}
.overlay-text.visible {
display: flex;
flex-direction: column;
animation: overlay-grow 500ms forwards;
}
@keyframes overlay-grow {
from {
background-color: rgba(0, 0, 0, 0);
font-size: 0;
}
to {
background-color: rgba(0, 0, 0, 0.8);
font-size: 60px;
}
}
@keyframes overlay-grow-small {
from {
font-size: 0;
}
to {
font-size: 20px;
}
}
@keyframes dance {
0%, 100% {
transform: rotate(0);
}
25% {
...
JavaScript
class Memory {
constructor(totalTime, cards) {
this.cardsArray = cards;
this.totalTime = totalTime;
this.timeRemaining = totalTime;
this.timer = document.getElementById('time-remaining')
this.ticker = document.getElementById('flips');
}
startGame() {
this.totalClicks = 0;
this.timeRemaining = this.totalTime;
this.cardToCheck = null;
this.matchedCards = [];
this.busy = true;
setTimeout(() => {
this.shuffleCards(this.cardsArray);
this.countdown = this.startCountdown();
this.busy = false;
}, 500);
this.hideCards();
this.timer.innerText = this.timeRemaining;
this.ticker.innerText = this.totalClicks;
}
startCountdown() {
return setInterval(() => {
this.timeRemaining--;
this.timer.innerText = this.timeRemaining;
if(this.timeRemaining === 0)
this.gameOver();
}, 1000);
}
gameOver() {
clearInterval(this.countdown);
document.getElementById('game-over-text').classList.add('visible');
}
victory() {
clearInterval(this.countdown);
document.getElementById('victory-text').classList.add('visible');
}
hideCards() {
this.cardsArray.forEach(card => {
card.classList.remove('visible');
card.classList.remove('matched');
});
}
flipCard(card) {
if(this.canFlipCard(card)) {
this.totalClicks++;
this.ticker.innerText = this.totalClicks;
card.classList.add('visible');
if(this.cardToCheck) {
this.checkForCardMatch(card);
} else {
this.cardToCheck = card;
}
}
}
checkForCardMatch(card) {
if(this.getCardType(card) === this.getCardType(this.cardToCheck))
this.cardMatch(card, this.cardToCheck);
else
...