๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Javascript Effect

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ : ๊ฒŒ์ž„ ํšจ๊ณผ : ๋ฉ”๋ชจ๋ฆฌ ๊ฒŒ์ž„

by ์ฝ”ํŒŒ์นด 2022. 10. 29.
728x90

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ : ๊ฒŒ์ž„ ํšจ๊ณผ : ๋ฉ”๋ชจ๋ฆฌ ๊ฒŒ์ž„

์ด๋ฒˆ์—๋Š” ๊ฐ™์€ ๊ทธ๋ฆผ ์ฐพ๊ธฐ ๋ฉ”๋ชจ๋ฆฌ ๊ฒŒ์ž„์„ ๋งŒ๋“ค์–ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


0. HTML

HTML ์†Œ์Šค๋Š” ์•„๋ž˜๋ฅผ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”.

HTML ์†Œ์Šค ๋ณด๊ธฐ
<div class="memory__wrap">
  <div class="memory__inner"><span class="memory-close"></span>
    <div class="memory__main">
      <h3>Memory Game</h3>
      <p class="memory__start">START</p>
    </div>
    <div class="memory__card">
      <h3>Memory Game</h3>
      <div class="memory__card__info">
        <p>์ ์ˆ˜ : <span class="memory__card__score">0</span> / 16</p>
        <p>๋‚จ์€ ๊ธฐํšŒ : <span class="memory__card__opp">3</span></p>
      </div>
      <ul class="cards">
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-1.svg" alt="img1" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-2.svg" alt="img2" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-3.svg" alt="img3" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-4.svg" alt="img4" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-5.svg" alt="img5" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-6.svg" alt="img6" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-7.svg" alt="img7" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-8.svg" alt="img8" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-1.svg" alt="img1" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-2.svg" alt="img2" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-3.svg" alt="img3" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-4.svg" alt="img4" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-5.svg" alt="img5" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-6.svg" alt="img6" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-7.svg" alt="img7" />
          </div>
        </li>
        <li>
          <div class="view front">
            <img src="../assets/img/card.png" alt="card__front" />
          </div>
          <div class="view back">
            <img src="../assets/img/memory-8.svg" alt="img8" />
          </div>
        </li>
      </ul>
      <!-- memory__card -->
    </div>
    <div class="memoryGameRestart">๋‹ค์‹œํ•˜๊ธฐ</div>
  </div>
</div>

1. ์„ ํƒ์ž ์ž‘์—…ํ•˜๊ธฐ

const memoryWrap = document.querySelector(".memory__wrap");
const memoryCard = memoryWrap.querySelectorAll(".cards li");

let cardOne, cardTwo; // ๋’ค์ง‘๋Š” ์นด๋“œ
let disableDeck = false;
let matchedCard = 0; // ์ ์ˆ˜
let endCardGame = 3; // ๊ธฐํšŒ

let sound = [
  "../assets/audio/search_good.m4a",
  "../assets/audio/search_bad.m4a",
  "../assets/audio/up.mp3",
  "../assets/audio/over.mp3",
  "../assets/audio/gamebg.mp3"
];
let soundMatch = new Audio(sound[0]);  // ์ •๋‹ต ์‚ฌ์šด๋“œ
let soundUnMatch = new Audio(sound[1]);  // ์˜ค๋‹ต ์‚ฌ์šด๋“œ
let soundSuccess = new Audio(sound[2]);  // ์Šน๋ฆฌ ์‚ฌ์šด๋“œ
let memoryGameOver = new Audio(sound[3]);  // ํŒจ๋ฐฐ ์‚ฌ์šด๋“œ
let memoryGameBg = new Audio(sound[4]);  // ๋ฐฐ๊ฒฝ์Œ์•…

HTML๊ณผ CSS๋กœ ๋””์ž์ธ ์ž‘์—…์„ ๋งˆ์ณค๋‹ค๋ฉด, ์„ ํƒ์ž๋ฅผ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

2. ์นด๋“œ๋ฅผ ๋’ค์ง‘์—ˆ์„ ๋•Œ์˜ ํ•จ์ˆ˜ ์ž‘์—…ํ•˜๊ธฐ

