본문 바로가기
vita_Programing

Javascript 벽돌깨기 게임 소스 공유

by lemonvita 2024. 5. 29.
728x90
반응형

 

 

자바스크립트 벽돌깨기 게임 소스

 

 

 

어릴 때 아케이드 게임에서 즐겼던 '벽돌깨기' 게임 기억하시나요? 별돌깨기 게임은 정말 단순하지만 중독성이 강해서 재미있었죠. 오늘은 그런 추억을 떠올리며, HTML, CSS, JavaScript를 활용해서 직접 벽돌깨기 게임을 만들어 보았습니다.

이 게임은 500px × 600px 크기의 캔버스에 200개의 무작위 색상 벽돌이 쌓여 있어요. 각 벽돌을 깨면 다른 점수를 얻을 수 있고, 공이 바닥에 닿으면 게임이 끝나죠. 키보드로 바를 움직여서 공을 튕겨 벽돌을 깨는 동작은 고전적인 아케이드 게임의 느낌을 그대로 살렸습니다.

각 벽돌의 색깔마다 다른 점수를 획득할 수 있고, 점수가 올라갈 때마다 공의 속도가 조금씩 빨라지도록 했습니다.

 

728x90

 

자바스크립트 벽돌깨기 게임

 

벽돌깨기 게임의 코드를 완성하고 실행하면 다음과 같이 동작됩니다. 정말 흥미롭죠?

 

자바스크립트 벽돌깨기 게임

 

 

 

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>벽돌깨기 게임</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="game-container">
        <h1>벽돌깨기 게임</h1>
        <div class="score">점수: <span id="score">0</span></div>
        <canvas id="gameCanvas" width="500" height="600"></canvas>
        <div id="gameOver" class="game-over">GAME OVER</div>
        <button id="startButton">시작</button>
        <button id="stopButton">종료</button>
    </div>
    <script src="script.js"></script>
</body>
</html>

 

 

 

 

 

style.css

body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #f0f0f0;
}

.game-container {
    text-align: center;
    position: relative;
}

canvas {
    display: block;
    margin: 0 auto;
    background-color: #000;
}

button {
    margin: 5px;
}

.game-over {
    display: none;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 48px;
    color: red;
    background-color: rgba(0, 0, 0, 0.7);
    padding: 20px;
    border-radius: 10px;
}

111

 

 

 

 

script.js

// 캔버스와 캔버스 컨텍스트 설정
const canvas = document.getElementById("gameCanvas"); // HTML에서 캔버스 요소를 가져옵니다.
const ctx = canvas.getContext("2d"); // 2D 렌더링 컨텍스트를 얻어옵니다.

// 게임 요소 초기화
let score = 0; // 게임 점수를 저장하는 변수를 초기화합니다.
let ball = { x: canvas.width / 2, y: canvas.height - 30, dx: 2, dy: -2, radius: 5, speed: 1 }; // 공의 초기 위치, 이동 속도, 반지름, 속도 등을 설정합니다.
let paddle = { height: 10, width: 50, x: (canvas.width - 50) / 2 }; // 바의 초기 크기와 위치를 설정합니다.
let rightPressed = false; // 오른쪽 화살표 키가 눌려 있는지 여부를 저장하는 변수를 초기화합니다.
let leftPressed = false; // 왼쪽 화살표 키가 눌려 있는지 여부를 저장하는 변수를 초기화합니다.
let isGameOver = false; // 게임이 종료되었는지 여부를 저장하는 변수를 초기화합니다.

// 벽돌 초기화
const brickRowCount = 20; // 벽돌 행의 개수를 설정합니다.
const brickColumnCount = 10; // 벽돌 열의 개수를 설정합니다.
const brickWidth = 50; // 벽돌의 너비를 설정합니다.
const brickHeight = 10; // 벽돌의 높이를 설정합니다.
const brickPadding = 2; // 벽돌 사이의 간격을 설정합니다.
const brickOffsetTop = 30; // 벽돌이 시작되는 영역의 상단 여백을 설정합니다.
const brickOffsetLeft = 0; // 벽돌이 시작되는 영역의 좌측 여백을 설정합니다.
let bricks = []; // 벽돌을 저장할 배열을 선언합니다.

