개발 기록 남기기✍️

[JavaScript] 토이 프로젝트 - 카드 짝 맞추기 게임 본문

Front-End/JavaScript

[JavaScript] 토이 프로젝트 - 카드 짝 맞추기 게임

너해동물원 2023. 1. 30. 11:49

🃏 카드 짝 맞추기 게임

  • 제작 기간 : 2023-01-16 ~ 2023-01-26 (11일)
  • 사용 언어 : HTML, SCSS, Javascript
  • 데모 사이트 : JAVASCRIPT PAIRS GAME

 

 페이지 소개

  • 카드 짝 맞추기 게임을 할 수 있습니다.
  • 페이지가 로드될 시 카드가 무작위로 섞입니다.

 

카드 섞는 함수

let shuffledCards = [];
function shuffle(cards) {
  for (let i = cards.length - 1; i >= 0; i--) {
    let makeRandom = Math.floor(Math.random() * cards.length);
    shuffledCards.push(cards[makeRandom]);
    cards.splice(makeRandom, 1);
  }
  return shuffledCards;
}

 

게임 플레이

  • start 버튼을 누르면 타이머 시작과 동시에 게임이 시작됩니다.
  • new Audio를 통해 카드 클릭 시 소리가 나도록 했습니다.
  • 카드를 클릭하면 flipped 클래스가 부여되며 카드가 뒤집어집니다.
  • 두 개의 카드가 선택되면, 두 카드의 data-item 값이 일치하는지 확인합니다. 일치하면 same 클래스를 부여해서 계속 뒤집어놓고, 일치하지 않으면 두 카드 다 filpped 클래스를 제거합니다.

 

카드 클릭 시 실행할 함수

function clickCards() {
  const myCardsEl = document.querySelectorAll(".card");
  let pairedCards = 0;
  let clicked = [];
  let pass = true;

  // 카드 클릭할 때마다 동작 수행
  // 카드 두개 선택 시 일치하는지 비교
  // 일치하지 않으면 다시 뒤집어 놓기
  // 일치하면 카드에 "same" 클래스 추가 및 pairedCards에 +1 처리
  // pairedCards이 10이 되면 게임 종료 및 걸린 시간 출력
  myCardsEl.forEach((item) => {
    item.addEventListener("click", async function () {
      if (pass) {
        // 카드 뒤집어지는 중에는 다른 카드 선택 못하도록 방지
        pass = false;
        clickBgm();
        this.classList.add("flipped");
        const clickedCard = this.dataset.item;
        clicked.push(clickedCard);
        // 뒤집어진 카드가 두 개일 때, 카드를 비교하는 함수 실행
        await compareCards(this);
      }
    });
  });

 

compareCards 함수

  async function compareCards(el) {
    if (clicked.length === 2) {
      let promise = new Promise((resolve) => {
        setTimeout(() => resolve(matchCards(el)), 300);
      });

      await promise;
    }
    pass = true;
  }

 

두 카드를 비교하는 함수

  function matchCards(el) {
    const firstCard = el;
    const secondCard = getSiblings(firstCard);
    secondCard.forEach((item) => {
      if (item.dataset.item == firstCard.dataset.item) {
        firstCard.classList.add("same");
        item.classList.add("same");
        pairedCards += 1;
        sameBgm();
      } else {
        differentBgm();
      }
      firstCard.classList.remove("flipped");
      item.classList.remove("flipped");
    });
    clicked = [];
    if (pairedCards === 10) endGame();
  }
  
  // 이전에 클릭했던 카드(첫번째로 뒤집어진 카드)를 선택하는 함수
  function getSiblings(el) {
    return Array.from(el.parentElement.children).filter(
      (e) => e.classList.contains("flipped") && e !== el
    );
  }

 

게임 클리어

  • 열 쌍의 카드를 모두 맞추면 게임이 종료되고, 걸린 시간을 보여줍니다.
  • Play Again 버튼을 누르면 페이지가 reload 됩니다.

 

 


🗒️ Review

아직도 모듈화하는 건 꽤 어렵다.. timer 함수를 모듈화해서 main.js에 불러오는 식으로 했는데, 처음에 timer 함수 안에 setInterval 메서드를 사용하고 그 상태로 불러왔는데, 타이머 작동은 잘 되는데 타이머를 멈추는게 되질 않았다.

그래서 setInterval 안에 들어갈 함수만 따로 모듈화하고, let play = setInterval(fn, 100) / clearInterval(clear) 식으로 하니 해결되었다. 메서드의 동작 원리를 제대로 알지 못해 발생한 문제였다. 왜 강사님들과 멘토님들이 공식 문서를 그렇게 강조하시는지를 깨닫게 되는 시간이였다..✨

 

또, 지금까지는 흥미를 붙이기 위해서 간단한 기능 구현을 연습했는데, 프론트엔드 기술의 핵심은 CRUD를 구현하는 것이라 하셔서 API를 활용한 SPA를 구현해볼 생각이다. 구현하는데까지 오래 걸리겠지만, 그래도 그 시간동안 많은 성장이 있을거라 기대하면서! 다시 도전~!