优化结果

This commit is contained in:
2025-09-15 19:08:47 +08:00
parent 72084a8782
commit dcfa89e63c
357 changed files with 16156 additions and 1589 deletions

View File

@@ -0,0 +1,130 @@
class GameControls {
constructor(game) {
this.game = game;
this.initControls();
this.initTouchControls();
}
initControls() {
// 方向按钮控制
document.getElementById('upBtn').addEventListener('click', () => {
this.game.changeDirection(0, -1);
});
document.getElementById('downBtn').addEventListener('click', () => {
this.game.changeDirection(0, 1);
});
document.getElementById('leftBtn').addEventListener('click', () => {
this.game.changeDirection(-1, 0);
});
document.getElementById('rightBtn').addEventListener('click', () => {
this.game.changeDirection(1, 0);
});
// 暂停/继续按钮
document.getElementById('pauseBtn').addEventListener('click', () => {
this.game.togglePause();
});
// 重新开始按钮
document.getElementById('restartBtn').addEventListener('click', () => {
this.game.restart();
});
// 键盘快捷键
this.initKeyboardShortcuts();
}
initKeyboardShortcuts() {
document.addEventListener('keydown', (e) => {
switch(e.key) {
case 'r':
case 'R':
if (this.game.gameOver) {
this.game.restart();
}
break;
case 'p':
case 'P':
this.game.togglePause();
break;
case 'Escape':
if (this.game.gameOver) {
document.getElementById('gameOverModal').style.display = 'none';
}
break;
}
});
}
initTouchControls() {
const canvas = document.getElementById('gameCanvas');
let touchStartX = 0;
let touchStartY = 0;
canvas.addEventListener('touchstart', (e) => {
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
e.preventDefault();
}, { passive: false });
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
}, { passive: false });
canvas.addEventListener('touchend', (e) => {
const touchEndX = e.changedTouches[0].clientX;
const touchEndY = e.changedTouches[0].clientY;
const deltaX = touchEndX - touchStartX;
const deltaY = touchEndY - touchStartY;
const minSwipeDistance = 30;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// 水平滑动
if (Math.abs(deltaX) > minSwipeDistance) {
if (deltaX > 0) {
this.game.changeDirection(1, 0); // 右滑
} else {
this.game.changeDirection(-1, 0); // 左滑
}
}
} else {
// 垂直滑动
if (Math.abs(deltaY) > minSwipeDistance) {
if (deltaY > 0) {
this.game.changeDirection(0, 1); // 下滑
} else {
this.game.changeDirection(0, -1); // 上滑
}
}
}
e.preventDefault();
}, { passive: false });
// 防止移动端页面滚动
document.addEventListener('touchmove', (e) => {
if (e.target.closest('.game-container')) {
e.preventDefault();
}
}, { passive: false });
}
// 震动反馈(移动端)
vibrate(duration = 50) {
if ('vibrate' in navigator) {
navigator.vibrate(duration);
}
}
}
// 初始化控制模块
document.addEventListener('DOMContentLoaded', () => {
// 等待游戏实例创建后初始化控制
setTimeout(() => {
new GameControls(game);
}, 100);
});

View File

