Javascript를 활용한 벽돌깨기3

박태현·2022년 7월 27일

Javascript

목록 보기
4/8
/*
    클래스 (class)

    함수 생성자 constructor
*/

// class로 객체의 설계도를 만든다. 
// 명사로 지칭되는 객체를 설계한다. ex : 자동차, 책, 몬스터, 사람....등  constructor안에 (속성과 기능)으로 표현한다.
class Brick {
    constructor(left, top, right, bottom, color) {
        this.left = left;
        this.top = top;
        this.right = right;
        this.bottom = bottom;
        this.isAlive = true;
        this.color = color;
    }

    draw() {
        if (this.isAlive) 
        {    
            context.rect(this.left, this.top, brickWidth, brickHeight);
            context.fillStyle = this.color;
            context.fill();
        }
    }
}

// constructor(left, top, right, bottom) {  // 이부분을 쓰지 않기 위해 Brick을 상속 해준다. extends Brick
    //     this.left = left;
    //     this.top = top;
    //     this.right = right;
    //     this.bottom = bottom;
    // }

class MovingBrick extends Brick{

    movingAction () {
        this.left++; 
        // console.log('내가 움직이고 있어');
    }
}

const canvas = document.getElementById('myCanvas');        //아이디를 가지고 특정 태그에 접근을 한다.
const context = canvas.getContext('2d'); 
canvas.style.backgroundColor = "aqua";

//게임 진행 관련
let deadBricksCount = 0;

// 벽돌 관련
const brickWidth = 50;  // 간격은 10
const brickHeight = 25; // 간격 5
const brickColumn = 4;  // 열
const brickRow = 5;     // 핼
let bricks ;  // 벽돌전체
// let bricks = [];
// let brickCount = brickColumn * brickRow;

// 장애물 관련
const wallWidth = 50;
const wallHeight = 20;
let wallPosX = 200;
let wallPosY = 200;
let wallMoveDirX = -1;
let wallMoveSpeed = 1;

let wall = {
    left:200, right:250, top:200, bottom:220, //함수안에서 변수들을 바꿔줘야한다.
};

// 볼 관련
const arcRadius = 20;
let arcPosX = 200;
// let arcPosY = canvas.height / 2 + 150;
let arcPosY = 370;
let arcMoveDirX = -1;
let arcMoveDirY = 1;                          // -1을 주면 Y가 위로 움직인다.    
let arcMoveSpeed = 3;

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

// let brick = {
//     left:0 , right:0, top:0, bottom:0, 
//     column:0, row:0, // 몇번째 열,행에 있는 것을 표현 할 수 있는 index
// }

// 패들 관련
const barWidth = 200;
const barHeight = 20;
let barPosX = canvas.width / 2 - barWidth / 2;
let barPosY = canvas.height - barHeight;
let barMoveSpeed = 20;

// 가운데가 0.0

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

// 키처리 함수 추가

document.addEventListener('keydown', keyDownEventHandler);   // 이벤트가 잇을때 해당함수를 호출해준다.
document.addEventListener('keyup', keyUpEventHandler);

// 함수 모음
function keyDownEventHandler(e)
{
    if (e.key == 'ArrowRight')
    {
        // 바를 오른쪽으로 이동
        if (barPosX + barWidth < canvas.width)
        {
            barPosX += barMoveSpeed;
            //1
        }       
    }
    else if (e.key == 'ArrowLeft')
    {
        // 바를 왼쪽으로 이동
        if (barPosX > 0)
        {
            barPosX -= barMoveSpeed;
            //1 
        }
    }

    //2 코드가 많이 중복되면 함수를 빼던가 연산량이 많지않으면 한번에 써주는 것이 좋다.
    paddle.left = barPosX;
    paddle.right = barPosX + barWidth;
    paddle.top = barPosY;
    paddle.bottom = barPosY + barWidth;
}

function keyUpEventHandler()
{
    
}

function gameWin ()
{
    if(brickCount == 0)
    {
        window.location.reload(true);
        alert('gamewin');
    }
}

function gameOver ()
{
    if(arcPosY > 370)
    {
        window.location.reload(true);
        alert('gameover');
    }
}

function update()
{
    // 데이터 수정 (도형의 위치 이동)
    if (arcPosX - arcRadius  < 0) //arcPosX - 50 원의 좌측끝
    {
        arcMoveDirX = 1;
    } 
    else if (arcPosX + arcRadius > canvas.width)  // arcPosX + 50 원의 우측 끝
    {  
        arcMoveDirX = -1;
    }

    if (arcPosY - arcRadius < 0) 
    {
        arcMoveDirY = 1;
    } 
    else if (arcPosY + arcRadius > canvas.width) 
    {
        arcMoveDirY = -1;
    }
// 벽돌 움직이기 
    if (wallPosX + 50 > canvas.width)
    {
        wallMoveDirX = -1;
    }
    else if (wallPosX < 0){
        wallMoveDirX = 1;
    }
    arcPosX += arcMoveDirX * arcMoveSpeed;
    arcPosY += arcMoveDirY * arcMoveSpeed;
    wallPosX += wallMoveDirX * wallMoveSpeed;
    

    ball.left = arcPosX - (arcRadius); // 위치가 계속 바낄때마다 바낀다.
    ball.right = arcPosX + (arcRadius); // 위치가 계속 바낄때마다 바낀다.
    ball.top = arcPosY - (arcRadius); // 위치가 계속 바낄때마다 바낀다.
    ball.bottom = arcPosY + (arcRadius); // 위치가 계속 바낄때마다 바낀다.

    // 벽돌이 움직이기 위한 
    wall.left =  wallPosX ;     // 시작지점 0.0
    wall.right = wallPosX + 50 ; 

    
    

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

    if (isCollisionRectToRect(ball, wall))
    {
			  // 위치를 바꾸는 동작
        arcMoveDirY = -1 * arcMoveDirY;
        arcMoveDirX = -1 * arcMoveDirX;
    }
    
    for (let i = 0; i < brickRow; i ++) 
    {
        for(let j = 0; j < brickColumn; j++) 
        {
            if (bricks[i][j].isAlive && isCollisionRectToRect(ball, bricks[i][j]))
            {
                 // 벽돌을 안보이게 하던지, 위치를 바꾸던지, ball의 방향 변경
                // console.log('i : ', i, 'j', j); // 
                bricks[i][j].isAlive = false; // 중복해서 찍히지 않게 해준다.
                arcMoveDirY = -arcMoveDirY;
                // brickCount--;

                deadBricksCount++;
                checkToWin();
                // if (deadBricksCount == brickRow * brickColumn)
                // {
                //     // 게임 클리어
                // }
                break;
            }
        }
         gameOver();
         // gameWin();
    }
}

