공 피하기 게임

게임 화면

이번에는 간단한 "공 피하기 (Avoid the Ball)" 게임을 만들어 보겠습니다. 이 게임은 사용자가 키보드를 이용해 캐릭터를 움직이며 떨어지는 공을 피하는 간단한 게임입니다. 캐릭터가 공에 닿으면 게임이 종료됩니다.

1. 프로젝트 구조

flask_avoid_game/ │ ├── app.py # Flask 서버 코드 ├── static/ │ └── game.js # JavaScript 파일 (게임 로직) └── templates/ └── index.html # HTML 파일 (게임 인터페이스)

2. Flask 서버 코드 (app.py)

Flask 서버를 통해 웹 페이지를 제공하는 간단한 서버 코드를 작성합니다.

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 파일을 작성합니다.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Avoid the Ball Game</title> <style> canvas { background-color: #f0f0f0; display: block; margin: 0 auto; border: 1px solid #000; } </style> </head> <body> <h1 style="text-align: center;">Avoid the Ball 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)

20개의 공을 관리하기 위해 공의 정보(위치와 속도)를 저장하는 배열을 사용합니다.

const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); let playerWidth = 30; let playerHeight = 30; let playerX = (canvas.width - playerWidth) / 2; let playerY = canvas.height - playerHeight - 10; let rightPressed = false; let leftPressed = false; let ballCount = 10; // 공의 개수 설정 let balls = []; // 공의 정보 저장 배열 let ballRadius = 10; let gameOver = false; // 공 초기화 for (let i = 0; i < ballCount; i++) { balls.push({ x: Math.random() * (canvas.width - ballRadius), y: -Math.random() * 1000, // 공이 화면 바깥에서 떨어지게 설정 speed: 2 + Math.random() * 3 // 각 공에 다른 속도 부여 }); } // 키보드 입력 처리 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 drawPlayer() { ctx.beginPath(); ctx.rect(playerX, playerY, playerWidth, playerHeight); ctx.fillStyle = "#0095DD"; ctx.fill(); ctx.closePath(); } // 공 그리기 function drawBalls() { for (let i = 0; i < ballCount; i++) { let ball = balls[i]; ctx.beginPath(); ctx.arc(ball.x, ball.y, ballRadius, 0, Math.PI * 2); ctx.fillStyle = "#DD0000"; ctx.fill(); ctx.closePath(); } } // 충돌 감지 function detectCollision() { for (let i = 0; i < ballCount; i++) { let ball = balls[i]; if (ball.y + ballRadius > playerY && ball.x > playerX && ball.x < playerX + playerWidth) { gameOver = true; } } } // 게임 오버 처리 function handleGameOver() { ctx.font = "30px Arial"; ctx.fillStyle = "#FF0000"; ctx.fillText("Game Over", canvas.width / 2 - 90, canvas.height / 2); } // 게임 루프 function draw() { if (gameOver) { handleGameOver(); return; } ctx.clearRect(0, 0, canvas.width, canvas.height); drawPlayer(); drawBalls(); detectCollision(); // 플레이어 이동 if(rightPressed && playerX < canvas.width - playerWidth) { playerX += 7; } else if(leftPressed && playerX > 0) { playerX -= 7; } // 공 이동 for (let i = 0; i < ballCount; i++) { let ball = balls[i]; ball.y += ball.speed; // 공이 화면을 벗어나면 다시 위에서 떨어지게 설정 if (ball.y - ballRadius > canvas.height) { ball.x = Math.random() * (canvas.width - ballRadius); ball.y = -ballRadius; } } requestAnimationFrame(draw); } draw();

5. 게임 실행

이제 Flask 서버를 실행하여 게임을 실행할 수 있습니다.

python app.py

브라우저에서 http://127.0.0.1:5000/에 접속하면 "공 피하기" 게임이 실행됩니다.

게임 동작 설명

  1. 플레이어: 플레이어는 화면 하단의 사각형으로, 화살표 키(왼쪽, 오른쪽)를 이용해 움직입니다.
  2. : 공이 화면 상단에서 떨어지며, 플레이어는 공을 피해야 합니다.
  3. 게임 오버: 공이 플레이어와 충돌하면 게임이 종료되고, "Game Over" 메시지가 나타납니다.

요약

이 프로젝트는 Flask와 JavaScript를 사용하여 간단한 "공 피하기" 게임을 구현한 예제입니다. 주요 구성 요소는 다음과 같습니다:

  • Flask: 게임 HTML과 JavaScript를 서빙하는 웹 서버 역할.
  • HTML5 Canvas: 게임 화면을 그리는 데 사용.
  • JavaScript: 게임 로직을 처리하여 캐릭터 이동 및 충돌 감지 등을 구현

댓글 쓰기

댓글 목록

