벽돌 깨기 게임
화면
이번에는 JavaScript와 HTML5 Canvas를 사용하여 "벽돌깨기" 게임을 만들어 보겠습니다. 이 게임에서는 플레이어가 바닥의 패들을 좌우로 움직여 공을 튕겨내어 위에 있는 벽돌을 깨는 간단한 구조입니다.
1. 프로젝트 구조
flask_brick_breaker/
│
├── app.py # Flask 서버 코드
├── static/
│ └── game.js # JavaScript 파일 (게임 로직)
└── templates/
└── index.html # HTML 파일 (게임 인터페이스)
2. Flask 서버 코드 (app.py
)
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
3. HTML 파일 (index.html
)
index.html
에서는 게임을 렌더링할 HTML5 canvas
요소를 추가합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Brick Breaker Game</title>
<style>
canvas {
background: #f0f0f0;
display: block;
margin: 0 auto;
border: 1px solid #000;
}
</style>
</head>
<body>
<h1>Brick Breaker Game</h1>
<canvas id="gameCanvas" width="480" height="320"></canvas>
<script src="{{ url_for('static', filename='game.js') }}"></script>
</body>
</html>
4. 게임 로직 (JavaScript) - game.js
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
let ballRadius = 10;
let x = canvas.width / 2;
let y = canvas.height - 30;
let dx = 2;
let dy = -2;
let paddleHeight = 10;
let paddleWidth = 75;
let paddleX = (canvas.width - paddleWidth) / 2;
let rightPressed = false;
let leftPressed = false;
let brickRowCount = 3;
let brickColumnCount = 5;
let brickWidth = 75;
let brickHeight = 20;
let brickPadding = 10;
let brickOffsetTop = 30;
let brickOffsetLeft = 30;
let score = 0;
// 벽돌 배열 생성
let bricks = [];
for (let c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (let r = 0; r < brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 }; // status가 1일 때 벽돌이 남아있음
}
}
// 키보드 입력 처리
document.addEventListener("keydown", keyDownHandler);
document.addEventListener("keyup", keyUpHandler);
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 drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
// 패들 그리기
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
ctx.fillStyle = "#0095DD";
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) {
let brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
let 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();
}
}
}
}
// 공과 벽돌 충돌 처리
function collisionDetection() {
for (let c = 0; c < brickColumnCount; c++) {
for (let r = 0; r < brickRowCount; r++) {
let 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();
}
}
}
}
}
}
// 점수 그리기
function drawScore() {
ctx.font = "16px Arial";
ctx.fillStyle = "#0095DD";
ctx.fillText("Score: " + score, 8, 20);
}
// 게임 루프
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBricks();
drawBall();
drawPaddle();
drawScore();
collisionDetection();
// 공 벽 충돌 처리
if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
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();
}
}
// 패들 이동 처리
if (rightPressed && paddleX < canvas.width - paddleWidth) {
paddleX += 7;
} else if (leftPressed && paddleX > 0) {
paddleX -= 7;
}
// 공 이동
x += dx;
y += dy;
requestAnimationFrame(draw);
}
draw();
5. 게임 실행
이제 app.py
파일을 실행하여 Flask 서버를 실행합니다.
python app.py
브라우저에서 http://127.0.0.1:5000/
에 접속하면 벽돌깨기 게임이 실행됩니다.
게임 동작 설명
- 공이 화면에서 튕기면서 벽돌을 맞추고, 패들을 움직여 공을 놓치지 않도록 합니다.
- 화살표 키(
←
,→
)를 사용하여 패들을 좌우로 움직일 수 있습니다. - 공이 화면 아래쪽으로 떨어지면 게임이 종료되고, 점수를 올리며 모든 벽돌을 깨면 승리합니다.
6. 요약
이 예제에서는 Flask를 사용하여 간단한 웹 기반 벽돌깨기 게임을 만들었습니다. 주요 구성 요소는 다음과 같습니다:
- Flask를 통해 웹 서버를 호스팅하고 HTML과 JavaScript를 서빙.
- HTML5 Canvas를 사용하여 게임 그래픽을 그리기.
- JavaScript를 사용하여 공의 이동, 패들 조작, 벽돌 충돌 등의 게임 로직을 처리.