// 이중 배열을 사용하여 벽돌 초기화
for (let c = 0; c < brickColumnCount; c++) {
    bricks[c] = [];
    for (let r = 0; r < brickRowCount; r++) {
        // 무작위로 색상 및 포인트(점수) 설정
        const colors = ['red', 'blue', 'yellow', 'green'];
        const color = colors[Math.floor(Math.random() * colors.length)];
        const points = color === 'red' ? 40 : color === 'blue' ? 30 : color === 'yellow' ? 20 : 10;
        // 벽돌 객체 생성 및 초기화
        bricks[c][r] = { x: 0, y: 0, status: 1, color: color, points: points };
    }
}

// 키보드 입력 핸들링
document.addEventListener("keydown", keyDownHandler, false); // 키가 눌렸을 때 이벤트를 처리합니다.
document.addEventListener("keyup", keyUpHandler, false); // 키가 떼졌을 때 이벤트를 처리합니다.

// 게임 시작 및 종료 버튼에 대한 클릭 이벤트 핸들링
document.getElementById("startButton").addEventListener("click", startGame); // 시작 버튼 클릭 이벤트를 처리합니다.
document.getElementById("stopButton").addEventListener("click", stopGame); // 종료 버튼 클릭 이벤트를 처리합니다.

// 키보드 입력 핸들러 함수
function keyDownHandler(e) { // 키가 눌렸을 때 실행되는 함수입니다.
    if (e.key === "Right" || e.key === "ArrowRight") { // 오른쪽 화살표 키가 눌렸는지 확인합니다.
        rightPressed = true; // 오른쪽 화살표 키가 눌렸음을 표시합니다.
    } else if (e.key === "Left" || e.key === "ArrowLeft") { // 왼쪽 화살표 키가 눌렸는지 확인합니다.
        leftPressed = true; // 왼쪽 화살표 키가 눌렸음을 표시합니다.
    }
}

function keyUpHandler(e) { // 키가 떼졌을 때 실행되는 함수입니다.
    if (e.key === "Right" || e.key === "ArrowRight") { // 오른쪽 화살표 키가 떼졌는지 확인합니다.
        rightPressed = false; // 오른쪽 화살표 키가 떼졌음을 표시합니다.
    } else if (e.key === "Left" || e.key === "ArrowLeft") { // 왼쪽 화살표 키가 떼졌는지 확인합니다.
        leftPressed = false; // 왼쪽 화살표 키가 떼졌음을 표시합니다.
    }
}

// 충돌 감지 함수
function collisionDetection() {
    for (let c = 0; c < brickColumnCount; c++) { // 모든 벽돌에 대해 반복합니다.
        for (let r = 0; r < brickRowCount; r++) {
            const b = bricks[c][r]; // 현재 벽돌을 가져옵니다.
            if (b.status === 1) { // 벽돌이 존재하는 상태인지 확인합니다.
                // 공과 벽돌이 충돌하는지 확인합니다.
                if (
                    ball.x > b.x && 
                    ball.x < b.x + brickWidth && 
                    ball.y > b.y && 
                    ball.y < b.y + brickHeight
                ) {
                    ball.dy = -ball.dy; // 공의 이동 방향을 바꿉니다.
                    b.status = 0; // 벽돌을 제거합니다.
                    score += b.points; // 점수를 증가시킵니다.
                    document.getElementById("score").innerText = score; // 화면에 점수를 업데이트합니다.
                    updateBallSpeed(); // 점수에 따라 공의 속도를 업데이트합니다.
                }
            }
        }
    }
}

// 점수에 따라 공의 속도를 업데이트하는 함수
function updateBallSpeed() {
    ball.speed = 1 + Math.floor(score / 100) * 0.1; // 점수에 따라 공의 속도를 계산합니다.
    // 공의 x 방향과 y 방향 속도를 설정합니다.
    ball.dx = ball.dx > 0 ? ball.speed : -ball.speed;
    ball.dy = ball.dy > 0 ? ball.speed : -ball.speed;
}

// 공 그리기 함수
function drawBall() {
    ctx.beginPath(); // 새로운 경로를 시작합니다.
    ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2); // 원을 그립니다.
    ctx.fillStyle = "#fff"; // 채우기 색상을 설정합니다.
    ctx.fill(); // 도형을 채웁니다.
    ctx.closePath(); // 경로를 닫습니다.
}

