[TIL] #06 JavaScript - Mission

DamHo Bae·2021년 1월 20일
0
post-thumbnail

⛳ JavaScrip으로 2D 벽돌뿌시기 게임을 만들어보자.

🌎 Intro


  • 하단바를 이용해 벽돌을 뿌시면 점수를 얻는 게임.
  • 목숨은 3개로 지정.

게임은 <canvas> 엘리먼트에 렌더링된다.
 <style>
    	* { padding: 0; margin: 0; }
    	canvas { background: #eee; display: block; margin: 0 auto; }
    </style>
  <canvas id="myCanvas" width="480" height="320"></canvas>
<script>
	// JavaScript 코드가 여기에 들어갈 것이다.
</script>
</body>  

캔버스 속성으로 id값을 myCanvas를 하고 너비 480, 높이 320으로 지정했다.

🚗 캔버스 기본


idheight 속성을 canvas엘리먼트에서 정의한다.
var 함수 getElementById로 아이디값을 넣어준다.
그리고 나서는 캔버스에 그리기 위해 실질적으로 사용되는 도구인 2D rendering contextctx 변수에 저장해야한다.


ctx.beginPath();
ctx.rect(20, 40, 50, 50); //직사각형 정의(처음 두값은 좌상단 좌표 의미, 나머지 두 값은 너비와 높이를 의미)
ctx.fillStyle = "#FF0000"; //사각형 빨간색으로
ctx.fill(); //색상 값을 갖는다.
ctx.closePath();
ctx.beginPath();
ctx.arc(240, 160, 20, 0, Math.PI*2, false);
ctx.fillStyle = "green";
ctx.fill();
ctx.closePath();

위 코드에서 arc()메서드: 6개의 파라미터를 갖는다.

  • 원의 중심을 가리키는 xy좌표
  • 시작 각도와 끝 각도
  • 그리는 방향(false를 넣으면 시계방향 / 기본 값이나 true를 넣으면 반시계 방향)

ctx.beginPath();
ctx.rect(160, 10, 100, 40);
ctx.strokeStyle = "rgba(0, 0, 255, 0.5)";
ctx.stroke();
ctx.closePath();

fill()을 사용해서 원에 색상을 채울 수 있다면, stroke()를 이용하면 원의 외곽선에 색상을 부여할 수 있다.


🎉 Result

나는 캔버스의 속성을 알게되었다. 두 번째 챕터로 넘어가서 게임에서 공을 움직이기위해 어떻게 해야하는지 계속 알아보겠다.


🚀 드로잉 루프를 정의하다.

  • 캔버스에 그리는것을 지속적으로 갱신하기 위해서는, 계속해서 그리는 것을 반복하게 만들어주는 함수가 필요하다. 매 프레임마다 위치를 바꿔주기 위한 몇가지 변수들을 포함한다.

  • JavaScript 타이밍 함수인 setInterval() 이나 requestAnimationFrame() 를 이용하면 함수를 몇번이고 계속해서 반복 할 수 있다고 한다.

  • 다시 script태그에서 처음 두 줄만 제외하고 나머지는 모두 지운다.

function draw() {
    // drawing code
}
setInterval(draw, 10);

무한히 작동되는 setInterval 함수 덕에, 여기서 draw() 함수는 우리가 멈추기 전 까지 10밀리초마다 영원히 호출된다.

ctx.beginPath();
ctx.arc(50, 50, 10, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();

이제 위에서 이 코드로 수정해본다. 그럼 공은 매 프레임마다 다시 그려지게 될 것이다.

🔎 (1) 동적이게 만들어보기

  • 공이 움직이지 않고 있기 때문에,
    공이 다시 그려지고 있다는 사실을 아직 알 수 없다.
    이제 공을 움직이게 바꿔 볼 것이다. 첫번째로

ctx.arc(50, 50, 10, 0, Math.PI*2);

(50,50)이라는 좌표 대신에, xy라는 변수를 이용하여 하단 중앙에서 그려지게 하겠다.
xy를 정의하기 위해서 다음 두 줄을 추가 한다.

var x = canvas.width/2;
var y = canvas.height-30;

그 다음 draw() 함수를 갱신 할 것이다. arc()메소드안에서 xy변수를 사용.

function draw() {
    ctx.beginPath();
    ctx.arc(x, y, 10, 0, Math.PI*2);
    ctx.fillStyle = "#0095DD";
    ctx.fill();
    ctx.closePath();
}

공을 움직이는 것을 표현하기 위해 xy에 작은 값을 매 프레임마다 더해줄 것이다.
그 작은 값을 dxdy라 정의하고, 각각 2-2로 값을 정해보겠다.

var dx = 2;
var dy = -2;

dxdy변수를 이용해서 매 프레임마다 xy변수를 갱신해 준다. draw()함수에 추가하면

function draw() {
    ctx.beginPath();
    ctx.arc(x, y, 10, 0, Math.PI*2);
    ctx.fillStyle = "#0095DD";
    ctx.fill();
    ctx.closePath();
    x += dx;
    y += dy;
}

여기까지 하면 공을 움직이는데는 이상이 없다. 하지만 뒤에 흔적을 지우기 위해서 코드를 수정해야할것이다.

🔎(1-2) 다음 프레임 전에 캔버스를 지우다.

  • 공이 흔적을 남기는 것은, 매 프레임마다 공을 그릴 때 이전 프레임을 지워주지 않았기 때문.
  • 캔버스의 내용들을 지워주기 위한 메소드인 clearRect() 이 메소드는 네 개의 파라미터가 필요하다. 직사각형의 좌상단 모서리를 표시할 xy좌표, 우하단 모서리를 표시할 xy좌표가 있다.
    function draw() {
        ctx.clearRect(0, 0, canvas.width, canvas.height); //0,0 =좌상단, width.height는 우하단 모서리
        ctx.beginPath();
        ctx.arc(x, y, 10, 0, Math.PI*2);
        ctx.fillStyle = "#0095DD";
        ctx.fill();
        ctx.closePath();
        x += dx;
        y += dy;
    }

📝 코드를 정리하기

  • draw()함수와 공을 움직이는 코드를 분리시킨다.
    현재의 draw()함수를 두개로 쪼개볼까?

👉🏻 자바스크립트 태그안에 총 정리를 하면 다음과 같다.

<script>
    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");
    var x = canvas.width/2;
    var y = canvas.height-30;
    var dx = 2;
    var dy = -2;
function drawBall() {
    ctx.beginPath();
    ctx.arc(x, y, 10, 0, Math.PI*2);
    ctx.fillStyle = "#0095DD";
    ctx.fill();
    ctx.closePath();
}
function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawBall();
    x += dx;
    y += dy;
}
setInterval(draw, 10);
</script>

결과 🎬

공을 움직이는 코드를 일단 성공해봤다. 이게 첫시작이다...
내용이 너무 길면 보는사람도 지루해 할 수 있기에 중요부분만 정리해야겠다.
( ͡° ͜ʖ ͡°)_/¯

📝 여기까지 내가 알게 된 점 :

캔버스란 ?

  • HTML5의 canvas 엘리먼트는 단지 그래픽들을 위한 컨테이너
  • 당신은 그래픽을 그리기 위해 자바스크립트를 사용해야함
  • idheight 속성을 canvas 엘리먼트로 정의한다.
  • canvasX Y좌표는 캔바스에서 그리는데 있어서 위치를 나타내는데 사용한다.

setInterval()함수 : 지정한 밀리초마다 영원히 호출 시킴. (타이밍 함수 라는것)

fill()을 사용해서 원에 색상을 채울 수 있다면,stroke()를 이용하면 원의 외곽선에 색상을 부여

arc()메서드: 6개의 파라미터를 갖는다.

  • 원의 중심을 가리키는 xy좌표
  • 시작 각도와 끝 각도
  • 그리는 방향(false를 넣으면 시계방향 / 기본 값이나 true를 넣으면 반시계 방향)

캔버스의 내용들을 지워주기 위한 메소드인 clearRect()
clearRect()는 매 프레임마다 그릴때 이전 프레임을 지워주지 않았을 경우에 사용됨.


🙋🏻‍♂️ (2) 이번엔 공이 충돌 시에 벽에 닿는 느낌을 보여줄 것이다.


📢 간단한 충돌 감지

  1. 충돌을 감지하기 위해서는 공이 벽에 닿았는지 확인

✔ 위 아래 튕겨내기

  1. 그에 따라 움직이는 방향 수정
    변수를 하나 선언한다. ballRadius = 10; 원의 반지름 값을 대입하여 계산하는데 사용
    drawBall() func에서 ballRadius로 수정
    캔버스에는 총4개의 벽이 있다.
    캔버스 내 위치 구조는 좌상단부터 시작
  1. 공의 위치에서 좌상단부터 y값을 측정하기 때문에
    상단 모서리에서의 y값은 0, 하단에서의 y값은 480, 즉 캔버스의 높이값.
    y축 움직임의 반대 방향으로 튕겨낸다.
if(y + dy > canvas.height || y + dy < 0) {
 dy = -dy;
}

✔ 좌우로 튕겨내기

이번엔 상,하단이 아닌 좌우 모서리이다.

y값 대신 x값을 대입하여 반복

if(x + dx > canvas.width || x + dx < 0) {
    dx = -dx;
}
if(y + dy > canvas.height || y + dy < 0) {
    dy = -dy;
}

결과

img

다음과 같이 공이 벽을 튕겨나와 벽 안으로 숨어있다.

이 문제를 해결해보자.

원인:

  • 이 문제는 기준을 공의 원점으로 계산해서 그렇다. 원의 둘레를 기준으로 계산해야 옳다.

수정:

if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
    dx = -dx;
}
if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
    dy = -dy;
}

