console
<!DOCTYPE html>
<html>
<head>
<title>边界碰撞贪吃蛇</title>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
background-color: #2c3e50;
font-family: Arial, sans-serif;
margin: 0;
min-height: 100vh;
}
#game-container {
position: relative;
margin-top: 20px;
}
#gameCanvas {
border: 3px solid #ecf0f1;
border-radius: 5px;
background-color: #34495e;
}
.control-btn {
position: absolute;
padding: 15px 30px;
font-size: 1.2em;
background-color: #27ae60;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
transform: translate(-50%, -50%);
z-index: 1;
}
#startBtn {
top: 50%;
left: 50%;
}
#restartBtn {
display: none;
top: 60%;
left: 50%;
}
#score {
color: #ecf0f1;
font-size: 2em;
margin: 20px 0;
}
</style>
</head>
<body>
<div id="score">得分: 0</div>
<div id="game-container">
<canvas id="gameCanvas" width="400" height="400"></canvas>
<button id="startBtn" class="control-btn">开始游戏</button>
<button id="restartBtn" class="control-btn">再来一次</button>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const startBtn = document.getElementById('startBtn');
const restartBtn = document.getElementById('restartBtn');
const GRID_SIZE = 20;
const TILE_COUNT = canvas.width / GRID_SIZE;
const GAME_SPEED = 100;
let snake = [];
let food = { x: 0, y: 0 };
let dx = 0;
let dy = 0;
let score = 0;
let lastTime = 0;
let isPlaying = false;
let animationFrameId = null;
function initGame() {
snake = [{ x: 10, y: 10 }];
dx = 1;
dy = 0;
score = 0;
scoreElement.textContent = `得分: ${score}`;
generateFood();
isPlaying = true;
}
function generateFood() {
do {
food.x = Math.floor(Math.random() * TILE_COUNT);
food.y = Math.floor(Math.random() * TILE_COUNT);
} while (snake.some(segment =>
segment.x === food.x &&
segment.y === food.y
));
}
function gameLoop(timestamp) {
if (!isPlaying) return;
const delta = timestamp - lastTime;
if (delta > GAME_SPEED) {
lastTime = timestamp;
const newHead = {
x: snake[0].x + dx,
y: snake[0].y + dy
};
if (newHead.x < 0 || newHead.x >= TILE_COUNT ||
newHead.y < 0 || newHead.y >= TILE_COUNT) {
gameOver();
return;
}
if (snake.some(segment =>
segment.x === newHead.x &&
segment.y === newHead.y
)) {
gameOver();
return;
}
snake.unshift(newHead);
if (newHead.x === food.x && newHead.y === food.y) {
score += 10;
scoreElement.textContent = `得分: ${score}`;
generateFood();
} else {
snake.pop();
}
draw();
}
animationFrameId = requestAnimationFrame(gameLoop);
}
function draw() {
ctx.fillStyle = '#34495e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#e74c3c';
ctx.fillRect(
food.x * GRID_SIZE,
food.y * GRID_SIZE,
GRID_SIZE - 2,
GRID_SIZE - 2
);
snake.forEach((segment, index) => {
ctx.fillStyle = index === 0 ? '#ff0000' : '#27ae60';
ctx.fillRect(
segment.x * GRID_SIZE,
segment.y * GRID_SIZE,
GRID_SIZE - 2,
GRID_SIZE - 2
);
});
}
function gameOver() {
isPlaying = false;
cancelAnimationFrame(animationFrameId);
restartBtn.style.display = 'block';
}
function handleKeyDown(e) {
if (!isPlaying) return;
const key = e.key;
const goingUp = dy === -1;
const goingDown = dy === 1;
const goingRight = dx === 1;
const goingLeft = dx === -1;
switch(key) {
case 'ArrowLeft':
if (!goingRight) { dx = -1; dy = 0; }
break;
case 'ArrowUp':
if (!goingDown) { dx = 0; dy = -1; }
break;
case 'ArrowRight':
if (!goingLeft) { dx = 1; dy = 0; }
break;
case 'ArrowDown':
if (!goingUp) { dx = 0; dy = 1; }
break;
}
}
startBtn.addEventListener('click', () => {
startBtn.style.display = 'none';
restartBtn.style.display = 'none';
initGame();
gameLoop(0);
});
restartBtn.addEventListener('click', () => {
restartBtn.style.display = 'none';
startBtn.click();
});
document.addEventListener('keydown', handleKeyDown);
initGame();
draw();
startBtn.style.display = 'block';
restartBtn.style.display = 'none';
</script>
</body>
</html>