// 바 그리기 함수
function drawPaddle() {
    ctx.beginPath(); // 새로운 경로를 시작합니다.
    ctx.rect(paddle.x, canvas.height - paddle.height - 10, paddle.width, paddle.height); // 직사각형을 그립니다.
    ctx.fillStyle = "#fff"; // 채우기 색상을 설정합니다.
    ctx.fill(); // 도형을 채웁니다.
    ctx.closePath(); // 경로를 닫습니다.
}

// 벽돌 그리기 함수
function drawBricks() {
    for (let c = 0; c < brickColumnCount; c++) { // 모든 벽돌에 대해 반복합니다.
        for (let r = 0; r < brickRowCount; r++) {
            if (bricks[c][r].status === 1) { // 벽돌이 존재하는 상태인지 확인합니다.
                const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft; // 벽돌의 x 좌표를 계산합니다.
                const brickY = r * (brickHeight + brickPadding) + brickOffsetTop; // 벽돌의 y 좌표를 계산합니다.
                bricks[c][r].x = brickX; // 벽돌의 x 좌표를 설정합니다.
                bricks[c][r].y = brickY; // 벽돌의 y 좌표를 설정합니다.
                ctx.beginPath(); // 새로운 경로를 시작합니다.
                ctx.rect(brickX, brickY, brickWidth, brickHeight); // 직사각형을 그립니다.
                ctx.fillStyle = bricks[c][r].color; // 채우기 색상을 설정합니다.
                ctx.fill(); // 도형을 채웁니다.
                ctx.closePath(); // 경로를 닫습니다.
            }
        }
    }
}

// 게임 그리기 함수
function draw() {
    if (isGameOver) return; // 게임이 종료되었으면 함수를 종료합니다.

    ctx.clearRect(0, 0, canvas.width, canvas.height); // 캔버스를 지웁니다.
    drawBricks(); // 벽돌을 그립니다.
    drawBall(); // 공을 그립니다.
    drawPaddle(); // 바를 그립니다.
    collisionDetection(); // 충돌을 감지합니다.

    // 공의 이동 경로를 처리합니다.
    if (ball.x + ball.dx > canvas.width - ball.radius || ball.x + ball.dx < ball.radius) {
        ball.dx = -ball.dx; // 공의 x 방향을 변경합니다.
    }
    if (ball.y + ball.dy < ball.radius) {
        ball.dy = -ball.dy; // 공의 y 방향을 변경합니다.
    } else if (ball.y + ball.dy > canvas.height - ball.radius - paddle.height - 10) {
        if (ball.x > paddle.x && ball.x < paddle.x + paddle.width) { // 공이 바에 닿았는지 확인합니다.
            ball.dy = -ball.dy; // 공의 y 방향을 변경합니다.
        } else {
            gameOver(); // 게임 오버 처리를 실행합니다.
        }
    }

    ball.x += ball.dx; // 공의 x 좌표를 이동시킵니다.
    ball.y += ball.dy; // 공의 y 좌표를 업데이트합니다.

    // 바의 위치를 업데이트합니다.
    if (rightPressed && paddle.x < canvas.width - paddle.width) {
        paddle.x += 7; // 오른쪽 화살표 키가 눌려 있고 바가 화면을 벗어나지 않았을 경우, 바를 오른쪽으로 이동시킵니다.
    } else if (leftPressed && paddle.x > 0) {
        paddle.x -= 7; // 왼쪽 화살표 키가 눌려 있고 바가 화면을 벗어나지 않았을 경우, 바를 왼쪽으로 이동시킵니다.
    }

    requestAnimationFrame(draw); // 다음 프레임을 그립니다.
}

// 게임 시작 함수
function startGame() {
    isGameOver = false; // 게임 오버 상태를 초기화합니다.
    gameOverText.style.display = "none"; // 게임 오버 텍스트를 숨깁니다.
    draw(); // 게임을 그립니다.
}

// 게임 종료 함수
function stopGame() {
    isGameOver = true; // 게임 오버 상태를 설정합니다.
    document.location.reload(); // 페이지를 새로고침하여 게임을 종료합니다.
}