🎉 결과:


게임을 만들면서 점점 형태가 보여서 신기하기도 하다🙄

알게 된 점:

  • 캔버스에는 총 4개의 벽으로 부터 내 위치 구조는 좌상단부터 시작된다는점!!
  • y축 움직임의 반대 방향으로 튕긴다?
  • 좌우로 튕길때: y값 대신 x값을 대입하여 반복한다.
  • 공이 벽에 닿는 느낌이 아니고 벽안에 숨었을 경우,
    기준을 공의 원점이 아닌 원의 둘레로 계산을 해야한다는 점 참고해야겠다.

🏓 (3) 공을 치기 위한 패들 정의


우리는 공을 치기 위한 패들이 필요하다. 이를 위해 몇가지 변수를 정의 해보자!!

paddle 의 높이와 너비, x축의 위에 시작 지점을 정의하자!!
paddle 을 스크린에 그리는 함수를 만들자!!

var paddleHeight = 10;
var paddleWidth = 75;
var paddleX = (canvas.width-paddleWidth)/2;

✅ 유저의 패들 컨트롤

우리는 어디든 그릴 수 있지만, 사용자의 컨트롤에 반응을 해야겠다.

키보드 컨트롤을 구현해보자

  • 왼쪽, 오른쪽 컨트롤 버튼이 눌렸는지 확인하는 두개의 변수
  • 이벤트 리스너로 keydownkeyup 이벤트를 사용해 패들의 움직임을 조종할 수 있는 코드가 실행되어야함.
  • 버튼이 눌렸을 때 keydownkeyup 이벤트를 핸들링하는 두개의 함수

