[Javascript Basic] 03. 벽돌깨기 게임(6)

Jaewonee·2022년 4월 20일
0

벽돌깨기 게임

목록 보기
6/8

학습 목표

  • space bar를 눌렀을때 게임 시작하기
  • ball의 위치를 bar와 맞추고, 게임 시작전 같이 움직이도록 하기

spacebar로 게임 시작하기

ball이 움직이고 충돌을 일으키는 코드는 모두 function update() 안에 들어있다. 그리고 이를 실행시키는 함수는 setInterval(update, 10); 이다. 앞서 bar를 움직였던것과 마찬가지로 spacebar keydown시 코드가 실행되도록 keyDownEeventHandler() 함수 안에 코드를 넣어주자

// function keyDownEeventHandler(e) 안에 코드 추가

if(e.key == ' '){
  setInterval(update, 10);   
}

다만, 위와 같이 코드를 작성할 경우 spacebar를 여러번 누를시 해당 함수가 여러번 작동하여 ball의 속도가 빨라지는 오류가 발생한다. boolean값이 들어간 변수를 하나 선언해주고 조건문안에 넣어줌으로써 첫 event발생시에만 실행되도록 하여 이를 해결했다.

let startClick = true;

// function keyDownEeventHandler(e) 안에 코드 추가

if(e.key == ' ' && startClick ){
  setInterval(update, 10);   
  startClick = false;
}



Ball 코드 재설정

기존 코드에선 ball은 게임보드 중앙에서 Y축 아래 방향으로 출발했다. 아래쪽에 위치한 bar와 맞추기 위해 다음과 같이 기존에 선언했던 변수값을 수정했다.

// arc
const arcRaius = 20;
// 수정코드
let arcPosX = canvas.width / 2
let arcPosY = canvas.height - barHeight / 2 - arcRaius // bar위쪽에 맞추기 위해 반지름값만큼 빼줌\

//기존코드
//let arcPosX = canvas.width / 2;
//let arcPosY = canvas.height / 2;

// 방향에 대한 변수 설정
// ball
let arcMoveDirX = 1;
let arcMoveDirY = -1; // 1에서 -1로변경 (y축은 위쪽으로 가는게 음수)
let arcSpeed = 4;


위에서 ball을 고정 해두니 게임 시작전 bar만 움직이는 현상이 발생했다. spaceebar event가 발생하기전 ArrowRight, ArrowLeft event가 발생할때 ball과 bar에 같은 barMoveDirX 값을 증감 해주는 방식으로 접근했다.

