[HTML/canvas] 장애물을 피해 마우스 움직이기 게임

미리보기

🔺마우스로 장애물 사이를 지나간다.



🔺장애물을 건드리면 게임종료



개요

  1. 순서
    A. 마우스로 장애물 사이를 지나간다.
    B. 장애물을 건드리면 게임종료
    C. 확인창에서 확인 누를 경우(restart?)
    1. 재시작
      • 장애물 새로 생성
      • 마우스 위치 초기화
    2. 종료
      • 애니메이션 종료



코드

// 마우스로 구멍 피하기 게임

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

// 구멍
const holeRadius = 30;
const totalHoles = 30;

let requestId;
let isGameOver = false;
let user;
let holeArray = [];

canvas.addEventListener("mousemove", handleMouseMove);

function handleMouseMove(event) {
  if (!isGameOver) {
    user.mouseX = event.clientX - canvas.offsetLeft;
    user.mouseY = event.clientY - canvas.offsetTop;
  }
}

addEventListener(
  "touchmove",
  (e) => {
    if (!isGameOver) {
      e.preventDefault(); // 기본 동작 실행하지 않도록 지정
      user.mouseX = e.touches[0].clientX;
      user.mouseY = e.touches[0].clientY;
    }
  },
  { passive: false },
);

function generateHole(amount) {
  for(let i=0; i<amount; i++) {
    holeArray[i] = new Hole(generateColor());
  }
}

function generateColor() {
  let hexSet = "0123456789ABCDEF";
  let finalHexString = "#";
  for(let i=0; i<6; i++) {
      finalHexString += hexSet[Math.ceil(Math.random() * 15)];
  }
  return finalHexString;
}

// 구멍 클래스
function Hole(color) {
  this.x = Math.random() * canvas.width;
  this.y = Math.random() * canvas.height;
  this.color = color

  this.draw = () => {
    ctx.beginPath();
    ctx.arc(this.x, this.y, holeRadius, 0, 2 * Math.PI);
    ctx.fillStyle = this.color; // Green color
    ctx.fill();
  }
}

generateHole(totalHoles);

// 사용자 클래스
function User() {
  this.mouseX = 0;
  this.mouseY = 0;
  this.img = new Image();
  this.img.src = "images/user_dot.jpg";

  // 마우스(이미지) 이동
  this.move = () => {
    ctx.drawImage(this.img, this.mouseX, this.mouseY, this.img.width, this.img.height);
  };

  // 충돌 검사
  this.checkCollision = (hole) => {
    let distance = Math.sqrt(Math.pow(this.mouseX - hole.x, 2) + Math.pow(this.mouseY - hole.y, 2));
    if (distance < user.img.width + holeRadius) {
        return true;
    }
    return false;
  };

  this.mouseInit = () => {
    this.mouseX = 0;
    this.mouseY = 0;
  }
}

user = new User();

// 애니메이션 처리
function anim() {
  requestId = requestAnimationFrame(anim);

  // 화면 비우기
  ctx.clearRect(0,0,canvas.width, canvas.height);

  // 구멍 그리기
  holeArray.forEach((hole) => {hole.draw();});

  user.move();

  // 충돌 검사
  for(const hole of holeArray) {
    if(user.checkCollision(hole)) {
      gameOver();
      break;
    }
  }
}

anim();

function gameOver() {
  console.log('call geme over');

  if(confirm("You DIE! restart?") == true) {
    resetGame();
  } else {
    cancelAnimationFrame(requestId);
    isGameOver = true;
  }
}

function resetGame() {
  isGameOver = false;
  holeArray = [];
  generateHole(totalHoles);
  user.mouseInit();
}