<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Project #17 - Memory Card Game</title>
</head>
<body>
<section class="memory-game">
<!-- 1st Card -->
<div class="memory-card" data-name="baby-bear">
<img src="https://cdn.pixabay.com/photo/2014/01/22/19/44/flower-field-250016_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 2nd Card -->
<div class="memory-card" data-name="baby-bear">
<img src="https://cdn.pixabay.com/photo/2014/01/22/19/44/flower-field-250016_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 3rd Card -->
<div class="memory-card" data-name="bird">
<img src="https://cdn.pixabay.com/photo/2013/08/22/19/18/flowers-174817_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 4th Card -->
<div class="memory-card" data-name="bird">
<img src="https://cdn.pixabay.com/photo/2013/08/22/19/18/flowers-174817_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 5th Card -->
<div class="memory-card" data-name="cat">
<img src="https://cdn.pixabay.com/photo/2013/07/21/13/00/rose-165819_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 6th Card -->
<div class="memory-card" data-name="cat">
<img src="https://cdn.pixabay.com/photo/2013/07/21/13/00/rose-165819_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 7th Card -->
<div class="memory-card" data-name="curious-cat">
<img src="https://cdn.pixabay.com/photo/2016/11/29/01/10/kitten-1866475_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 8th Card -->
<div class="memory-card" data-name="curious-cat">
<img src="https://cdn.pixabay.com/photo/2016/11/29/01/10/kitten-1866475_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 9th Card -->
<div class="memory-card" data-name="dog">
<img src="https://cdn.pixabay.com/photo/2021/10/19/10/56/cat-6723256_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 10th Card -->
<div class="memory-card" data-name="dog">
<img src="https://cdn.pixabay.com/photo/2021/10/19/10/56/cat-6723256_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 11th Card -->
<div class="memory-card" data-name="hamster">
<img src="https://cdn.pixabay.com/photo/2016/03/28/10/05/kitten-1285341_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
<!-- 12th Card -->
<div class="memory-card" data-name="hamster">
<img src="https://cdn.pixabay.com/photo/2016/03/28/10/05/kitten-1285341_960_720.jpg" alt="animal" class="front-face" />
<img src="https://cdn.pixabay.com/photo/2019/09/29/22/06/light-bulb-4514505_960_720.jpg" alt="?" class="back-face" />
</div>
</section>
<!-- -------------------------------- -->
<!-- JS File -->
<script src="app.js"></script>
</body>
</html>
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.memory-game {
height: 650px;
width: 1200px;
display: flex;
flex-wrap: wrap;
}
.memory-card {
width: calc(25% - 10px);
height: calc(33.3333% - 10px);
margin: 5px;
position: relative;
transform: scale(1);
transform-style: preserve-3d;
transition: transform 0.3s ease-out;
}
.front-face,
.back-face {
height: 100%;
width: 100%;
position: absolute;
object-fit: cover;
/* 뒤집혔을때 앞뒷면이 서로 겹치지 않도록 한 면은 숨겨놓는다. */
backface-visibility: hidden;
}
.memory-card:active {
/* 카드를 누르면 크기가 조금 작아지며 눌리는 효과냄. */
transform: scale(0.97);
transition: transform 0.15s ease-out;
}
/* 카드를 180도 회전 turn은 단위. */
.front-face {
transform: rotateY(0.5turn);
}
/* Dynamic Class */
.memory-card.flip {
/* perspective 값이 작을수록화면과 가까이 있다는 뜻. 즉 변화가 커진다.*/
transform: rotateY(180deg) perspective(1000px);
}
const cards = document.querySelectorAll(".memory-card");
let cardIsFlipped = false;
//카드 두개를 확인하는 동안에는 다른 카드들을 열수 없도록 화면 잠그기.
let lockBoard = false;
let firstCard, secondCard;
function flipCard() {
//세번째 카드를 열수 없도록 함.
if (lockBoard) return;
//처음 누른 카드를 또 누르면 아무 작용도 없이 리턴.
//이렇게 안하면 더블 클릭으로 같은 카드를 누르면 그 이름이 같으므로 카드가 일치하게 되어 화면에 남게 된다.
if (this === firstCard) return;
// this.classList.toggle("flip");
this.classList.add("flip");
if (!cardIsFlipped) {
//카드가 눌린 적 없는 첫번째 클릭. 첫 카드
cardIsFlipped = true;
firstCard = this;
return;
}
// 두번째 클릭 , 두번째 카드.
secondCard = this;
checkForMatch();
}
//카드가 맞는지 확인.
function checkForMatch() {
let isMatched = firstCard.dataset.name === secondCard.dataset.name;
isMatched ? disableCards() : unFlipCards();
}
//카드가 서로 맞으면. 카드 비활성화 (더이상 클릭 이벤트가 없도록.)
function disableCards() {
firstCard.removeEventListener("click", flipCard);
secondCard.removeEventListener("click", flipCard);
resetBoard();
}
//카드가 틀리면 , 일정 시간이 지난 후에 뒤집힌 상태가 없어져서 다시 뒷면으로 뒤집히게 된다.
function unFlipCards() {
lockBoard = true;
setTimeout(() => {
firstCard.classList.remove("flip");
secondCard.classList.remove("flip");
resetBoard();
}, 1500);
}
function resetBoard() {
//구조 분해 할당으로 리셋
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
[cardIsFlipped, lockBoard] = [false, false];
[firstCard, secondCard] = [null, null];
}
// IIFE -> Immediately Invoked Function Expression => 즉시 실행 함수 => 함수가 정의된 바로 직후에 실행.
//화면을 새로고침만해도, 즉시 셔플이 실행됨.
(function shuffle() {
cards.forEach(function (card) {
let randomPositions = Math.floor(Math.random() * 12);
card.style.order = randomPositions;
});
})();
cards.forEach(function (card) {
card.addEventListener("click", flipCard);
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.