@@ -0,0 +1,366 @@
class SnakeGame {
constructor() {
this.canvas = document.getElementById('gameCanvas');
this.ctx = this.canvas.getContext('2d');
// 游戏配置
this.gridSize = 20;
this.tileCount = this.canvas.width / this.gridSize;
this.tileCountY = this.canvas.height / this.gridSize;
// 蛇的初始状态
this.snake = [
{x: 10, y: 10},
{x: 9, y: 10},
{x: 8, y: 10}
];
// 食物位置
this.food = {x: 15, y: 15};
// 游戏状态
this.dx = 1; // 初始向右移动
this.dy = 0;
this.score = 0;
this.level = 1;
this.gameSpeed = 10; // 初始速度
this.isPaused = false;
this.gameOver = false;
this.startTime = Date.now();
this.foodEaten = 0;
// 特殊食物
this.specialFood = null;
this.specialFoodTimer = 0;
this.specialFoodDuration = 5000; // 5秒
this.init();
}
init() {
this.generateFood();
this.gameLoop();
// 监听键盘事件
document.addEventListener('keydown', (e) => {
if (this.isPaused || this.gameOver) return;
switch(e.key) {
case 'ArrowUp':
case 'w':
case 'W':
if (this.dy === 0) {
this.dx = 0;
this.dy = -1;
}
break;
case 'ArrowDown':
case 's':
case 'S':
if (this.dy === 0) {
this.dx = 0;
this.dy = 1;
}
break;
case 'ArrowLeft':
case 'a':
case 'A':
if (this.dx === 0) {
this.dx = -1;
this.dy = 0;
}
break;
case 'ArrowRight':
case 'd':
case 'D':
if (this.dx === 0) {
this.dx = 1;
this.dy = 0;
}
break;
case ' ':
this.togglePause();
break;
}
});
}
generateFood() {
// 生成普通食物
let newFood;
do {
newFood = {
x: Math.floor(Math.random() * this.tileCount),
y: Math.floor(Math.random() * this.tileCountY)
};
} while (this.isPositionOccupied(newFood));
this.food = newFood;
// 有10%几率生成特殊食物
if (Math.random() < 0.1 && !this.specialFood) {
this.generateSpecialFood();
}
}
generateSpecialFood() {
let newFood;
do {
newFood = {
x: Math.floor(Math.random() * this.tileCount),
y: Math.floor(Math.random() * this.tileCountY),
type: 'special',
value: 5 // 特殊食物价值5分
};
} while (this.isPositionOccupied(newFood));
this.specialFood = newFood;
this.specialFoodTimer = Date.now();
}
isPositionOccupied(position) {
// 检查是否与蛇身重叠
for (let segment of this.snake) {
if (segment.x === position.x && segment.y === position.y) {
return true;
}
}
// 检查是否与普通食物重叠
if (this.food && this.food.x === position.x && this.food.y === position.y) {
return true;
}
// 检查是否与特殊食物重叠
if (this.specialFood && this.specialFood.x === position.x && this.specialFood.y === position.y) {
return true;
}
return false;
}
update() {
if (this.isPaused || this.gameOver) return;
// 更新蛇头位置
const head = {x: this.snake[0].x + this.dx, y: this.snake[0].y + this.dy};
// 检查游戏结束条件
if (this.checkCollision(head)) {
this.gameOver = true;
this.showGameOver();
return;
}
// 移动蛇
this.snake.unshift(head);
// 检查是否吃到食物
if (head.x === this.food.x && head.y === this.food.y) {
this.score += 1;
this.foodEaten++;
this.generateFood();
this.updateLevel();
} else if (this.specialFood && head.x === this.specialFood.x && head.y === this.specialFood.y) {
this.score += this.specialFood.value;
this.foodEaten++;
this.specialFood = null;
this.generateFood();
this.updateLevel();
} else {
this.snake.pop(); // 如果没有吃到食物,移除尾部
}
// 检查特殊食物超时
if (this.specialFood && Date.now() - this.specialFoodTimer > this.specialFoodDuration) {
this.specialFood = null;
}
// 更新UI
this.updateUI();
}
checkCollision(head) {
// 检查撞墙
if (head.x < 0 || head.x >= this.tileCount || head.y < 0 || head.y >= this.tileCountY) {
return true;
}
// 检查撞到自己从第4节开始检查避免误判
for (let i = 4; i < this.snake.length; i++) {
if (this.snake[i].x === head.x && this.snake[i].y === head.y) {
return true;
}
}
return false;
}
updateLevel() {
// 每吃5个食物升一级
const newLevel = Math.floor(this.foodEaten / 5) + 1;
if (newLevel > this.level) {
this.level = newLevel;
this.gameSpeed = Math.min(20, 10 + this.level); // 速度上限20
}
}
updateUI() {
document.getElementById('score').textContent = this.score;
document.getElementById('length').textContent = this.snake.length;
document.getElementById('level').textContent = this.level;
}
draw() {
// 清空画布
this.ctx.fillStyle = '#222';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
// 绘制网格(背景)
this.ctx.strokeStyle = '#333';
this.ctx.lineWidth = 0.5;
for (let x = 0; x < this.tileCount; x++) {
for (let y = 0; y < this.tileCountY; y++) {
this.ctx.strokeRect(x * this.gridSize, y * this.gridSize, this.gridSize, this.gridSize);
}
}
// 绘制蛇
this.snake.forEach((segment, index) => {
if (index === 0) {
// 蛇头
this.ctx.fillStyle = '#4CAF50';
} else {
// 蛇身,渐变颜色
const gradient = (index / this.snake.length) * 100;
this.ctx.fillStyle = `hsl(120, 80%, ${60 - gradient}%)`;
}
this.ctx.fillRect(segment.x * this.gridSize, segment.y * this.gridSize, this.gridSize, this.gridSize);
// 边框
this.ctx.strokeStyle = '#2E7D32';
this.ctx.strokeRect(segment.x * this.gridSize, segment.y * this.gridSize, this.gridSize, this.gridSize);
});
// 绘制普通食物
this.ctx.fillStyle = '#FF5252';
this.ctx.beginPath();
this.ctx.arc(
this.food.x * this.gridSize + this.gridSize / 2,
this.food.y * this.gridSize + this.gridSize / 2,
this.gridSize / 2 - 2,
0,
Math.PI * 2
);
this.ctx.fill();
// 绘制特殊食物(如果存在)
if (this.specialFood) {
this.ctx.fillStyle = '#FFD700';
this.ctx.beginPath();
this.ctx.arc(
this.specialFood.x * this.gridSize + this.gridSize / 2,
this.specialFood.y * this.gridSize + this.gridSize / 2,
this.gridSize / 2 - 1,
0,
Math.PI * 2
);
this.ctx.fill();
// 闪烁效果
const time = Date.now() - this.specialFoodTimer;
const alpha = 0.5 + 0.5 * Math.sin(time / 200);
this.ctx.globalAlpha = alpha;
this.ctx.fillStyle = '#FF6B00';
this.ctx.fill();
this.ctx.globalAlpha = 1;
}
// 绘制暂停状态
if (this.isPaused) {
this.ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.fillStyle = 'white';
this.ctx.font = '24px Arial';
this.ctx.textAlign = 'center';
this.ctx.fillText('游戏暂停', this.canvas.width / 2, this.canvas.height / 2);
}
}
gameLoop() {
this.update();
this.draw();
if (!this.gameOver) {
setTimeout(() => this.gameLoop(), 1000 / this.gameSpeed);
}
}
togglePause() {
this.isPaused = !this.isPaused;
document.getElementById('pauseBtn').textContent = this.isPaused ? '继续' : '暂停';
if (!this.isPaused && !this.gameOver) {
this.gameLoop();
}
}
changeDirection(dx, dy) {
if (this.isPaused || this.gameOver) return;
// 防止180度转弯
if ((this.dx !== 0 && dx !== 0) || (this.dy !== 0 && dy !== 0)) {
return;
}
this.dx = dx;
this.dy = dy;
}
showGameOver() {
const modal = document.getElementById('gameOverModal');
const gameTime = Math.floor((Date.now() - this.startTime) / 1000);
document.getElementById('finalScore').textContent = this.score;
document.getElementById('finalLength').textContent = this.snake.length;
document.getElementById('finalLevel').textContent = this.level;
document.getElementById('gameTime').textContent = gameTime;
document.getElementById('foodEaten').textContent = this.foodEaten;
modal.style.display = 'flex';
}
restart() {
this.snake = [
{x: 10, y: 10},
{x: 9, y: 10},
{x: 8, y: 10}
];
this.dx = 1;
this.dy = 0;
this.score = 0;
this.level = 1;
this.gameSpeed = 10;
this.isPaused = false;
this.gameOver = false;
this.startTime = Date.now();
this.foodEaten = 0;
this.specialFood = null;
this.generateFood();
this.updateUI();
document.getElementById('gameOverModal').style.display = 'none';
document.getElementById('pauseBtn').textContent = '暂停';
this.gameLoop();
}
}
// 全局游戏实例
let game;
document.addEventListener('DOMContentLoaded', () => {
game = new SnakeGame();
});

