Javascript 벽돌깨기

정종찬·2022년 4월 20일
0

const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');

//벽돌 관련
const brickWidth = 50;  // 간격 10
const brickHeight = 25; // 간격 5
const brickColumn = 5;  // 열
const brickRow = 4;     // 행
let bricks = []; // 갯수가 정해져있다면. new Array(5) 

//볼 관련
const arcRadius = 10;
let arcPosX = canvas.width / 2 ;         // 다른언어는 멤버변수가 들어있어서 오타시 잡아줌  
let arcPosY = canvas.height - 30;
let arcMoveDirX = -1;                    // 원이 이동하는 방향 X축
let arcMoveDirY = -1;                    // 원이 이동하는 방향 Y축
let arcMoveSpd = 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,    
}

//패들관련
const barWidth = 100;
const barHight = 20; 
let barPosX = canvas.width / 2 - barWidth / 2;
// let arcPosX = barPosX + 50; 
let barPosY = canvas.height - barHight;
let barMoveSpd = 50;

let paddle = {
    left : barPosX, 
    right : barPosX + barWidth, 
    top : 380, 
    bottom : 400,    
}

// 키처리 함수 추가
document.addEventListener('keydown', keyDownEventHandler);
document.addEventListener('keyup', keyUpEventHandler);

//함수 모음
let setStart = false;
function keyDownEventHandler(e)
{
    if(e.key == ' ')    
    {
        // setInterval(() => {        
        // }, update);
        setStart = true
    }
    if(e.key == 'ArrowRight')
    {
        // updateRec();
        // 바를 오른쪽으로 이동
        if(barPosX + barWidth < canvas.width && setStart == false)
        {
            barPosX += barMoveSpd;
            arcPosX = barPosX + 50;
            //1번씩(2-1)
        }
        else if(barPosX + barWidth < canvas.width){
            barPosX += barMoveSpd;
        }        
    }    
    else if(e.key == 'ArrowLeft')
    {
        // updateRec();
        // 바를 왼쪽으로 이동
        if(barPosX > 0  && setStart == false)
        {
            barPosX -= barMoveSpd;
            arcPosX = barPosX + 50;
            //1번씩(2-2)
        }  
        else if(barPosX > 0 ){
            barPosX -= barMoveSpd;
        }       
    }

    //2에 1번(1) 연산량이 많을수도 있다. 
    paddle.left = barPosX;
    paddle.right = barPosX + barWidth;
    paddle.top = barPosY;
    paddle.bottom = barPosY + barHight;
}

function keyUpEventHandler(e)
{
    
}

function update()
{
    if( arcPosY + 10 > 400) 
    {
        window.location.reload();
        //console.log('gg')
        alert("겜오버!!")
    } 
    //데이터 수정 도형의 위치 이동
    if(arcPosX - arcRadius < 0)
    {
        arcMoveDirX = 1;
    }
    else if(arcPosX + arcRadius > canvas.width)
    {
        arcMoveDirX = -1;        
    }
    
    if(arcPosY - arcRadius < 0)
    {
        arcMoveDirY = 1;
    }
    else if(arcPosY + arcRadius > canvas.height)
    {
        arcMoveDirY = -1;
    }
    
    arcPosX += arcMoveDirX * arcMoveSpd;  
    arcPosY += arcMoveDirY * arcMoveSpd;  


    ball.left = arcPosX - arcRadius;
    ball.right = arcPosX + arcRadius;
    ball.top = arcPosY - arcRadius;
    ball.bottom = arcPosY + arcRadius;
    
    // 충돌확인 어떤경우에도 안부딪히는 상황
    if(isCollisionRectToArc(ball, paddle))
    {
        arcMoveDirY = -1;
        arcPosY = paddle.top - arcRadius;
    }
    for(let i = 0; i < brickRow; i++)
    {
        for(let j = 0; j < brickColumn; j++)
        {
            if (isCollisionRectToArc(ball, bricks[i][j]))
            {
                // 벽돌을 안보이게.. 위치를 바꾸던지.. 볼의 방향을 바꾸던지.. 
                // console.log('i : ', i, ', j : ', j);
                if(bricks[i][j].collisionCount > 0) {
                    bricks[i][j].collisionCount--;
                    arcMoveDirY *= -1;
                    break
                } 
            }
            else{
            }
        }
    }
    
}

function isCollisionRectToArc(arcA, rectB)
{
    // a의 완쪽과 b의 오른쪽
    // a의 오른쪽과 b의 왼쪽
    // a의 아래쪽과 b의 위쪽
    // a의 위쪽과 b의 아래쪽
    if (arcA.left > rectB.right ||     // a의 왼쪽이 더 클때
        arcA.right < rectB.left ||     // b의 왼쪽이 더 클때
        arcA.top > rectB.bottom ||     // a의 탑이 더 클때
        arcA.bottom < rectB.top )      // b의 탑이 더 클때
        {
            return false;
        }
    return true;
}

