ougi FE

javascript로 사과게임을 만들어보자! 본문

JavaScript

javascript로 사과게임을 만들어보자!

ougi 2025. 1. 8. 00:17
728x90

안녕하세요 오늘은 제가 최근에 제가 좋아하는 게임인 사과게임을 따라서 만들어보았는데 

이 게임을 만드는 과정에 대해서 글을 써보고 싶어 이렇게 글을 써보게 되었습니다

저는 토마토 버전으로 만들어보았습니다 ㅎㅎ


사과 게임 소개

사과게임이란 주어진 시간 안에 랜덤한 숫자 값이 들어있는 사과들을 없애는 것이 목표인 게임인데 

사과를 없앨 수 있는 조건은 드래그 해서 생긴 네모 칸 안에 숫자 값들이 합해서 10이 되는게 조건입니다

사과 한개 당 1점을 받습니다


만드는 과정 

과정을 나누어 보자면 크게 이렇게 나누어 구현 했던 것 같습니다

  1. 시간 타이머 바 구현하기
  2. 토마토들에 1-9까지 랜덤한 값을 주어 canvas에 그리기
  3. 드래그하면 네모 칸 만들어지게 하기
  4. 네모 칸 안에 숫자들이 10 되는지 확인하고 되면 사과를 없애고 점수 올라가게 구현하기

시간 타이머 바 구현하기

실제 구현된 타이머
const maxGage = document.querySelector(".max"); // 최대 게이지
const currentGage = document.querySelector(".cur"); // 현재 게이지 
let time = 100; // 남은 시간

function countDown() {
  setInterval(() => {
    currentGage.style.height = `${time}%`; // 현재 게이지의 높이 시간%로 업데이트
    time--;
    if (time === 0) { // 시간이 다 지나면 점수 알려주고 다시 초기화
      alert("Game Over! " + curScore + "점을 획득하셨습니다.");
      location.reload();
    }
  }, 1000);
}

document.addEventListener("DOMContentLoaded", () => { // load 되면 바로 count
  countDown();
});

 

 

 

토마토들에 1-9까지 랜덤한 값을 주어 canvas에 그리기

function drawTomatoes() { 
  tomatoes.forEach(({ x, y, number }) => { // 구조 분해 할당
    const tomatoSize = 52; // 토마토 크기
    ctx.drawImage(tomato, x, y, tomatoSize, tomatoSize); // 토마토 그리기

    ctx.font = "20px"; // 글씨 크기
    ctx.fillStyle = "white"; // 글씨 색
    ctx.textAlign = "center"; // 수평 가운데 정렬
    ctx.textBaseline = "middle"; // 수직 가운데 정렬

    const numberX = x + tomatoSize / 2; // 숫자 x 위치
    const numberY = y + tomatoSize / 2; // 숫자 y 위치
    ctx.fillText(number, numberX, numberY); // 글자 그리기
  });
}

function drawCanvas() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawTomatoes();
}

// 토마토 초기화
tomato.onload = () => {
  const canvasWidth = 800;
  const canvasHeight = 500;
  const margin = 8;

  canvas.width = canvasWidth * (window.devicePixelRatio || 1);
  canvas.height = canvasHeight * (window.devicePixelRatio || 1);
  canvas.style.width = `${canvasWidth}px`;
  canvas.style.height = `${canvasHeight}px`;
  ctx.scale(window.devicePixelRatio || 1, window.devicePixelRatio || 1);

  const tomatoSize = 52;
  const rows = Math.floor((canvasHeight - margin) / (tomatoSize + margin));
  const cols = Math.floor((canvasWidth - margin) / (tomatoSize + margin));

  for (let row = 0; row < rows; row++) {
    for (let col = 0; col < cols; col++) {
      const x = col * (tomatoSize + margin) + margin;
      const y = row * (tomatoSize + margin) + margin;

      const randomNumber = Math.floor(Math.random() * 9) + 1; // 1~9
      tomatoes.push({ x, y, number: randomNumber });
    }
  }

  drawCanvas();
};

 

드래그 이벤트 감지해서 네모 칸 만들고 점수 계산하기

// 드래그 시작 
canvas.addEventListener("mousedown", (e) => {
  drag = true;
  const rect = canvas.getBoundingClientRect();
  startX = e.clientX - rect.left;
  startY = e.clientY - rect.top;
});

// 드래그 중
canvas.addEventListener("mousemove", (e) => {
  if (drag) {
    const rect = canvas.getBoundingClientRect();
    curX = e.clientX - rect.left;
    curY = e.clientY - rect.top;

    drawCanvas();

    ctx.strokeStyle = "red";
    ctx.lineWidth = 2;
    ctx.strokeRect(
      Math.min(startX, curX),
      Math.min(startY, curY),
      Math.abs(curX - startX),
      Math.abs(curY - startY)
    );
  }
});

// 드래그 완료
canvas.addEventListener("mouseup", () => {
  drag = false;

  // Calculate the rectangle bounds
  const rectX = Math.min(startX, curX);
  const rectY = Math.min(startY, curY);
  const rectWidth = Math.abs(curX - startX);
  const rectHeight = Math.abs(curY - startY);

  // 안에 있는 토마토만 거르기
  const insideTomatoes = tomatoes.filter(({ x, y }) => {
    const tomatoSize = 52;
    return (
      x >= rectX &&
      x + tomatoSize <= rectX + rectWidth &&
      y >= rectY &&
      y + tomatoSize <= rectY + rectHeight
    );
  });

  // 더하기
  const sum = insideTomatoes.reduce((acc, cur) => acc + cur, 0);

  // sum이 10인지 확인
  if (sum === 10) {
    // 지우기
    const remainingTomatoes = tomatoes.filter(
      (tomato) => !insideTomatoes.includes(tomato)
    );

    // 점수 업데이트
    curScore += insideTomatoes.length;
    score.textContent = curScore;

    tomatoes.length = 0;
    tomatoes.push(...remainingTomatoes); // 남은 토마토 다시 넣기

    drawCanvas();
  }
  drawCanvas();
});

 


글을 마치며 

제가 만든 토마토 게임의 링크 https://tomato-game-kappa.vercel.app

 

진짜 사과게임의 링크https://www.gamesaien.com/game/fruit_box_a/

 

無料ゲーム「フルーツボックス」

画面上をマウスでドラッグして、数字の合計が10になるようにリンゴを囲むパズルゲームです。(説明) iPhone/iPadやAndroidスマホ/タブレットでも動作します。

www.gamesaien.com

 

참고한 글 https://github.com/Yejin-Han/peach_game

 

GitHub - Yejin-Han/peach_game: javascript, canvas를 활용한 복숭아 모으기 게임입니다.

javascript, canvas를 활용한 복숭아 모으기 게임입니다. Contribute to Yejin-Han/peach_game development by creating an account on GitHub.

github.com

 

JS로 게임은 처음 만들어본 것인데 만드는 동안 꽤 재미를 많이 느꼈던 것 같습니다

글을 읽어주셔서 감사합니다

 

728x90