View File

@@ -0,0 +1,295 @@
class GameStatistics {
constructor() {
this.highScores = JSON.parse(localStorage.getItem('snakeHighScores')) || [];
this.sessionStats = {
gamesPlayed: 0,
totalScore: 0,
maxLength: 0,
maxLevel: 0,
totalTime: 0
};
this.init();
}
init() {
// 恢复会话统计(如果存在)
const savedSession = localStorage.getItem('snakeSessionStats');
if (savedSession) {
this.sessionStats = JSON.parse(savedSession);
}
// 监听游戏事件
this.setupEventListeners();
}
setupEventListeners() {
// 监听自定义游戏事件
document.addEventListener('gameOver', (e) => {
this.handleGameOver(e.detail);
});
document.addEventListener('foodEaten', (e) => {
this.handleFoodEaten(e.detail);
});
document.addEventListener('levelUp', (e) => {
this.handleLevelUp(e.detail);
});
}
handleGameOver(gameData) {
this.sessionStats.gamesPlayed++;
this.sessionStats.totalScore += gameData.score;
this.sessionStats.maxLength = Math.max(this.sessionStats.maxLength, gameData.length);
this.sessionStats.maxLevel = Math.max(this.sessionStats.maxLevel, gameData.level);
this.sessionStats.totalTime += gameData.gameTime;
// 保存会话统计
localStorage.setItem('snakeSessionStats', JSON.stringify(this.sessionStats));
// 检查是否进入高分榜
this.checkHighScore(gameData);
// 显示统计信息
this.displaySessionStats();
}
handleFoodEaten(foodData) {
// 可以记录特殊食物统计等
console.log('食物被吃掉:', foodData);
}
handleLevelUp(levelData) {
// 等级提升统计
console.log('等级提升到:', levelData.level);
}
checkHighScore(gameData) {
const highScoreEntry = {
score: gameData.score,
length: gameData.length,
level: gameData.level,
time: gameData.gameTime,
date: new Date().toLocaleDateString(),
timestamp: Date.now()
};
// 添加到高分榜
this.highScores.push(highScoreEntry);
// 按分数排序(降序)
this.highScores.sort((a, b) => b.score - a.score);
// 只保留前10名
this.highScores = this.highScores.slice(0, 10);
// 保存到本地存储
localStorage.setItem('snakeHighScores', JSON.stringify(this.highScores));
// 显示高分榜
this.displayHighScores();
}
displaySessionStats() {
const statsElement = document.createElement('div');
statsElement.className = 'session-stats';
statsElement.innerHTML = `
<h3>本次会话统计</h3>
<p>游戏次数: ${this.sessionStats.gamesPlayed}</p>
<p>总得分: ${this.sessionStats.totalScore}</p>
<p>最高长度: ${this.sessionStats.maxLength}</p>
<p>最高等级: ${this.sessionStats.maxLevel}</p>
<p>总游戏时间: ${Math.floor(this.sessionStats.totalTime / 60)}分钟</p>
<p>平均得分: ${Math.round(this.sessionStats.totalScore / this.sessionStats.gamesPlayed)}</p>
`;
// 添加到游戏结束模态框
const statsContainer = document.querySelector('.stats');
if (statsContainer && !document.querySelector('.session-stats')) {
statsContainer.appendChild(statsElement);
}
}
displayHighScores() {
const highScoresElement = document.createElement('div');
highScoresElement.className = 'high-scores';
if (this.highScores.length > 0) {
highScoresElement.innerHTML = `
<h3>🏆 高分榜</h3>
${this.highScores.map((score, index) => `
<div class="score-item ${index === 0 ? 'first-place' : ''}">
<span class="rank">${index + 1}.</span>
<span class="score">${score.score}分</span>
<span class="length">长度:${score.length}</span>
<span class="date">${score.date}</span>
</div>
`).join('')}
`;
} else {
highScoresElement.innerHTML = '<p>暂无高分记录</p>';
}
// 添加到游戏结束模态框
const modalContent = document.querySelector('.modal-content');
if (modalContent && !document.querySelector('.high-scores')) {
modalContent.appendChild(highScoresElement);
}
}
getAchievements(gameData) {
const achievements = [];
if (gameData.score >= 100) achievements.push('百分达人');
if (gameData.length >= 20) achievements.push('长蛇之王');
if (gameData.level >= 5) achievements.push('等级大师');
if (gameData.gameTime >= 300) achievements.push('持久战将');
if (gameData.score >= 50 && gameData.gameTime <= 60) achievements.push('速通高手');
return achievements;
}
// 工具方法:格式化时间
formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins}${secs}`;
}
// 清除统计
clearStatistics() {
this.highScores = [];
this.sessionStats = {
gamesPlayed: 0,
totalScore: 0,
maxLength: 0,
maxLevel: 0,
totalTime: 0
};
localStorage.removeItem('snakeHighScores');
localStorage.removeItem('snakeSessionStats');
console.log('统计信息已清除');
}
}
// 扩展游戏核心类,添加统计事件触发
SnakeGame.prototype.showGameOver = function() {
const modal = document.getElementById('gameOverModal');
const gameTime = Math.floor((Date.now() - this.startTime) / 1000);
document.getElementById('finalScore').textContent = this.score;
document.getElementById('finalLength').textContent = this.snake.length;
document.getElementById('finalLevel').textContent = this.level;
document.getElementById('gameTime').textContent = gameTime;
document.getElementById('foodEaten').textContent = this.foodEaten;
// 触发游戏结束事件
const gameOverEvent = new CustomEvent('gameOver', {
detail: {
score: this.score,
length: this.snake.length,
level: this.level,
gameTime: gameTime,
foodEaten: this.foodEaten
}
});
document.dispatchEvent(gameOverEvent);
modal.style.display = 'flex';
};
// 初始化统计模块
let gameStats;
document.addEventListener('DOMContentLoaded', () => {
gameStats = new GameStatistics();
});
// 添加CSS样式
const statsStyles = `
.session-stats {
margin-top: 20px;
padding: 15px;
background: linear-gradient(135deg, #fdfcfb 0%, #e2d1c3 100%);
border-radius: 10px;
border: 2px solid #d4a76a;
}
.session-stats h3 {
color: #8b4513;
margin-bottom: 10px;
text-align: center;
}
.session-stats p {
margin: 5px 0;
color: #654321;
font-size: 0.9rem;
}
.high-scores {
margin-top: 20px;
padding: 15px;
background: linear-gradient(135deg, #fff1eb 0%, #ace0f9 100%);
border-radius: 10px;
border: 2px solid #4682b4;
}
.high-scores h3 {
color: #2c5282;
margin-bottom: 10px;
text-align: center;
}
.score-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #cbd5e0;
}
.score-item:last-child {
border-bottom: none;
}
.score-item.first-place {
background: linear-gradient(135deg, #fceabb 0%, #f8b500 100%);
border-radius: 5px;
padding: 8px;
margin: -8px -8px 8px -8px;
}
.rank {
font-weight: bold;
color: #2d3748;
min-width: 30px;
}
.score {
font-weight: bold;
color: #e53e3e;
min-width: 60px;
}
.length {
color: #4a5568;
font-size: 0.8rem;
min-width: 60px;
}
.date {
color: #718096;
font-size: 0.7rem;
min-width: 60px;
text-align: right;
}
`;
// 注入样式
const styleSheet = document.createElement('style');
styleSheet.textContent = statsStyles;
document.head.appendChild(styleSheet);

View File

@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>贪吃蛇游戏</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="game-container">
<div class="game-header">
<h1>贪吃蛇</h1>
<div class="score-board">
<span>分数: <span id="score">0</span></span>
<span>长度: <span id="length">3</span></span>
<span>等级: <span id="level">1</span></span>
</div>
</div>
<div class="game-canvas-container">
<canvas id="gameCanvas" width="300" height="500"></canvas>
</div>
<div class="game-controls">
<div class="control-row">
<button id="upBtn" class="control-btn"></button>
</div>
<div class="control-row">
<button id="leftBtn" class="control-btn"></button>
<button id="pauseBtn" class="control-btn">暂停</button>
<button id="rightBtn" class="control-btn"></button>
</div>
<div class="control-row">
<button id="downBtn" class="control-btn"></button>
</div>
</div>
<div class="game-instructions">
<p>使用方向键或触摸按钮控制蛇的方向</p>
</div>
</div>
<div id="gameOverModal" class="modal">
<div class="modal-content">
<h2>游戏结束!</h2>
<div class="stats">
<p>最终分数: <span id="finalScore">0</span></p>
<p>蛇的长度: <span id="finalLength">0</span></p>
<p>达到等级: <span id="finalLevel">0</span></p>
<p>游戏时间: <span id="gameTime">0</span></p>
<p>吃掉食物: <span id="foodEaten">0</span></p>
</div>
<button id="restartBtn" class="restart-btn">重新开始</button>
</div>
</div>
<script src="game-core.js"></script>
<script src="game-controls.js"></script>
<script src="game-stats.js"></script>
</body>
</html>

View File

@@ -0,0 +1,258 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
}
.game-container {
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
padding: 20px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
max-width: 400px;
width: 95%;
margin: 20px auto;
}
.game-header {
text-align: center;
margin-bottom: 20px;
}
.game-header h1 {
color: #333;
font-size: 2.5rem;
margin-bottom: 15px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
}
.score-board {
display: flex;
justify-content: space-around;
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
padding: 12px;
border-radius: 15px;
color: white;
font-weight: bold;
font-size: 1.1rem;
}
.score-board span {
display: flex;
flex-direction: column;
align-items: center;
}
.game-canvas-container {
display: flex;
justify-content: center;
margin: 20px 0;
}
#gameCanvas {
border: 3px solid #333;
border-radius: 10px;
background: #222;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
.game-controls {
margin: 20px 0;
}
.control-row {
display: flex;
justify-content: center;
margin: 8px 0;
}
.control-btn {
width: 70px;
height: 70px;
margin: 0 10px;
border: none;
border-radius: 50%;
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
font-size: 1.5rem;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.control-btn:hover {
transform: scale(1.1);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3);
}
.control-btn:active {
transform: scale(0.95);
}
#pauseBtn {
background: linear-gradient(135deg, #ff9a9e 0%, #fad0c4 100%);
color: #333;
font-size: 1.2rem;
}
.game-instructions {
text-align: center;
color: #666;
font-size: 0.9rem;
margin-top: 15px;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-content {
background: white;
padding: 30px;
border-radius: 20px;
text-align: center;
max-width: 400px;
width: 90%;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.4);
}
.modal-content h2 {
color: #e74c3c;
margin-bottom: 20px;
font-size: 2rem;
}
.stats p {
margin: 10px 0;
font-size: 1.1rem;
color: #333;
}
.stats span {
font-weight: bold;
color: #e74c3c;
}
.restart-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 15px 30px;
border-radius: 25px;
font-size: 1.2rem;
font-weight: bold;
cursor: pointer;
margin-top: 20px;
transition: all 0.3s ease;
}
.restart-btn:hover {
transform: scale(1.05);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
}
/* 手机端优化 */
@media (max-width: 768px) {
.game-container {
padding: 15px;
margin: 10px;
border-radius: 15px;
}
.game-header h1 {
font-size: 2rem;
}
.score-board {
font-size: 0.9rem;
padding: 8px;
}
.control-btn {
width: 60px;
height: 60px;
font-size: 1.3rem;
margin: 0 8px;
}
#pauseBtn {
font-size: 1rem;
}
#gameCanvas {
width: 280px;
height: 400px;
}
}
/* 超小屏幕优化 */
@media (max-width: 480px) {
.game-header h1 {
font-size: 1.8rem;
}
.score-board {
flex-direction: column;
gap: 5px;
}
.control-btn {
width: 50px;
height: 50px;
font-size: 1.1rem;
margin: 0 5px;
}
#gameCanvas {
width: 250px;
height: 350px;
}
.modal-content {
padding: 20px;
}
.modal-content h2 {
font-size: 1.5rem;
}
}
/* 防止文本选择 */
.control-btn, .restart-btn {
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
/* 动画效果 */
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}
.score-board {
animation: pulse 2s infinite;
}