testfile1 / index.html
createcodeinnovation's picture
Update index.html
09cc2b3 verified
<!DOCTYPE html>
<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>