function flipCard(e) {
  let clickedCard = e.target;

  // && !disableDeck : ๋’ค์ง‘ํžŒ ์นด๋“œ๊ฐ€ ์˜ค๋‹ต์ผ ๋•Œ, ํ”๋“ค๋ฆด ๋•Œ ๋‹ค๋ฅธ ์นด๋“œ ๋ˆ„๋ฅด๋Š” ๊ฒƒ ๋ฐฉ์ง€
  if (clickedCard !== cardOne && !disableDeck) {
    clickedCard.classList.add("flip");

    if (!cardOne) {
      return (cardOne = clickedCard);
    }
    cardTwo = clickedCard;
    disableDeck = true;

    let cardOneImg = cardOne.querySelector(".back img").src;
    let cardTwoImg = cardTwo.querySelector(".back img").src;

    matchCards(cardOneImg, cardTwoImg);
  }
}

memoryCard.forEach((card) => {
    card.addEventListener("click", flipCard);
  });

target์€ ํ•จ์ˆ˜ ์•ˆ์—์„œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ ๋Œ€์ƒ์„ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค. flip ํด๋ž˜์Šค๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด, ์‚ฌ์ „์— ์ž‘์—…ํ•œ ์นด๋“œ ๋’ค์ง‘๊ธฐ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์ž‘๋™ํ•˜์—ฌ ์นด๋“œ์˜ ์•ž๋ฉด์ด ๋ณด์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
์ด ๊ฒŒ์ž„์—์„œ๋Š” ํ•œ ํ„ด์— ์นด๋“œ๋ฅผ ๋‘ ์žฅ์”ฉ ๋’ค์ง‘๊ธฐ ๋•Œ๋ฌธ์—, if๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ฒซ ๋ฒˆ์งธ ํด๋ฆญ๋œ ์นด๋“œ๋Š” cardOne, ๋‘ ๋ฒˆ์งธ ํด๋ฆญ๋œ ์นด๋“œ๋Š” cardTwo๋กœ ๊ตฌ๋ถ„ํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
๋‹ค์Œ์€ ๊ตฌ๋ถ„ํ•œ ์นด๋“œ๋“ค์˜ img ์ฃผ์†Œ๋ฅผ ํ™•์ธํ•˜์—ฌ ์ด๋ฏธ์ง€ ์ผ์น˜ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” matchCards ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

3. ๋‘ ๊ฐœ์˜ ์นด๋“œ๋ฅผ ๋น„๊ตํ•˜๋Š” ํ•จ์ˆ˜ ์ž‘์—…ํ•˜๊ธฐ

function matchCards(img1, img2) {
  if (img1 == img2) {  // ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ
    matchedCard++;
    matchedCard++;
    soundMatch.play();
    document.querySelector(".memory__card__score").innerHTML = matchedCard;

    cardOne.removeEventListener("click", flipCard);
    cardTwo.removeEventListener("click", flipCard);
    cardOne = cardTwo = "";
    disableDeck = false;

    if (matchedCard == 16) {
      soundSuccess.play();
      memoryGameBg.pause();
      setTimeout(() => {
        document.querySelector(".memoryGameRestart").style.transform = "scale(1)";
      }, 3000);
    }
  }

img1, img2๋Š” ์•ž์„œ flipCard() ํ•จ์ˆ˜ ๋‚ด์—์„œ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „์†กํ•œ ์ด๋ฏธ์ง€ ์ฃผ์†Œ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.
๋จผ์ € img1 == img2, ์ฆ‰ ๋‘ ๊ฐœ์˜ ์ด๋ฏธ์ง€๊ฐ€ ์ผ์น˜ํ•  ๋•Œ์—๋Š”, ์ ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ๊ณ , ์ •๋‹ต ์‚ฌ์šด๋“œ๋ฅผ ์žฌ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์„ฑ๊ณตํ•œ ์นด๋“œ๋Š” ๋‹ค์‹œ ๋’ค์ง‘์–ด์ง€์ง€ ์•Š๋„๋ก removeEventListener๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ž์„œ ์ž‘์—…ํ–ˆ๋˜ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ์ œ๊ฑฐํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
๋˜, ์ด ๊ฒŒ์ž„์—์„œ ์Šน๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ ์ˆ˜๋Š” 16์ ์ด๋ฏ€๋กœ, ์ ์ˆ˜๊ฐ€ 16์ ์— ๋‹ค๋‹ค๋ฅด๋ฉด ์Šน๋ฆฌ ์‚ฌ์šด๋“œ๊ฐ€ ์žฌ์ƒ๋˜๊ณ , ๊ฒŒ์ž„์„ ๋‹ค์‹œ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ„ํŠผ์ด ๋‚˜ํƒ€๋‚˜๋„๋ก ์ž‘์—…ํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

  else {  // ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ
    soundUnMatch.play();
    setTimeout(() => {
      cardOne.classList.add("shakeX");
      cardTwo.classList.add("shakeX");
    }, 400);

    setTimeout(() => {
      cardOne.classList.remove("shakeX", "flip");
      cardTwo.classList.remove("shakeX", "flip");
      cardOne = cardTwo = "";
      disableDeck = false;
    }, 1000);
    endCardGame--;
    document.querySelector(".memory__card__opp").innerHTML = endCardGame;
    if (endCardGame == 0) {
      setTimeout(() => {
        memoryGameOver.play();
        memoryGameBg.pause();
        memoryCard.forEach((card) => {
          card.classList.add("flip");
          card.removeEventListener("click", flipCard);
        });
      }, 1000);
      setTimeout(() => {
        document.querySelector(".memoryGameRestart").style.transform = "scale(1)";
      }, 4000);
    }
  }
}