버튼을 누르는 것은 boolean 변수로 정의하고 초기화.
처음엔 버튼이 눌려지지 않은 상태이므로 기본값은 false 이다.

var rightPressed = false;
var leftPressed = false;

키가 눌렸음을 인식하기 위해 이벤트 리스너를 설정하겠다.

document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);
function keyDownHandler(e) { //키보드 중 어떤 키 하나를 누르면 keydown 이벤트 발생 -> keyDownHandler() 함수가 실행
    if(e.keyCode == 39) {
        rightPressed = true;
    }
    else if(e.keyCode == 37) {
        leftPressed = true;
    }
}
function keyUpHandler(e) {//키에서 손을 때면 keyup이벤트 -> keyupHandler()함수 실행
    if(e.keyCode == 39) {
        rightPressed = false;
    }
    else if(e.keyCode == 37) {
        leftPressed = false;
    }
}

각 변수에 키를 누르면 true / 키에서 손을 때면 false가 됨

이때 function 값에 e변수 를 적용해서 이벤트를 파라미터로 사용해보자.

keycode는 눌려진 키에 대한 정보를 가지고 있다. 예시로 왼쪽 방향이 37 오른쪽이 39이다. 만약에 왼쪽키를 누르면 leftPreseed 변수가 true 가 설정이 되고,

반대 오른쪽키를 누르면 rightPressed 변수에도 동일하게 적용된다.

🚕 패들을 화면에서 움직여보자!

각각의 프레임이 렌더링 될때마다 왼쪽 오른쪽 방향키가 눌렸는지 확인.

if(rightPressed && paddleX < canvas.width-paddleWidth) {
    paddleX += 7;
}
else if(leftPressed && paddleX > 0) {
    paddleX -= 7;
}