function draw()
{
    // 화면 클리어
    context.clearRect(0, 0, canvas.width, canvas.height);
    drawCanavs();

    // 다른 도형 그리기
    drawRect();
    drawArc();    
    drawBricks();
}

function drawCanavs()
{
    context.beginPath();
    context.rect(0, 0, canvas.width, canvas.height);
    context.fillStyle = "rgba(10, 10, 10, 0.1)";
    context.fill();

    context.closePath();
}

function drawArc()                  // 컴파일시 실행준비 함수는 한번씩만 작동하는게 좋다 - 기능하나만 구현하는게 최고다
{    
    context.beginPath();

    context.arc(arcPosX, arcPosY, arcRadius, 0, 2 * Math.PI);
    context.fillStyle = 'gold'
    context.fill();

    context.closePath();
}

function drawRect()
{
    context.beginPath();

    // context.rect(canvas.width / 2 , canvas.heigh / 2, 100, 100);
    context.rect(barPosX , barPosY, barWidth, barHight);
    context.fillStyle = 'red';
    context.fill();

    context.closePath();
}

function setBricks()
{
    for(let i = 0; i < brickRow; i++) // 위에서아래라 4줄
    {
        bricks[i] = [];
        for(let j = 0; j < brickColumn; j++) // 좌우로 5개씩
        {
            // TODO : right : lefi + 50 해보기
            bricks[i][j] = {
                left : 55 + j * (brickWidth + 10), 
                right : 55 + j * (brickWidth + 10) + 50, 
                top : 30 + i * (brickHeight + 5), 
                bottom : 30 + i * (brickHeight + 5) + 25,
                column : i,
                row : j,                
                collisionCount : 2
            };
        } 
    }
}

const bricksColor = [ "red", "orange", "yellow", "green", "blue" ]
function drawBricks()
{
    let gamimg = false;
    // context.beginPath();
    for(let i = 0; i < brickRow; i++) // 위에서아래로 4줄    {
    {    
        for(let j = 0; j < brickColumn; j++) // 좌우로 5개씩
        {
            // TODO : right : lefi + 50 해보기
            if(bricks[i][j].collisionCount == 2)
            {
                context.beginPath();
                context.rect(bricks[i][j].left, bricks[i][j].top, brickWidth, brickHeight);
                context.fillStyle = bricksColor[i];
                context.fill();
                context.closePath();
                gamimg = true;
            }
            else if(bricks[i][j].collisionCount == 1)
            {
                context.beginPath();
                context.rect(bricks[i][j].left, bricks[i][j].top, brickWidth, brickHeight);
                context.fillStyle = "purple";
                context.fill();
                context.closePath();
                gamimg = true;
            }
            else
            {
                
            }
        } 
    }
    if(!gamimg) {
        clear();        
    }
    // context.closePath();
}

function clear()
{
    window.location.reload();
    alert("클리어!!")
}

function gameover()
{   
    
    if( arcPosY + 10 > 400) 
    {
        console.log('gg')
        alert("겜오버!!")
    }
}

setBricks();
setInterval(() => {if(setStart) {update()}}, 10);
setInterval(draw, 10);           // 런타임시 컴피알된 함수 실행

// 실습1. 동그라미가 오른쪽으로 움직이다가 캔버스 끝에 닿으면 왼쪽으로 이동 반대까지

// 실습2. 동그라마가 빠르게 움직이기

// 실습3. 방향키로 방향을 입력하면 네모칸의 방향이 움직인다. // 화면밖으로 이동하는걸 막는다.

// 부딪힌 벽돌이 사라지는 함수 추가 // arc가 브릭스에 닿을때 브릭스가 사라진다. 색이 변한다.

// 공과 브릭이 하나하나씩 충돌하는지 확인 // 충돌체크

// 벽돌이 2번에 걸쳐서 사라지게 하기(색변경으로 상태나타내기) // 안그리면 된다.

  1. 블록깨기 게임 작성
    1. 공 움직임 (자동)
    2. 패들 움직임 (수동 : 키 입력 처리)
    3. 벽돌 생성
    4. 공 - 패들 , 공 - 벽돌 충돌처리
    5. 게임 클리어 , 게임 오버 처리
    6. 벽돌 배치 후 스페이스바 누르면 공 발사 방향 결정

  2. 게임 외부 입력 요소 (react 활용)

    1. 타이틀 화면 출력 ( 페이드 인, 페이드 아웃 효과 )
    2. 왼쪽 혹은 오른쪽 화면 밖에서 입장하는 input , 게임 화면
    3. 행, 열 값 입력 (input)
    4. 입력된 행렬 값에 따른 벽돌 배치

// 처리한거
// 처리못한거

profile
dalssenger

0개의 댓글

Powered by GraphCDN, the GraphQL CDN