|
|
是的,刚刚提供的代码包括了HTML、CSS和JavaScript部分。为了确保所有部分都能正确地结合并运行,这里再次详细说明这些文件以及它们之间的关系。
### 文件结构
我们将文件分为三个部分:HTML结构文件(`index.html`)、CSS样式文件(`styles.css`)和JavaScript逻辑文件(`snake.js`)。
### 1. HTML 部分 (`index.html`)
这个文件包含网页的基本结构,包括游戏画布(`canvas`)、控制按钮、得分显示和模态窗口等:
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>贪吃蛇游戏</title>
- <link rel="stylesheet" href="styles.css">
- </head>
- <body>
- <!-- 开始界面 -->
- <div id="startScreen" class="active">
- <h1>欢迎来到贪吃蛇游戏</h1>
- <button id="startBtn">开始游戏</button>
- </div>
- <!-- 游戏界面 -->
- <div id="gameScreen">
- <div id="scoreBoard">得分: 0 | 最高分: 0</div>
- <canvas id="gameCanvas" width="400" height="400"></canvas>
- <div id="controls">
- <button id="pauseBtn">暂停</button>
- <button id="restartBtn">重启</button>
- </div>
- </div>
- <!-- 游戏结束屏幕 -->
- <div id="gameOverScreen">
- <h2>游戏结束!</h2>
- <p>最终得分: <span id="finalScore">0</span></p>
- <button id="restartGameOverBtn">重新开始</button>
- <button id="returnMainMenuBtn">返回主菜单</button>
- </div>
- <!-- 背景音乐和音效 -->
- <audio id="bgMusic" src="background-music.mp3" loop></audio>
- <audio id="eatSound" src="eat-sound.mp3"></audio>
- <script src="snake.js"></script>
- </body>
- </html>
复制代码
### 2. CSS 部分 (`styles.css`)
这个文件负责美化游戏界面:
- body {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- height: 100vh;
- margin: 0;
- font-family: Arial, sans-serif;
- background-color: #f0f0f0;
- background-image: url('background.jpg');
- background-size: cover;
- }
- #startScreen,
- #gameScreen,
- #gameOverScreen {
- display: none;
- flex-direction: column;
- align-items: center;
- text-align: center;
- }
- .active {
- display: flex;
- }
- h1 {
- font-size: 36px;
- margin-bottom: 20px;
- color: #333;
- }
- button {
- padding: 10px 20px;
- font-size: 18px;
- margin: 5px;
- cursor: pointer;
- border: none;
- border-radius: 5px;
- background-color: #4CAF50;
- color: white;
- transition: background-color 0.3s ease;
- }
- button:hover {
- background-color: #45a049;
- }
- button:active {
- background-color: #357737;
- }
- #scoreBoard {
- font-size: 24px;
- margin-bottom: 10px;
- }
- canvas {
- border: 2px solid #333;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
- }
- #controls {
- margin-top: 10px;
- display: flex;
- gap: 10px;
- }
- button:disabled {
- background-color: #CCCCCC;
- cursor: not-allowed;
- }
- #gameOverModal {
- position: fixed;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- padding: 20px;
- border-radius: 10px;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
- background-color: white;
- display: none;
- text-align: center;
- z-index: 1000;
- }
- #gameOverModal.active {
- display: block;
- }
- .modal-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.5);
- z-index: 999;
- display: none;
- }
- .modal-overlay.active {
- display: block;
- }
- .snake {
- transition: all 0.1s linear;
- }
- .food {
- animation: foodBlink 1.5s infinite;
- }
- @keyframes foodBlink {
- 0%, 100% {
- opacity: 1;
- }
- 50% {
- opacity: 0.5;
- }
- }
复制代码
### 3. JavaScript 部分 (`snake.js`)
这个文件包含游戏的主要逻辑,包括蛇的移动、食物生成、控制事件等:
- const canvas = document.getElementById('gameCanvas');
- const ctx = canvas.getContext('2d');
- const scoreBoard = document.getElementById('scoreBoard');
- const startBtn = document.getElementById('startBtn');
- const pauseBtn = document.getElementById('pauseBtn');
- const restartBtn = document.getElementById('restartBtn');
- const startScreen = document.getElementById('startScreen');
- const gameScreen = document.getElementById('gameScreen');
- const gameOverScreen = document.getElementById('gameOverScreen');
- const finalScoreElement = document.getElementById('finalScore');
- const restartGameOverBtn = document.getElementById('restartGameOverBtn');
- const returnMainMenuBtn = document.getElementById('returnMainMenuBtn');
- // 背景音乐和音效
- const bgMusic = document.getElementById('bgMusic');
- const eatSound = document.getElementById('eatSound');
- let snake, foods, direction, speed, score, highScore, gameInterval, obstacles;
- let gamePaused = false;
- const createSnake = () => [{ x: 10, y: 10 }];
- const createFoods = () => [
- { color: 'red', effect: increaseLength },
- { color: 'blue', effect: slowDown }
- ];
- const createObstacles = () => [
- { x: 5, y: 5 },
- { x: 15, y: 15 }
- ];
- const initGame = () => {
- snake = createSnake();
- foods = generateFoods();
- obstacles = generateObstacles();
- direction = { x: 0, y: 0 };
- speed = 200; // 初始速度
- score = 0;
- highScore = localStorage.getItem('highScore') || 0;
- updateScoreBoard();
- };
- const updateScoreBoard = () => {
- scoreBoard.textContent = `得分: ${score} | 最高分: ${highScore}`;
- };
- const increaseLength = () => {
- score += 10;
- };
- const slowDown = () => {
- speed = Math.min(300, speed + 50);
- score += 5;
- };
- const generateFoods = () => {
- return createFoods().map(food => ({
- ...food,
- x: Math.floor(Math.random() * 20),
- y: Math.floor(Math.random() * 20)
- }));
- };
- const generateObstacles = () => {
- return createObstacles().map(obstacle => ({
- ...obstacle,
- x: Math.floor(Math.random() * 20),
- y: Math.floor(Math.random() * 20)
- }));
- };
- const drawRect = (x, y, color, className) => {
- ctx.fillStyle = color || 'green';
- ctx.fillRect(x * 20, y * 20, 18, 18);
- const div = document.createElement('div');
- div.style.position = 'absolute';
- div.style.left = `${x * 20}px`;
- div.style.top = `${y * 20}px`;
- div.style.width = '18px';
- div.style.height = '18px';
- div.className = className;
- document.body.appendChild(div);
- };
- const updateSnake = () => {
- if (gamePaused) return;
- const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
- snake.unshift(head);
- let ateFood = false;
- foods.forEach(food => {
- if (head.x === food.x && head.y === food.y) {
- eatSound.play();
- food.effect(); // 执行食物的效果
- foods = generateFoods();
- ateFood = true;
- }
- });
- if (!ateFood) {
- snake.pop();
- }
- // 检测障碍物
- obstacles.forEach(obstacle => {
- if (head.x === obstacle.x && head.y === obstacle.y) {
- endGame();
- }
- });
- };
- const drawGame = () => {
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- foods.forEach(food => drawRect(food.x, food.y, food.color, 'food'));
- obstacles.forEach(obstacle => drawRect(obstacle.x, obstacle.y, 'brown', 'obstacle'));
- snake.forEach(part => drawRect(part.x, part.y, null, 'snake'));
- updateScoreBoard();
- };
- const showGameOverScreen = () => {
- gameOverScreen.classList.add('active');
- finalScoreElement.textContent = score;
- };
- const hideGameOverScreen = () => {
- gameOverScreen.classList.remove('active');
- };
- const endGame = () => {
- bgMusic.pause();
- if (score > highScore) {
- localStorage.setItem('highScore', score);
- }
- clearInterval(gameInterval);
- showGameOverScreen();
- };
- const gameLoop = () => {
- updateSnake();
- drawGame();
- const head = snake[0];
- if (head.x < 0 || head.x >= canvas.width / 20 || head.y < 0 || head.y >= canvas.height / 20 ||
- snake.slice(1).some(part => part.x === head.x && part.y === head.y)) {
- endGame();
- }
- };
- document.addEventListener('keydown', event => {
- if (event.key === 'ArrowUp' && direction.y === 0) direction = { x: 0, y: -1 };
- else if (event.key === 'ArrowDown' && direction.y === 0) direction = { x: 0, y: 1 };
- else if (event.key === 'ArrowLeft' && direction.x === 0) direction = { x: -1, y: 0 };
- else if (event.key === 'ArrowRight' && direction.x === 0) direction = { x: 1, y: 0 };
- });
- const handleTouchSwipe = direction => {
- if (direction === 'up' && direction.y === 0) direction = { x: 0, y: -1 };
- else if (direction === 'down' && direction.y === 0) direction = { x: 0, y: 1 };
- else if (direction === 'left' && direction.x === 0) direction = { x: -1, y: 0 };
- else if (direction === 'right' && direction.x === 0) direction = { x: 1, y: 0 };
- };
- // 添加触摸事件监听器
- window.addEventListener('touchstart', handleTouchStart, false);
- window.addEventListener('touchmove', handleTouchMove, false);
- let xDown = null;
- let yDown = null;
- function getTouches(evt) {
- return evt.touches || evt.originalEvent.touches;
- }
- function handleTouchStart(evt) {
- const firstTouch = getTouches(evt)[0];
- xDown = firstTouch.clientX;
- yDown = firstTouch.clientY;
- }
- function handleTouchMove(evt) {
- if (!xDown || !yDown) {
- return;
- }
- const xUp = evt.touches[0].clientX;
- const yUp = evt.touches[0].clientY;
- const xDiff = xDown - xUp;
- const yDiff = yDown - yUp;
- if (Math.abs(xDiff) > Math.abs(yDiff)) {
- if (xDiff > 0) handleTouchSwipe('left');
- else handleTouchSwipe('right');
- } else {
- if (yDiff > 0) handleTouchSwipe('up');
- else handleTouchSwipe('down');
- }
- xDown = null;
- yDown = null;
- }
- const pauseGame = () => {
- gamePaused = !gamePaused;
- if (!gamePaused) gameInterval = setInterval(gameLoop, speed);
- else clearInterval(gameInterval);
- };
- const restartGame = () => {
- clearInterval(gameInterval);
- hideGameOverScreen();
- initGame();
- bgMusic.play();
- gamePaused = false;
- gameInterval = setInterval(gameLoop, speed);
- };
- startBtn.addEventListener('click', () => {
- startScreen.classList.remove('active');
- gameScreen.classList.add('active');
- initGame();
- bgMusic.play();
- gameInterval = setInterval(gameLoop, speed);
- });
- pauseBtn.addEventListener('click', pauseGame);
- restartBtn.addEventListener('click', restartGame);
- restartGameOverBtn.addEventListener('click', restartGame);
- returnMainMenuBtn.addEventListener('click', () => {
- gameOverScreen.classList.remove('active');
- startScreen.classList.add('active');
- bgMusic.pause();
- });
- initGame();
复制代码
### 总结
以上提供的代码包括HTML、CSS和JavaScript三部分,确保你的文件结构和内容与上述代码一致,并且在相应的位置放置背景图片`background.jpg`和音频文件`background-music.mp3`、`eat-sound.mp3`。
通过这些优化,你的贪吃蛇游戏将变得更加丰富和有趣。如果你有其他需求或问题,请随时告诉我,我很愿意帮助你继续优化和完善这个游戏! |
|