위 코드에서는 왼쪽키를 눌르면 패들은 좌측으로 7픽셀 움직이고,
반대로, 오른쪽키를 눌러도 7픽셀 움직인다. 키를 너무 오래 누를 경우에
패들이 캔버스 밖으로 사라질 수 있어 캔버스의 width값과 패들width를 계산해줘야한다.

  • paddleX 의 위치는 캔버스 왼쪽 끝 0 위치와 오른쪽 canvas.width-paddleWidth 에서 움직인다.

  • draw() 함수 안에서 drawPaddle()을 호출해준다.

하단바 생성

👏👏👏👏👏👏👏👏👏👏👏


(4) 🎮 GameOver기능 적용하기

게임오버 기능을 만들어보자.

벽에 공을 반사시키는 코드에서 수정

if(x + dx > canvas.width - ballRadius || x + dx < ballRadius){
	dx = -dx;
}
if(y + dy > canvas.height - ballRadius || y + dx < balllRadius){
	dy = -dy;
}

수정부분:

  • 사면 모두 공을 좌우,위쪽에만 적용시켜주고 아래에 닿는다면 게임over되게 해야한다.

  • 그래서 if문을 수정해보자!

  • 우선 경고 메시지를 주려면 alert("경고창")을 해야될텐데
    경고메시지를 보여주고 페이지를 리로딩하게 게임을 다시 시작할 것이다.

  • 그 과정에서는 location.reload()함수를 써보자 !