// 게임 오버 처리 함수
function gameOver() {
    isGameOver = true; // 게임 오버 상태를 설정합니다.
    gameOverText.style.display = "block"; // 게임 오버 텍스트를 표시합니다.
}

 

 

  1. 캔버스와 캔버스 컨텍스트 설정
    • const canvas = document.getElementById("gameCanvas");: HTML에서 id가 "gameCanvas"인 캔버스 요소를 가져옵니다.
    • const ctx = canvas.getContext("2d");: 2D 렌더링 컨텍스트를 얻어옵니다.
  2. 게임 요소 초기화
    • let score = 0;: 게임 점수를 저장하는 변수를 초기화합니다.
    • let ball = { x: canvas.width / 2, y: canvas.height - 30, dx: 2, dy: -2, radius: 5, speed: 1 };: 공의 초기 위치, 이동 속도, 반지름, 속도 등을 설정합니다.
    • let paddle = { height: 10, width: 50, x: (canvas.width - 50) / 2 };: 바의 초기 크기와 위치를 설정합니다.
    • let rightPressed = false;: 오른쪽 화살표 키가 눌려 있는지 여부를 저장하는 변수를 초기화합니다.
    • let leftPressed = false;: 왼쪽 화살표 키가 눌려 있는지 여부를 저장하는 변수를 초기화합니다.
    • let isGameOver = false;: 게임이 종료되었는지 여부를 저장하는 변수를 초기화합니다.
  3. 벽돌 초기화
    • 이중 배열 bricks를 사용하여 벽돌을 생성하고 초기 상태를 설정합니다. 각 벽돌의 색상과 포인트(점수), 상태 등을 무작위로 설정합니다.
  4. 이벤트 리스너 설정
    • 사용자의 키보드 입력에 따라 keyDownHandler와 keyUpHandler 함수를 호출합니다. 이 함수들은 각각 키가 눌렸을 때와 떼졌을 때의 동작을 처리합니다.
    • 시작 버튼과 종료 버튼에 클릭 이벤트 리스너를 추가하여 게임 시작 및 종료 동작을 처리합니다.
  5. 키보드 입력 핸들링
    • keyDownHandler: 오른쪽 키와 왼쪽 키가 눌렸는지 여부를 설정합니다.
    • keyUpHandler: 오른쪽 키와 왼쪽 키가 떼졌는지 여부를 설정합니다.
  6. 충돌 감지
    • collisionDetection: 공과 벽돌 간의 충돌을 감지하고, 충돌한 벽돌을 제거하며 점수를 갱신합니다.
    • updateBallSpeed: 점수에 따라 공의 속도를 업데이트합니다.
  7. 그리기 함수
    • drawBall: 공을 그립니다.
    • drawPaddle: 바를 그립니다.
    • drawBricks: 벽돌을 그립니다.
  8. 게임 루프 및 게임 오버 처리
    • draw: 게임을 그리는 메인 루프입니다. 공과 바의 이동, 벽돌 그리기, 충돌 감지 등을 수행합니다.
    • startGame: 게임을 시작합니다. draw 함수를 호출하여 게임 루프를 실행합니다.
    • stopGame: 게임을 종료하고 페이지를 새로고침합니다.
    • gameOver: 게임 오버 상태를 설정하고 "GAME OVER" 메시지를 화면에 표시합니다.

 

이상으로 이번 글에서는 벽돌깨기 게임을 자바스크립트, HTML, CSS를 이용하여 제작해 보았습니다.

 

이 게임을 만들면서 JavaScript의 객체지향 프로그래밍과 캔버스 다루는 법을 익혔어요. 또한 게임 로직과 그래픽을 구현하는 과정에서 창의성도 발휘할 수 있었죠. HTML과 CSS로 사용자 인터페이스를 디자인하고, JavaScript로 동적인 동작을 부여하면서 웹 개발의 기본기도 다질 수 있었습니다.

이번 글을 통해 벽돌깨기 게임을 만들어보면서 코드 구현 과정과 함께, 게임 개발에 대한 즐거움과 만족감을 경험할 수 있었습니다. 프로그래밍과 게임 개발에 관심 있는 분들에게 유익한 정보가 되었으면 좋겠네요. 앞으로도 재미있는 게임 개발 이야기를 더 들려드리겠습니다.

728x90
반응형