<!DOCTYPE html> <html> <head> <title>Browser Dodge Game</title> <style> body { margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #222; color: white; font-family: Arial, sans-serif; flex-direction: column; } canvas { background-color: #000; border: 4px solid #444; box-shadow: 0 0 20px rgba(0, 255, 0, 0.2); } h2 { margin-bottom: 10px; } p { color: #aaa; } </style> </head> <body> <h2>Dodge the Red Blocks!</h2> <canvas id="gameCanvas" width="400" height="500"></canvas> <p>Use <b>Left</b> and <b>Right</b> Arrow Keys to Move</p> <script> const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); // Game Variables let player = { x: 175, y: 440, width: 50, height: 50, color: "#00FF00" }; let enemies = []; let score = 0; let gameSpeed = 3; let isGameOver = false; // Listen for Key Presses let rightPressed = false; let leftPressed = false; 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; } // Create a new enemy function spawnEnemy() { const xPos = Math.random() * (canvas.width - 40); enemies.push({ x: xPos, y: 0, width: 40, height: 40, color: "red" }); } // Main Game Loop function draw() { if (isGameOver) { ctx.fillStyle = "white"; ctx.font = "40px Arial"; ctx.textAlign = "center"; ctx.fillText("GAME OVER", canvas.width/2, canvas.height/2); ctx.font = "20px Arial"; ctx.fillText("Click to Restart", canvas.width/2, canvas.height/2 + 40); return; } // Clear Screen ctx.clearRect(0, 0, canvas.width, canvas.height); // Move Player if(rightPressed && player.x < canvas.width - player.width) player.x += 5; if(leftPressed && player.x > 0) player.x -= 5; // Draw Player ctx.fillStyle = player.color; ctx.fillRect(player.x, player.y, player.width, player.height); // Handle Enemies if (Math.random() < 0.02) spawnEnemy(); // 2% chance per frame to spawn for (let i = 0; i < enemies.length; i++) { let e = enemies[i]; e.y += gameSpeed; // Move enemy down // Draw Enemy ctx.fillStyle = e.color; ctx.fillRect(e.x, e.y, e.width, e.height); // Collision Detection if ( player.x < e.x + e.width && player.x + player.width > e.x && player.y < e.y + e.height && player.height + player.y > e.y ) { isGameOver = true; } } // Draw Score ctx.fillStyle = "white"; ctx.font = "20px Arial"; ctx.fillText("Score: " + score, 10, 30); score++; // Loop requestAnimationFrame(draw); } // Restart logic canvas.addEventListener('click', () => { if(isGameOver) location.reload(); }); draw(); // Start the game </script> </body> </html>
User, 2026-01-01
<!DOCTYPE html> <html> <head> <title>Browser Dodge Game</title> <style> body { margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #222; color: white; font-family: Arial, sans-serif; flex-direction: column; } canvas { background-color: #000; border: 4px solid #444; box-shadow: 0 0 20px rgba(0, 255, 0, 0.2); } h2 { margin-bottom: 10px; } p { color: #aaa; } </style> </head> <body> <h2>Dodge the Red Blocks!</h2> <canvas id="gameCanvas" width="400" height="500"></canvas> <p>Use <b>Left</b> and <b>Right</b> Arrow Keys to Move</p> <script> const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); // Game Variables let player = { x: 175, y: 440, width: 50, height: 50, color: "#00FF00" }; let enemies = []; let score = 0; let gameSpeed = 3; let isGameOver = false; // Listen for Key Presses let rightPressed = false; let leftPressed = false; 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; } // Create a new enemy function spawnEnemy() { const xPos = Math.random() * (canvas.width - 40); enemies.push({ x: xPos, y: 0, width: 40, height: 40, color: "red" }); } // Main Game Loop function draw() { if (isGameOver) { ctx.fillStyle = "white"; ctx.font = "40px Arial"; ctx.textAlign = "center"; ctx.fillText("GAME OVER", canvas.width/2, canvas.height/2); ctx.font = "20px Arial"; ctx.fillText("Click to Restart", canvas.width/2, canvas.height/2 + 40); return; } // Clear Screen ctx.clearRect(0, 0, canvas.width, canvas.height); // Move Player if(rightPressed && player.x < canvas.width - player.width) player.x += 5; if(leftPressed && player.x > 0) player.x -= 5; // Draw Player ctx.fillStyle = player.color; ctx.fillRect(player.x, player.y, player.width, player.height); // Handle Enemies if (Math.random() < 0.02) spawnEnemy(); // 2% chance per frame to spawn for (let i = 0; i < enemies.length; i++) { let e = enemies[i]; e.y += gameSpeed; // Move enemy down // Draw Enemy ctx.fillStyle = e.color; ctx.fillRect(e.x, e.y, e.width, e.height); // Collision Detection if ( player.x < e.x + e.width && player.x + player.width > e.x && player.y < e.y + e.height && player.height + player.y > e.y ) { isGameOver = true; } } // Draw Score ctx.fillStyle = "white"; ctx.font = "20px Arial"; ctx.fillText("Score: " + score, 10, 30); score++; // Loop requestAnimationFrame(draw); } // Restart logic canvas.addEventListener('click', () => { if(isGameOver) location.reload(); }); draw(); // Start the game </script> </body> </html>
User, 2026-01-01