์ด๋ฏธ์ง€๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋Š” ์˜ค๋‹ต ์‚ฌ์šด๋“œ๋ฅผ ์žฌ์ƒ์‹œํ‚ค๊ณ , ์˜ค๋‹ต ์นด๋“œ๋“ค์ด ์ขŒ์šฐ๋กœ ํ”๋“ค๋ฆฌ๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋‚˜ํƒ€๋‚ฌ๋‹ค๊ฐ€, ๋‹ค์‹œ ๋’ค์ง‘์–ด์ง€๊ฒŒ๋” ์ž‘์—…ํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
๋˜, ์ด ๊ฒŒ์ž„์€ 3ํšŒ ์˜ค๋‹ต์„ ์ œ์‹œํ•œ ๊ฒฝ์šฐ, ๊ฒŒ์ž„์ด ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค. ๊ฒŒ์ž„ ์˜ค๋ฒ„๊ฐ€ ๋˜์—ˆ์„ ๋•Œ๋Š” ๊ฒŒ์ž„ ์˜ค๋ฒ„ ์‚ฌ์šด๋“œ๊ฐ€ ์žฌ์ƒ๋˜๊ณ , ๋ชจ๋“  ์นด๋“œ๋“ค์˜ ์•ž๋ฉด์„ ๋ณด์—ฌ์ฃผ๊ณ , ๋‹ค์‹œํ•˜๊ธฐ ๋ฒ„ํŠผ์ด ๋‚˜ํƒ€๋‚˜๋„๋ก ์ž‘์—…ํ•ด ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.

4. ์นด๋“œ ์„ž๊ธฐ ํ•จ์ˆ˜ ์ž‘์—…ํ•˜๊ธฐ

function shuffledCard() {
  cardOne = cardTwo = "";
  disableDeck = false;
  matchedCard = 0;

  let arr = [1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8];
  let result = arr.sort(() => (Math.random() > 0.5 ? 1 : -1));

  memoryCard.forEach((card, index) => {
    card.classList.remove("flip");

    setTimeout(() => {
      card.classList.add("flip");
    }, 200 * index);

    setTimeout(() => {
      card.classList.remove("flip");
    }, 4000);

    let imgTag = card.querySelector(".back img");
    imgTag.src = `../assets/img/memory-${arr[index]}.svg`;
  });
}

๊ฐ๊ฐ์˜ ์นด๋“œ๋“ค์ด ํ•ญ์ƒ ๊ฐ™์€ ์ž๋ฆฌ์— ์žˆ๋‹ค๋ฉด ๊ฒŒ์ž„์ด ๋„ˆ๋ฌด ์‰ฌ์›Œ์ง€๊ธฐ ๋•Œ๋ฌธ์—, ๊ฒŒ์ž„์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „ ์นด๋“œ๋ฅผ ์„ž๋Š” ๊ณผ์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์นด๋“œ์˜ ์ด ๊ฐœ์ˆ˜์— ํ•ด๋‹นํ•˜๋Š” ๊ธธ์ด๋ฅผ ๊ฐ€์ง„ ๋ฐฐ์—ด์„ ๋งŒ๋“ค๊ณ , Math.random() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์นด๋“œ๋“ค์„ ๋žœ๋ค์œผ๋กœ ์žฌ๋ฐฐ์น˜ํ•ด ์ฃผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๊ฒŒ์ž„ ์™„์„ฑ์ž…๋‹ˆ๋‹ค.


๊ฒฐ๊ณผ

์„ธ ๋ฒˆ์งธ ๋ถ„ํ™์ƒ‰ ํด๋”๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๊ฒŒ์ž„์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋””์ž์ธ์— ๋Œ€ํ•œ ํƒœํด์€ ๋ฐ›์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค.

728x90

๋Œ“๊ธ€

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๐Ÿฆ™

CSS
๊ด‘๊ณ  ์ค€๋น„์ค‘