[JavaScript] 카드 맞추기 💘

혜연·2024년 2월 28일
0

미니게임 만들기

목록 보기
4/4
post-thumbnail

🎮 게임 링크

미니게임 만들기 | 카드 맞추기


세번째 게임 : 카드 맞추기

같은 그림의 카드를 짝지어 찾는 게임

  • 게임 시나리오
  1. 랜덤 카드 만들기
  2. 게임판 구성하기
  3. 전체 카드를 공개후 게임 시작
  4. 2개의 카드를 클릭시 두 카드를 비교

1. 랜덤 카드 만들기

24개의 카드를 사용할 것이니 총 12개의 이미지가 필요합니다. 이미지는 무료 아이콘 사이트인 flaticon에서 Cute Fast Food Mascot을 사용했습니다.
randomCard 배열에 이미지를 담고, 이 배열은 항상 게임 시작전에 랜덤으로 섞일 수 있도록 해주어야 합니다.

  const card_img = [
    //카드에 넣을 이미지 배열
    ...
  ];
  randomCard = card_img;
  randomCard.push(...randomCard); //2쌍씩

1.1 카드 섞기

function shuffleCard(array) {
  array.sort(() => Math.random() - 0.5);
}

Math.random() 메서드는 0 ~ 1 사이의 난수를 반환합니다. 반환되는 난수의 중간 값인 0.5를 뺀 값은 50% 확률로 양수가 되거나 음수가 됩니다.
무작위로 양수와 음수를 반환하는 식을 sort 정렬에 대입해 배열의 요소를 무작위로 바꿀 수 있는 방법을 사용했습니다.


2. 게임판 만들기

게임은 4X6 게임판에서 진행됩니다. 24장의 카드가 필요하고 한 카드div는 카드앞면, 카드뒷면 div를 가지고 있도록 해줍니다.

<div class="card" id=${index} data-img=${item}>
<div class="card__front" id=${item}.jpg></div>
<div class="card__back"></div>
</div>

이 구조의 카드를 innerHTML을 통해 그려줄게요. 랜덤 이미지를 담고 있는 randomCard 배열에 map함수를 적용해 그려지는 카드의 인덱스에 맞는 이미지까지 바로 넣어주었습니다.

randomCard.map((item, index) => {
    cards.innerHTML =
      cards.innerHTML +
      ` 
<div class="card" id=${index} data-img=${item}>
<div class="card__front" id=${item}.jpg></div>
<div class="card__back"></div>
</div>
`;
  });

randomCard 배열에 담긴 이미지 순서대로 카드가 생성됩니다. randomCard 안의 이미지는 매 게임마다 랜덤으로 섞이기 때문에 항상 다른 순서로 카드르를 그릴 수 있습니다.


3. 카드 공개

게임 시작 전 한 카드씩 앞면을 보여주고 마지막 카드까지 공개된 이후에는 전체 카드를 다시 뒤집고 게임을 시작합니다.

3.1 카드 뒷면 숨기기

한 카드의 앞면이 보일 땐 뒷면이 보이지 않도록 cardFront와 cardBack에 backface-visibility: hidden을 주어 뒷면은 보이지 않도록 해줍니다.

 backface-visibility: hidden;

3.2 카드 이미지 보이기

cardFront는 처음 생성 시 rotateY(180deg)를 적용해 뒷면을 보인 채 그려집니다. 이를 뒤집어 뒷면을 숨기고 앞면을 보여주기 위해 cardFront는 rotateY(360deg), cardBack에는 rotateY(180deg)를 적용합니다.

//처음 실행시에 카드를 전체적으로 보여주는 함수
function firstShowCard() {
  let cnt = 0;
  const showInterval = setInterval(() => {
    cardBack[cnt].style.transform = 'rotateY(180deg)';
    cardFront[cnt].style.transform = 'rotateY(360deg)';
    ++cnt;
  }, 350);
}

3.3 카드 이미지 숨기기

마지막 카드까지 공개된 이후에는 closeCard() 메서드를 불러 다시 카드 뒷면을 보이도록 해줍니다.

    if (cnt === GAME_SIZE - 1) {
      clearInterval(showInterval);
      setTimeout(() => {
        closeCard();
      }, 3000);
    }

이미지 공개와는 반대로 cardBack은 rotateY(360deg)로 다시 보여지고, cardFront는 rotateY(180deg)로 다시 숨겨집니다.

//카드를 다시 닫는 함수
function closeCard() {
  for (let i = 0; i < GAME_SIZE; i++) {
    cardBack[i].style.transform = 'rotateY(360deg)';
    cardFront[i].style.transform = 'rotateY(180deg)';
  }
}

4. 카드를 클릭시 두 카드를 비교

4.1 카드 클릭

첫번째 클릭된 카드와 두번째로 클릭한 카드를 위한 변수를 선언해줍니다.

let firstCard = 0;
let secondCard = 0;

클릭 이벤트를 사용해 클릭된 카드를 타겟카드에 넣어주고, 해당 카드 click이라는 클래스를 삽입해 클릭된 카드임을 알 수 있도록 해줍니다.

cards.addEventListener('click', (e) => {
  let targetCard = e.target;
  //카드를 선택했을때만 작동되도록
  if (targetCard.parentNode.className === 'card' && secondCard === 0) {
    targetCard.parentNode.classList.add('click');
    let targetCardId = targetCard.parentNode.id;
    openCard(targetCardId);
  }
});

클릭된 카드의 id를 targetCardId로 넘겨주고, openCard() 메서드를 호출해 targetCardId를 가지는 카드를 오픈합니다.

4.2 카드 비교하기

두번째 카드가 공개되면 matchCard()메서드를 호출해 두 카드를 비교합니다. 두 카드의 이미지가 같은 경우 카드가 오픈된 상태로 두고, 이미지가 다른 경우에는 두 카드를 다시 뒤집어야 합니다.

let matchArr = [];

맞춘 카드들을 담아둘 matchArr 배열을 선언해줍니다.

function matchCard(first, second) {
  if (first.dataset.img === second.dataset.img) {
    matchArr.push(first, second);
  } else {
   // 카드 뒤집기
  }
  firstCard = 0;
  secondCard = 0;
}

dataset

사용자는 원하는 속성을 data-속성의 형식으로 특정 요소에 지정해 사용할 수 있습니다. data-속성으로 시작되는 속성들은 dataset이라는 속성을 통해 접근합니다.

first.dataset.img === second.dataset.img

data-img로 img속성에 이미지 이름을 넣어주고, 이를 통해 카드 이미지를 비교해주었습니다.

4.3 카드 불일치 애니메이션 효과

 setTimeout(() => {
      first.animate(keyframes, options);
      second.animate(keyframes, options);
    }, 1000);
let keyframes = [
  { transform: 'rotate(3deg)' },
  { transform: 'rotate(-3deg)' },
  { transform: 'rotate(5deg)' },
  { transform: 'rotate(-5deg)' },
];
let options = {
  duration: 300,
  easing: 'ease-in',
};

rotate를 이용해 카드가 양 옆으로 진동하는듯한 느낌을 주었습니다.

4.4 게임종료

맞춘 이미지들을 담아두는 matchArr 배열에 모든 카드가 들어온 경우 게임을 종료합니다.

    if (matchArr.length === 24) {
      console.log('스테이지 완료');
      gameClearModal();
    }

0개의 댓글