Spaces:
Running
Running
| <html lang="ko"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>HTML ์ง๋ ์ด ๊ฒ์</title> | |
| <style> | |
| /* ๊ธฐ๋ณธ ์คํ์ผ */ | |
| body { | |
| background-color: #f0f0f0; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| height: 100vh; | |
| margin: 0; | |
| } | |
| /* ๊ฒ์ ์ปจํ ์ด๋ ์คํ์ผ */ | |
| #game-container { | |
| background-color: #fff; | |
| border-radius: 10px; | |
| box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); | |
| padding: 20px; | |
| text-align: center; | |
| } | |
| h1 { | |
| color: #333; | |
| margin-bottom: 10px; | |
| } | |
| /* ๊ฒ์ ์บ๋ฒ์ค ์คํ์ผ */ | |
| #gameCanvas { | |
| background-color: #dcedc8; /* ์ฐํ ๋ น์ ๋ฐฐ๊ฒฝ */ | |
| border: 2px solid #333; | |
| } | |
| /* ์ ์ํ ์คํ์ผ */ | |
| #score-board { | |
| font-size: 24px; | |
| font-weight: bold; | |
| color: #555; | |
| margin-top: 10px; | |
| } | |
| /* ๊ฒ์ ์ค๋ฒ ๋ฉ์์ง ์คํ์ผ */ | |
| #game-over { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background-color: rgba(0, 0, 0, 0.7); | |
| color: white; | |
| padding: 20px 40px; | |
| border-radius: 10px; | |
| display: none; /* ๊ธฐ๋ณธ์ ์ผ๋ก ์จ๊น */ | |
| text-align: center; | |
| } | |
| #game-over h2 { | |
| margin: 0 0 10px 0; | |
| } | |
| #restart-button { | |
| background-color: #4CAF50; | |
| color: white; | |
| border: none; | |
| padding: 10px 20px; | |
| font-size: 16px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| transition: background-color 0.3s; | |
| } | |
| #restart-button:hover { | |
| background-color: #45a049; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="game-container"> | |
| <h1>์ง๋ ์ด ๊ฒ์</h1> | |
| <canvas id="gameCanvas" width="400" height="400"></canvas> | |
| <div id="score-board">์ ์: <span id="score">0</span></div> | |
| </div> | |
| <div id="game-over"> | |
| <h2>๊ฒ์ ์ค๋ฒ!</h2> | |
| <button id="restart-button">๋ค์ ์์</button> | |
| </div> | |
| <script> | |
| // --- 1. ์ด๊ธฐ ์ค์ --- | |
| const canvas = document.getElementById('gameCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const scoreElement = document.getElementById('score'); | |
| const gameOverElement = document.getElementById('game-over'); | |
| const restartButton = document.getElementById('restart-button'); | |
| const BOX_SIZE = 20; // ๊ฐ ์นธ์ ํฌ๊ธฐ | |
| const CANVAS_WIDTH = canvas.width; | |
| const CANVAS_HEIGHT = canvas.height; | |
| let snake; // ์ง๋ ์ด ๋ฐฐ์ด (x, y ์ขํ ๊ฐ์ฒด) | |
| let food; // ๋จน์ด ๊ฐ์ฒด (x, y ์ขํ) | |
| let score; // ์ ์ | |
| let direction; // ํ์ฌ ์ด๋ ๋ฐฉํฅ | |
| let changingDirection; // ๋ฐฉํฅ ์ ํ ์ค์ธ์ง ํ์ธ (์ฐ์์ ์ธ ํค ์ ๋ ฅ ๋ฐฉ์ง) | |
| let gameLoop; // ๊ฒ์ ๋ฃจํ setInterval ID | |
| // --- 2. ๊ฒ์ ์์ ๋ฐ ์ฌ์์ --- | |
| function startGame() { | |
| // ๊ฒ์ ์ํ ์ด๊ธฐํ | |
| snake = [ | |
| { x: 10 * BOX_SIZE, y: 10 * BOX_SIZE }, | |
| { x: 9 * BOX_SIZE, y: 10 * BOX_SIZE }, | |
| { x: 8 * BOX_SIZE, y: 10 * BOX_SIZE } | |
| ]; | |
| score = 0; | |
| direction = 'RIGHT'; | |
| changingDirection = false; | |
| // UI ์ด๊ธฐํ | |
| scoreElement.textContent = score; | |
| gameOverElement.style.display = 'none'; | |
| generateFood(); // ์ฒซ ๋จน์ด ์์ฑ | |
| // ๊ธฐ์กด ๊ฒ์ ๋ฃจํ๊ฐ ์๋ค๋ฉด ์ค์ง | |
| if (gameLoop) { | |
| clearInterval(gameLoop); | |
| } | |
| // ์๋ก์ด ๊ฒ์ ๋ฃจํ ์์ (100ms ๋ง๋ค main ํจ์ ์คํ) | |
| gameLoop = setInterval(main, 100); | |
| } | |
| // --- 3. ๊ฒ์ ๋ฉ์ธ ๋ฃจํ --- | |
| function main() { | |
| if (checkGameOver()) { | |
| clearInterval(gameLoop); | |
| gameOverElement.style.display = 'block'; | |
| return; | |
| } | |
| changingDirection = false; | |
| clearCanvas(); | |
| drawFood(); | |
| moveSnake(); | |
| drawSnake(); | |
| } | |
| // --- 4. ๊ทธ๋ฆฌ๊ธฐ ํจ์๋ค --- | |
| // ์บ๋ฒ์ค ์ง์ฐ๊ธฐ | |
| function clearCanvas() { | |
| ctx.fillStyle = '#dcedc8'; | |
| ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); | |
| } | |
| // ์ง๋ ์ด ๊ทธ๋ฆฌ๊ธฐ | |
| function drawSnake() { | |
| snake.forEach((segment, index) => { | |
| // ๋จธ๋ฆฌ ์์ ๋ค๋ฅด๊ฒ ํ๊ธฐ | |
| ctx.fillStyle = (index === 0) ? '#1b5e20' : '#4caf50'; | |
| ctx.strokeStyle = '#388e3c'; | |
| ctx.fillRect(segment.x, segment.y, BOX_SIZE, BOX_SIZE); | |
| ctx.strokeRect(segment.x, segment.y, BOX_SIZE, BOX_SIZE); | |
| }); | |
| } | |
| // ๋จน์ด ๊ทธ๋ฆฌ๊ธฐ | |
| function drawFood() { | |
| ctx.fillStyle = '#d32f2f'; // ๋ถ์์ ๋จน์ด | |
| ctx.strokeStyle = '#c62828'; | |
| ctx.fillRect(food.x, food.y, BOX_SIZE, BOX_SIZE); | |
| ctx.strokeRect(food.x, food.y, BOX_SIZE, BOX_SIZE); | |
| } | |
| // --- 5. ๊ฒ์ ๋ก์ง ํจ์๋ค --- | |
| // ๋จน์ด ์์ฑ (์ง๋ ์ด ๋ชธ ์๊ฐ ์๋ ๊ณณ์) | |
| function generateFood() { | |
| while (true) { | |
| const foodX = Math.floor(Math.random() * (CANVAS_WIDTH / BOX_SIZE)) * BOX_SIZE; | |
| const foodY = Math.floor(Math.random() * (CANVAS_HEIGHT / BOX_SIZE)) * BOX_SIZE; | |
| let isFoodOnSnake = snake.some(segment => segment.x === foodX && segment.y === foodY); | |
| if (!isFoodOnSnake) { | |
| food = { x: foodX, y: foodY }; | |
| return; | |
| } | |
| } | |
| } | |
| // ์ง๋ ์ด ์ด๋ | |
| function moveSnake() { | |
| let dx = 0; | |
| let dy = 0; | |
| if (direction === 'RIGHT') dx = BOX_SIZE; | |
| if (direction === 'LEFT') dx = -BOX_SIZE; | |
| if (direction === 'UP') dy = -BOX_SIZE; | |
| if (direction === 'DOWN') dy = BOX_SIZE; | |
| const head = { x: snake[0].x + dx, y: snake[0].y + dy }; | |
| snake.unshift(head); // ์๋ก์ด ๋จธ๋ฆฌ๋ฅผ ๋ฐฐ์ด ๋งจ ์์ ์ถ๊ฐ | |
| // ๋จน์ด๋ฅผ ๋จน์๋์ง ํ์ธ | |
| if (head.x === food.x && head.y === food.y) { | |
| score += 10; | |
| scoreElement.textContent = score; | |
| generateFood(); | |
| } else { | |
| snake.pop(); // ๋จน์ด๋ฅผ ๋จน์ง ์์๋ค๋ฉด ๊ผฌ๋ฆฌ ์ ๊ฑฐ | |
| } | |
| } | |
| // ๊ฒ์ ์ค๋ฒ ์กฐ๊ฑด ํ์ธ | |
| function checkGameOver() { | |
| // 1. ๋ฒฝ ์ถฉ๋ ํ์ธ | |
| const head = snake[0]; | |
| if (head.x < 0 || head.x >= CANVAS_WIDTH || head.y < 0 || head.y >= CANVAS_HEIGHT) { | |
| return true; | |
| } | |
| // 2. ์๊ธฐ ๋ชธ ์ถฉ๋ ํ์ธ | |
| for (let i = 1; i < snake.length; i++) { | |
| if (head.x === snake[i].x && head.y === snake[i].y) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| // --- 6. ์ด๋ฒคํธ ๋ฆฌ์ค๋ --- | |
| // ํค๋ณด๋ ์ ๋ ฅ ์ฒ๋ฆฌ | |
| function changeDirection(event) { | |
| if (changingDirection) return; | |
| changingDirection = true; | |
| const keyPressed = event.key; | |
| const goingUp = direction === 'UP'; | |
| const goingDown = direction === 'DOWN'; | |
| const goingRight = direction === 'RIGHT'; | |
| const goingLeft = direction === 'LEFT'; | |
| if ((keyPressed === 'ArrowLeft' || keyPressed.toLowerCase() === 'a') && !goingRight) { | |
| direction = 'LEFT'; | |
| } | |
| if ((keyPressed === 'ArrowUp' || keyPressed.toLowerCase() === 'w') && !goingDown) { | |
| direction = 'UP'; | |
| } | |
| if ((keyPressed === 'ArrowRight' || keyPressed.toLowerCase() === 'd') && !goingLeft) { | |
| direction = 'RIGHT'; | |
| } | |
| if ((keyPressed === 'ArrowDown' || keyPressed.toLowerCase() === 's') && !goingUp) { | |
| direction = 'DOWN'; | |
| } | |
| } | |
| document.addEventListener('keydown', changeDirection); | |
| restartButton.addEventListener('click', startGame); | |
| // --- 7. ๊ฒ์ ์์ --- | |
| startGame(); | |
| </script> | |
| </body> | |
| </html> |