function keyDownEeventHandler(e) {
  if (e.key == "ArrowRight" && barPosX + barWidth < canvas.width) {
    // 바를 오른쪽으로 이동
    barPosX += barMoveDirX;
    arcPosX += barMoveDirX
  } 
  else if (e.key == "ArrowLeft" && barPosX > 0) {
    // 바를 왼쪽으로 이동
    barPosX -= barMoveDirX;
    arcPosX -= barMoveDirX
  }

위와 같이 코드작성시 게임 시작 이후에도 bar를 움직일시 ball도 같이 움직이는 문제가 발생했다. 우선 ball과 bar의 함수를 분리했다. 이후 앞서 spacebar와 같은 접근방식으로 boolean값으로 선언된 변수를 if문에 넣어 주어 게임 시작후에도 움직이지 않도록 설정했다.
// function keyDownEeventHandler(e) 안에 새로 추가하기

if (e.key == "ArrowRight" && startClick && barPosX + barWidth < canvas.width
  ) 
	{
    arcPosX += barMoveDirX;
} 
else if (e.key == "ArrowLeft" && startClick && barPosX > 0){
    arcPosX -= barMoveDirX;
}

최종 코드

const canvas = document.getElementById("myCanvas"); // 이 아이디를 가지고 특정 탭에 접근을 한다
const context = canvas.getContext("2d"); // context라는 존재를 통해 그리기를 한다

// keydown
document.addEventListener("keydown", keyDownEeventHandler);
document.addEventListener("keyup", keyDownEeventHandler); // 자연스러움을 추가하기 위해 쓸 수 있다.

// bar
let barWidth = 250;
let barHeight = 40;
let barPosX = canvas.width / 2 - barWidth / 2;
let barPosY = canvas.height - barHeight / 2;

// arc
const arcRaius = 20;
let arcPosX = canvas.width / 2;
let arcPosY = canvas.height - barHeight / 2 - arcRaius; // bar위쪽에 맞추기 위해 반지름값만큼 빼줌
//let arcPosX = canvas.width / 2;
//let arcPosY = canvas.height / 2;

// 방향에 대한 변수 설정
// ball
let arcMoveDirX = 1;
let arcMoveDirY = -1; // 1에서 -1로변경 (y축은 위쪽으로 가는게 음수)
let arcSpeed = 4;

// bar
let barMoveDirX = 10;
let barSpeed = 40;

//객체생성
let ball = {
  left: 0,
  right: 0,
  top: 0,
  bottom: 0,
};

let paddle = {
  left: 0,
  right: 0,
  top: 0,
  bottom: 0,
};

// 블록만들기
const brickWidth = 50; // 간격 10
const brickHeight = 25; // 간격 5
const brickColumn = 5;
const brickRow = 4;
let brickArray = [];

// 외부 변수 선언
let clearCount = 0;
let startClick = true;

function setBricks() {
  for (let i = 0; i < brickRow; i++) {
    brickArray[i] = [];
    for (let j = 0; j < brickColumn; j++) {
      brickArray[i][j] = {
        // 여기 숫자 의미를 잘 파악해야한다
        left: 55 + j * (brickWidth + 10),
        right: 55 + j * (brickWidth + 10) + 50, //60으로 나중에 묶기
        top: 30 + i * (brickHeight + 5),
        bottom: 30 + i * (brickHeight + 5) + 25,
        row: j,
        column: i,
        isAlive: true, // 여기에 변수를 추가하는 개념
        test: 0,
      };
    }
  }
}

// ball과 bar가 만나지 않는 경우 설정
function isCollisionRectToRect(rectA, rectB) {
  // a의 왼쪽과 b의 오른쪽
  // a의 오른과 b의 왼쪽
  // a의 아래쪽과 b의 위쪽
  // a의 위쪽과 b의 아래쪽
  if (
    rectA.left > rectB.right ||
    rectA.right < rectB.left ||
    rectA.top > rectB.bottom ||
    rectA.bottom < rectB.top
  ) {
    return false;
  }
  return true;
}

// bar 움직이기
function keyDownEeventHandler(e) {
  if (e.key == "ArrowRight" && barPosX + barWidth < canvas.width) {
    // 바를 오른쪽으로 이동
    //console.log(alert("오른쪽 된다!"))
    barPosX += barMoveDirX;
    //arcPosX += barMoveDirX
  } else if (e.key == "ArrowLeft" && barPosX > 0) {
    //console.log(alert("왼쪽 된다!"))
    barPosX -= barMoveDirX;
    //arcPosX -= barMoveDirX
  }

  if (
    e.key == "ArrowRight" &&
    startClick &&
    barPosX + barWidth < canvas.width
  ) {
    arcPosX += barMoveDirX;
  } else if (e.key == "ArrowLeft" && startClick && barPosX > 0) {
    arcPosX -= barMoveDirX;
  }

  if (e.key == " " && startClick) {
    setInterval(update, 10);
    startClick = false;
  }

  paddle.left = barPosX;
  paddle.right = barPosX + barWidth;
  paddle.top = barPosY;
  paddle.bottom = barPosY + barHeight;
}

// ball 움직이기
function update() {
  if (arcPosX - arcRaius < 0) {
    arcMoveDirX = 1;
  } else if (arcPosX + arcRaius > canvas.width) {
    arcMoveDirX = -1;
  }

  if (arcPosY - arcRaius < 0) {
    arcMoveDirY = -1;
  } else if (arcPosY + arcRaius > canvas.height) {
    location.reload();
    alert("Game Over!!");
  }

  //arcSpeed+=0.01;
  arcPosX += arcMoveDirX * arcSpeed;
  arcPosY -= arcMoveDirY * arcSpeed;

  ball.left = arcPosX - arcRaius;
  ball.right = arcPosX + arcRaius;
  ball.top = arcPosY - arcRaius;
  ball.bottom = arcPosY + arcRaius;

  // 충돌확인
  if (isCollisionRectToRect(ball, paddle)) {
    arcMoveDirY = 1;
    //arcMoveDirX = -1;
    //arcPosY = paddle.top - arcRaius;
  }

  for (let i = 0; i < brickRow; i++) {
    for (let j = 0; j < brickColumn; j++) {
      if (
        brickArray[i][j].isAlive &&
        isCollisionRectToRect(ball, brickArray[i][j])
      ) {
        // console.log(i,j)
        brickArray[i][j].isAlive = false;
        arcMoveDirY = -1;
        clearCount++;
        console.log(clearCount);
        break; // 벽돌 중복으로 뿌서지는거 방지
      }
    }
  }

  if (clearCount == 20) {
    setTimeout(function () {
      alert("Clear!", location.reload());
    }, 100);
  }
}

// ==================================== 화면 그리기(도형) ======================================
function draw() {
  // 화면 클리어
  context.clearRect(0, 0, canvas.width, canvas.height);

  // 다른 도형 그리기
  drawBar();
  drawArc();
  drawBricks(); //블록 그리기 추가
}

// ball 그리기
function drawArc() {
  context.beginPath(); // 그리기를 시작하겠다
  // x    ,   y      , radius  , startAngle, endAngle
  context.arc(arcPosX, arcPosY, arcRaius, 0, 2 * Math.PI);
  context.fillStyle = "blue"; // 색깔 고르고
  context.fill(); // 채우기
  context.closePath(); // 그리기를 끝내겠다
}

// bar 그리기
function drawBar() {
  context.beginPath(); // 그리기를 시작하겠다
  //  x    ,    y   ,   width ,  height
  context.rect(barPosX, barPosY, barWidth, barHeight);
  context.fillStyle = "red"; // 색깔 고르고
  context.fill(); // 채우기
  context.closePath(); // 그리기를 끝내겠다
}

// block 그리기
function drawBricks() {
  context.beginPath();
  for (let i = 0; i < brickRow; i++) {
    for (let j = 0; j < brickColumn; j++) {
      if (brickArray[i][j].isAlive) {
        context.rect(
          brickArray[i][j].left,
          brickArray[i][j].top,
          brickWidth,
          brickHeight
        );
        context.fillStyle = "coral"; // 이때 색칠하는것을 for문 안에 넣느냐 마느냐로 블록색을 여러개로 줄 수 있다.
        context.fill();
      }
    }
  }
  context.closePath();
}

setInterval(draw, 10);
setBricks();
profile
🙋‍♂️블록체인 개발자 되기 / 📑 공부기록 공간

0개의 댓글

관련 채용 정보

Powered by GraphCDN, the GraphQL CDN