function checkToWin() 
{
    // 1. bricks배열에 있는 정보로 처리

    // let bricks = [];
    // bricks[0] = [];
    // bricks[1] = [];
    // bricks[2] = [];
    // bricks 안의 요소를 가져오면 bricks는 배열이다.

    let flatBricks = bricks.flat();
    // console.log(flatBricks);
    // 
    let deadBricks = bricks.flat().filter(brick => brick.isAlive == false); // map쓰는 것과 비슷하다. 조건을 확인해서 해당 조건에 만족하는 것들로 다시 선언해준다.
    if(deadBricks.length == brickRow * brickColumn)
    {
        // 게임 클리어
        alert("게임클리어");
    }

    // 2. 카운트를 세는 변수를 만들어서 처리
    // if (deadBricksCount == brickRow * brickColumn)
    // {
    //     // 게임 클리어
    // }
}
//충돌 bricks[0][0] bricks[0][1]
function isCollisionRtToRect(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;
}

// bricks 와 ball이 충돌 했을때 없어지게 해야한다. + 2중 충돌 한번 충돌시 색상변경

function draw()
{
    // 화면 클리어
    context.clearRect(0, 0, canvas.width, canvas.height);
    drawCanvas();   
    // 다른 도형 그리기
    
    drawRect();
    drawArc();
    drawBricks();
    drawWall();
}

function drawCanvas() {
    context.beginPath();
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = '#CA9B89';
    context.fill();
    context.closePath();
}

function drawArc()  // 컴파일 순간에 내용물이 정해지고 호출된 시점에 사용이 된다. 
{   
    context.beginPath();
    context.arc(arcPosX, arcPosY, arcRadius, 0, 2 * Math.PI);
    context.fillStyle = 'blue';
    context.fill();
    context.closePath();
}

function drawWall()
{
    context.beginPath();
    context.rect(wallPosX, wallPosY, wallWidth, wallHeight);
    context.fillStyle = 'black';
    context.fill();
    context.closePath();
}

function drawRect()
{
    context.beginPath();

    // context.rect(canvas.width / 2, canvas.height / 2, 100, 100);                         // 가운데 좌표
    context.rect(barPosX, barPosY, barWidth, barHeight);   //      
    context.fillStyle = 'red';
    context.fill();
    
    context.closePath();
}

function setBricks() 
{
    bricks = [];

    
    for(let i = 0; i < brickRow; i++) //  가로 5 줄 
    {
        bricks[i] = [];
        for(let j = 0; j < brickColumn; j++)   // 세로 4줄
        {
            
            // TODO : right : left + 50 해보기
            // bricks[i][j] = { //2차원 배열안의 요소에 접근을 해야 left,right,top,bottom,
            //     left:55 + j * (brickWidth + 30), // 시작위치(왼쪽에서 얼마나 뛰어서 시작할건가) + j  * (벽돌위치 + 각각의 간격)
            //     right:55 + j * (brickWidth + 30) + 50, 
            //     // right:this.left + 50,  // this.left는 left가 값으로 변경되기 전인지 후인지 알수 없다. 
            //     top:30 + i * (brickHeight + 10),
            //     bottom:30 + i * (brickHeight + 10) + 25, 
            //     column:i, row:j,
            //     isAlive:true
            // };

            bricks[i][j] = new Brick(   55 + j * (brickWidth + 30), // left
                                        30 + i * (brickHeight + 10), // top
                                        55 + j * (brickWidth + 30) + 50, // right
                                        30 + i * (brickHeight + 10) + 25, // bottom
                                        'green'
                                    );
        }
    }
}

// 위에는 데이터 값만 지정을 해준 것이고 그 데이터 값을 그려줘야한다. drawBricks
function drawBricks() 
{
    context.beginPath();
    for(let i = 0; i < brickRow; i++) 
    {
        for(let j = 0; j < brickColumn; j++)   
        {
            bricks[i][j].draw();
        }
    }
    context.closePath();
}

setBricks();
setInterval(update, 10);   // 1000=1초, 10=0.01초 호출
setInterval(draw, 10);
const wallWidth = 50;
const wallHeight = 20;
let wallPosX = 200;
let wallPosY = 200;
let wallMoveDirX = -1;
let wallMoveSpeed = 1;
profile
꿈을 찾는 Frontend 개발자 입니다.

0개의 댓글