아래 코드를 참고해보자

  if(y + dy < ballRadius) {
    dy = -dy;
} else if(y + dy > canvas.height-ballRadius) {
    alert("GAME OVER");
    document.location.reload();
``` }

✔ 패들로 공을 튕겨내기

공이 밑면에 닿는 순간, 공이 패들의 안쪽에 있는지 확인해야한다.
만약 그렇다면, 공은 튕겨진다. 그게 아니라면, 게임의 전과 같이 끝내야함.

if(y + dy < ballRadius) {
    dy = -dy;
} else if(y + dy > canvas.height-ballRadius) {
    if(x > paddleX && x < paddleX + paddleWidth) {
        dy = -dy;
    }
    else {
        alert("GAME OVER");
        document.location.reload();
    }
}

결과: 👇🏻


🔨 (5) 벽돌에 대한 변수 설정


벽돌을 위한 코드를 2차원 배열 동작하는 반복문을 사용할것이다.

가로,세로,행,열 등 벽돌에 대한 값을 정의할 몇몇 변수들을 지정.

var brickRowCount = 3;
var brickColumnCount = 5;
var brickWidth = 75;
var brickHeight = 20;
var brickPadding = 10;
var brickOffsetTop = 30;
var brickOffsetLeft = 30;
  • 배열은 c, 행은 r, 화면에 벽돌을 그릴 위치를 나타낼 x,y위치를 가진다.
var bricks = [];
for(var c=0; c<brickColumnCount; c++) {
    bricks[c] = [];
    for(var r=0; r<brickRowCount; r++) {
        bricks[c][r] = { x: 0, y: 0 };
    }
}

배열을 담을 수 있는 bricks 함수를 만들었다.
그리고 이중for문으로 행과 열 수만큼 반복되는 벽돌을 만든다.

✔ 벽돌을 그리는 방법

배열안의 모든 벽돌을 반복해 화면에 그려줄 함수를 만들어보자.

function drawBricks() {
    for(var c=0; c<brickColumnCount; c++) {
        for(var r=0; r<brickRowCount; r++) {
            bricks[c][r].x = 0;
            bricks[c][r].y = 0;
            ctx.beginPath();
            ctx.rect(0, 0, brickWidth, brickHeight);
            ctx.fillStyle = "#0095DD";
            ctx.fill();
            ctx.closePath();
        }
    }
}

행,열 반복함으로써 x,y값을 설정, 캔버스에 brickwidth*brickHeight 크기의 벽돌을 그린다. 좌표는 0,0 위치해 있고, 연산을 통해 각 벽돌의 x,y값을 계산해야함

var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;

**brickX는brickWidth + brickPaddingc를 곱하고, brickOffsetLeft를 더한 값

brickY도 동일합니다. 이제 모든 벽돌들이 올바른 위치에, 알맞은 간격을 두었다.
캔버스 모서리부터 오프셋 값만큼 그릴 수 있게되었다.
brickXbrickY 값을 (0, 0) 대신 갑으로 할당하고 drawpaddle함수 아래에 추가.

drawBall() 함수를 fun draw()에 호출!!!**

🎉 결과:


여기까지 벽돌도 만들어보았다.
어느정도 틀이 잡힌 느낌이 든다. 이제 동적인 것과
유저의 컨트롤만 남았다. 화이팅하자 !!


💡 (6) 충돌 감지 함수

코드의 가독성을 향상시키기 위해 충돌 감지 반복문에서 b변수를 정의

function collisionDetection() {
    for(var c=0; c<brickColumnCount; c++) {
        for(var r=0; r<brickRowCount; r++) {
            var b = bricks[c][r];
            // calculations
        }
    }
}

만약, 공이 어떤 벽돌의 범위 내에 있을경우, 공의 방향을 바꾸게 된다.

공이 벽돌 안에 존재하려면, 4가지 조건이 참이어야 한다.

  • 공의 x 좌표는 벽돌의 x 좌표보다 커야 한다.
  • 공의 x 좌표는 벽돌의 x 좌표 + 가로 길이보다 작아야 한다.
  • 공의 y 좌표는 벽돌의 y 좌표보다 커야 한다.
  • 공의 y 좌표는 벽돌의 y 좌표 + 높이보다 작아야 한다.

이 조건을 코드로 작성해봅시다.

function collisionDetection(){
	for(var c = 0; c<brickColumCount; c++){
		for(var r=0; r<brickRowCount; r++){
			var b = brick[c][r];
			if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHight){
			dy = -dy;
			}
		}
	}
}

✔ 충돌 후에 벽돌을 사라지게 만들기

아직까지 공이 충돌시 벽돌이 제거되지 않는다.

변수를 선언해서 벽돌을 초기화를 코드에, status 속성을 각 벽돌 객체에 추가해보자

var bricks = [];
for(var c=0; c<brickColumnCount; c++) {
    bricks[c] = [];
    for(var r=0; r<brickRowCount; r++) {
        bricks[c][r] = { x: 0, y: 0, status: 1 };
    }
}

status 속성을 확인해야 한다. 만약 status가 1이라면 벽돌을 그리고, 만약 0이라면 이미 공이 치고간 벽돌이므로 그릴 필요가 없다.

function drawBricks() {
    for(var c=0; c<brickColumnCount; c++) {
        for(var r=0; r<brickRowCount; r++) {
            if(bricks[c][r].status == 1) {
                var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
                var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
                bricks[c][r].x = brickX;
                bricks[c][r].y = brickY;
                ctx.beginPath();
                ctx.rect(brickX, brickY, brickWidth, brickHeight);
                ctx.fillStyle = "#0095DD";
                ctx.fill();
                ctx.closePath();
            }
        }
    }
}

✔ 충돌 감지함수에서 상태 추적 및 업데이트

collisonDectection 함수에 벽돌 status 속성을 포함 시키자.
만약 벽돌 활성 상태시 (status 1)이라면 추우돌이 일어났는지 확인해야한다.
만약 충돌이 발생했다면 다시 그리지 않게 벽돌의 속성을 0으로 변경

function collisionDetection(){
	for(var = c=0; c<brickCoulumCount; c++){
		for(var = r=0; r<brickRowCount; r++){
			var b = bricks[c][r];
			if(b.status == 1){
				if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight){
				dy = -dy;
				b.status = 0;
				}
			}
		}
	}
}

draw함수에서 collisionDetection()함수를 호출

🎉 실행결과:


🥇 (7) 점수계산

점수를 기록하려고 또 하나의 변수를 생성 할 것이다.
var score = 0;
drawScore()점수 표시를 만들고 업데이트 하는 기능 도 필요하다.

collistionDetection() 함수 뒤에 다음을 추가하자.

fucntion drawScore(){
	ctx.font = "16px Arial";
	ctx.fillStyle = "#0095DD";
	ctx.fillText("Score:" +score, 8, 20);
}
  • fileText()설정하고 캔버스에 배치 할 실제 텍스트와 배치 할 위치를 설정

  • 첫번째 매개 변수는 텍스트 자체. 현재 포인트 수를 보여준다, 마지막 두 매개 변수는 텍스트가 캔버스에 배치 될 좌표

drawPaddle()호출 바로 아래에 추가한다.

function collisionDetection() {
    for(var c=0; c<brickColumnCount; c++) {
        for(var r=0; r<brickRowCount; r++) {
            var b = bricks[c][r];
            if(b.status == 1) {
                if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
                    dy = -dy;
                    b.status = 0;
                    score++;
                }
            }
        }
    }
}

🏆 (8) 모든 벽돌이 파괴되었을 때 승리 메시지를 표시

function collisionDetection() {
    for(var c=0; c<brickColumnCount; c++) {
        for(var r=0; r<brickRowCount; r++) {
            var b = bricks[c][r];
            if(b.status == 1) {
                if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
                    dy = -dy;
                    b.status = 0;
                    score++;
                    if(score == brickRowCount*brickColumnCount) {
                        alert("YOU WIN, CONGRATULATIONS!");
                        document.location.reload();
                        clearInterval(interval); // Needed for Chrome to end game
                    }
                }
            }
        }
    }
}

여기서 document.location.reload()기능은 페이지를 다시로드하고 경고 버튼을 클릭하면 게임을 다시 시작

🎉 결과:

공이 벽돌을 깨면 좌측 상단에 Score가 1이 올라가는걸 볼 수 있다.

벽돌 하나당 1점이다.


🚀 (9) 마우스 컨트롤

이미 키보드 컨트롤을 추가했지만, 마우스 컨트롤도 쉽게 추가 할 수 있다.

mousemove. 이벤트에 대한 리스너 생성하기!
document.addEventListener("mousemove", mouseMoveHandler, false);

✔ 패들 움직임을 마우스 움직임에 고정

function mouseMoveHandler(e) {
    var relativeX = e.clientX - canvas.offsetLeft;
    if(relativeX > 0 && relativeX < canvas.width) {
        paddleX = relativeX - paddleWidth/2;
    }
}
  • relativeX 뷰포트의 수평 마우스 위치

  • (e.clientX)에서 캔버스의 왼쪽 가장자리와 뷰포트의 왼쪽 가장자리 사이의 거리()를 뺀 값을 계산

  • canvas.offsetLeft 사실상 이것은 사이의 거리와 같다. 캔버스 왼쪽 가장자리와 마우스 포인터.
    상대 x포인터 위치가 0보다 크고 Canvas 너비보다 낮으면 포인터가 Canvas 경계 내에 있고 paddleX위치가 패들 relativeX 너비의 절반을 뺀 값으로 설정 움직임이 실제로 패들의 중앙을 기준으로 한다.

  • 패들은 이제 마우스 커서의 위치를 따르지만 캔버스의 크기로 이동을 제한하고 있습니다.


🍚 (10) 플레이어에게 생명을 주기

var lives = 3; //3개의 목숨을 준다.
수명 카운터를 그리는 것은 점수 카운터를 그리는 것과 같다.

drawScore()함수 아래에 추가

function drawLives() {
    ctx.font = "16px Arial";
    ctx.fillStyle = "#0095DD";
    ctx.fillText("Lives: "+lives, canvas.width-65, 20);
}
  • 게임을 즉시 종료하는 대신 더 몫이 끝날때까지 생명 수를 줄인다.

  • 다음 생을 시작하면 공과 패들 위치를 재설정 할 수도 있다.

lives--;
if(!lives) {
    alert("GAME OVER");
    document.location.reload();
    clearInterval(interval); // Needed for Chrome to end game
}
else {
    x = canvas.width/2;
    y = canvas.height-30;
    dx = 2;
    dy = -2;
    paddleX = (canvas.width-paddleWidth)/2;
}
공이 화면의 하단 가장자리에 닿으면 live변수에서 생명 1개를 뺀다.
남은 생명이 0이면 GameOver/ 아직 목숨이 남아 있으면 다시 재설정 됨

이제 다시 함수 drawrLives() 내부에 호출

requestAnimationFram()으로 렌더링 개선
requestAnimationFrame브라우저가 현재 setInterval(). 다음 줄을 바꾼다.
var interval = setInterval(draw, 10)
requestAnimationFrame(draw);
draw();


🎊 최종 결과물:



내 자기소개 페이지에 게임을 저장했다.
녹화중 렉이 생겼네..

2D게임이지만 이번 과제를 진행하면서 자바스크립트에 대해서
많이 알아가고 공부한것 같다. 추후엔 기능이 더 추가되는 멋진 게임을
만들고싶다.
노래추가 + 난이도 추가 + 랭킹등록 등,, 생각해 본것들은 많다.
그러기 위해서는 자바스크립트 공부를 열심히 해야겠다.

여기까지 읽어주셔서 감사합니다.


profile
Frontend Developer

0개의 댓글