〇、前言
貪吃蛇是一款經典的休閑游戲,在諾基亞手機時代風靡全球。
作為編程入門者,實現一個貪吃蛇游戲是學習Web前端技術的絕佳練習。
名人說:博觀而約取,厚積而薄發。——蘇軾《稼說送張琥》
創作者:Code_流蘇(CSDN)(一個喜歡古詩詞和編程的Coder😊)目錄
- 〇、前言
- 效果預覽
- 一、HTML結構
- 二、CSS樣式設計
- 三、JavaScript游戲邏輯
- 四、代碼詳解
- 1. 游戲初始化
- 2. 生成食物
- 3. 移動蛇
- 4. 碰撞檢測
- 5. 游戲控制
- 五、完整代碼
很高興你打開了這篇博客,更多好用的軟件工具,請關注我、訂閱專欄《項目探索實驗室》,內容持續更新中…
思維速覽:
本文將詳細講解如何使用HTML、CSS和JavaScript從零開始創建一個功能完整的貪吃蛇網頁游戲(更多功能可以根據個人開發需求拓展)。
我們的貪吃蛇游戲將包含以下功能:
- 基礎的游戲邏輯(移動、吃食物、碰撞檢測)
- 分數記錄和最高分保存
- 游戲控制(開始、暫停、繼續)
- 自適應界面設計(支持PC和移動設備)
- 逐步提高的游戲難度
效果預覽
▍1??靜態展示:
▍2??動態展示:
完成后的游戲效果如下:
- 一個20x20格子的游戲場地
- 綠色的蛇,紅色的食物
- 頂部顯示當前分數和歷史最高分
- 底部有游戲控制按鈕和移動設備專用的方向控制鍵
一、HTML結構
首先,創建基本的HTML結構:
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>貪吃蛇小游戲</title><!-- CSS將在這里添加 -->
</head>
<body><h1>貪吃蛇小游戲</h1><div class="game-container"><div class="game-header"><div>分數: <span id="score">0</span></div><div>最高分: <span id="high-score">0</span></div></div><div id="game-board"></div><div class="controls"><button id="start-button">開始游戲</button><div class="mobile-controls"><button class="up">↑</button><button class="left">←</button><button class="right">→</button><button class="down">↓</button></div></div></div><!-- JavaScript將在這里添加 -->
</body>
</html>
這個HTML結構包含了:
- 游戲標題
- 分數和最高分顯示區域
- 游戲主畫布(game-board)
- 游戲控制按鈕
- 移動設備的方向控制按鈕
二、CSS樣式設計
接下來,我們需要添加CSS樣式,使游戲看起來更加美觀:
<style>body {display: flex;flex-direction: column;align-items: center;justify-content: center;height: 100vh;margin: 0;background-color: #f0f0f0;font-family: Arial, sans-serif;}.game-container {display: flex;flex-direction: column;align-items: center;}.game-header {display: flex;justify-content: space-between;width: 400px;margin-bottom: 10px;}#game-board {width: 400px;height: 400px;border: 2px solid #333;position: relative;background-color: #eee;}.snake-part {width: 20px;height: 20px;background-color: #4CAF50;position: absolute;border-radius: 2px;}.snake-head {background-color: #388E3C;}.food {width: 20px;height: 20px;background-color: #F44336;position: absolute;border-radius: 50%;}.controls {margin-top: 20px;display: flex;flex-direction: column;align-items: center;}button {padding: 10px 20px;margin: 5px;font-size: 16px;cursor: pointer;background-color: #2196F3;color: white;border: none;border-radius: 4px;}button:hover {background-color: #0b7dda;}.mobile-controls {display: grid;grid-template-columns: 1fr 1fr 1fr;grid-template-rows: 1fr 1fr 1fr;gap: 5px;margin-top: 15px;max-width: 200px;}.mobile-controls button {padding: 15px;margin: 0;}.up {grid-column: 2;grid-row: 1;}.left {grid-column: 1;grid-row: 2;}.right {grid-column: 3;grid-row: 2;}.down {grid-column: 2;grid-row: 3;}@media (max-width: 500px) {#game-board {width: 300px;height: 300px;}.game-header {width: 300px;}}
</style>
這些CSS樣式:
- 使用Flexbox和Grid布局
- 設計蛇和食物的外觀
- 美化按鈕和控件
- 添加響應式設計,適應不同屏幕尺寸
三、JavaScript游戲邏輯
最后,也是最重要的部分,我們需要實現游戲的核心邏輯:
<script>document.addEventListener('DOMContentLoaded', () => {// 游戲變量const boardSize = 20; // 20x20 格子const gridSize = 20; // 每個格子的大小(像素)const board = document.getElementById('game-board');const scoreElement = document.getElementById('score');const highScoreElement = document.getElementById('high-score');const startButton = document.getElementById('start-button');let snake = []; // 蛇的身體部分坐標let food = null; // 食物坐標let direction = 'right'; // 初始方向let nextDirection = 'right';let gameInterval = null;let score = 0;let highScore = localStorage.getItem('snakeHighScore') || 0;let gameSpeed = 150; // 游戲速度,毫秒let gameStarted = false;let gamePaused = false;highScoreElement.textContent = highScore;// 初始化游戲function initGame() {clearBoard();// 初始化蛇snake = [{x: 5, y: 10}, // 頭部{x: 4, y: 10},{x: 3, y: 10}];// 重置游戲狀態direction = 'right';nextDirection = 'right';score = 0;scoreElement.textContent = score;// 生成第一個食物generateFood();// 渲染初始狀態renderSnake();renderFood();}// 清空游戲板function clearBoard() {board.innerHTML = '';}// 生成食物function generateFood() {let foodPosition;let onSnake;do {// 隨機生成食物位置foodPosition = {x: Math.floor(Math.random() * boardSize),y: Math.floor(Math.random() * boardSize)};// 檢查食物是否與蛇重疊onSnake = snake.some(part => part.x === foodPosition.x && part.y === foodPosition.y);} while (onSnake);food = foodPosition;}// 渲染蛇function renderSnake() {snake.forEach((part, index) => {const snakePart = document.createElement('div');snakePart.className = 'snake-part';if (index === 0) {snakePart.classList.add('snake-head');}snakePart.style.left = `${part.x * gridSize}px`;snakePart.style.top = `${part.y * gridSize}px`;board.appendChild(snakePart);});}// 渲染食物function renderFood() {const foodElement = document.createElement('div');foodElement.className = 'food';foodElement.style.left = `${food.x * gridSize}px`;foodElement.style.top = `${food.y * gridSize}px`;board.appendChild(foodElement);}// 移動蛇function moveSnake() {// 更新方向direction = nextDirection;// 獲取蛇頭的當前位置const head = {...snake[0]};// 根據方向移動蛇頭switch (direction) {case 'up':head.y -= 1;break;case 'down':head.y += 1;break;case 'left':head.x -= 1;break;case 'right':head.x += 1;break;}// 檢查碰撞if (checkCollision(head)) {gameOver();return;}// 將新頭部添加到蛇的開始snake.unshift(head);// 檢查是否吃到食物if (head.x === food.x && head.y === food.y) {// 吃到食物,增加分數score += 10;scoreElement.textContent = score;// 更新最高分if (score > highScore) {highScore = score;highScoreElement.textContent = highScore;localStorage.setItem('snakeHighScore', highScore);}// 生成新食物generateFood();// 增加游戲速度if (gameSpeed > 50) {gameSpeed -= 2;clearInterval(gameInterval);gameInterval = setInterval(gameLoop, gameSpeed);}} else {// 沒吃到食物,移除蛇尾snake.pop();}// 重新渲染游戲clearBoard();renderSnake();renderFood();}// 檢查碰撞function checkCollision(head) {// 檢查墻壁碰撞if (head.x < 0 || head.x >= boardSize || head.y < 0 || head.y >= boardSize) {return true;}// 檢查自身碰撞return snake.some((part, index) => {// 跳過第一個元素,因為它就是頭部if (index === 0) return false;return part.x === head.x && part.y === head.y;});}// 游戲結束function gameOver() {clearInterval(gameInterval);alert(`游戲結束! 你的得分: ${score}`);gameStarted = false;startButton.textContent = '開始游戲';}// 游戲循環function gameLoop() {moveSnake();}// 開始游戲function startGame() {if (gameStarted) {// 如果游戲已經開始,暫停或繼續if (gamePaused) {// 繼續游戲gameInterval = setInterval(gameLoop, gameSpeed);startButton.textContent = '暫停游戲';gamePaused = false;} else {// 暫停游戲clearInterval(gameInterval);startButton.textContent = '繼續游戲';gamePaused = true;}} else {// 開始新游戲initGame();gameInterval = setInterval(gameLoop, gameSpeed);gameStarted = true;gamePaused = false;startButton.textContent = '暫停游戲';}}// 處理鍵盤輸入document.addEventListener('keydown', e => {if (!gameStarted || gamePaused) return;// 防止方向鍵引起頁面滾動if(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', ' '].includes(e.key)) {e.preventDefault();}// 更新方向switch (e.key) {case 'ArrowUp':if (direction !== 'down') nextDirection = 'up';break;case 'ArrowDown':if (direction !== 'up') nextDirection = 'down';break;case 'ArrowLeft':if (direction !== 'right') nextDirection = 'left';break;case 'ArrowRight':if (direction !== 'left') nextDirection = 'right';break;}});// 移動設備控制按鈕document.querySelector('.up').addEventListener('click', () => {if (direction !== 'down' && gameStarted && !gamePaused) nextDirection = 'up';});document.querySelector('.down').addEventListener('click', () => {if (direction !== 'up' && gameStarted && !gamePaused) nextDirection = 'down';});document.querySelector('.left').addEventListener('click', () => {if (direction !== 'right' && gameStarted && !gamePaused) nextDirection = 'left';});document.querySelector('.right').addEventListener('click', () => {if (direction !== 'left' && gameStarted && !gamePaused) nextDirection = 'right';});// 開始游戲按鈕startButton.addEventListener('click', startGame);// 初始化游戲initGame();});
</script>
四、代碼詳解
1. 游戲初始化
function initGame() {clearBoard();// 初始化蛇snake = [{x: 5, y: 10}, // 頭部{x: 4, y: 10},{x: 3, y: 10}];// 重置游戲狀態direction = 'right';nextDirection = 'right';score = 0;scoreElement.textContent = score;// 生成第一個食物generateFood();// 渲染初始狀態renderSnake();renderFood();
}
這個函數負責:
- 清空游戲板
- 創建初始長度為3的蛇
- 重置方向和分數
- 生成食物
- 渲染初始游戲狀態
2. 生成食物
function generateFood() {let foodPosition;let onSnake;do {// 隨機生成食物位置foodPosition = {x: Math.floor(Math.random() * boardSize),y: Math.floor(Math.random() * boardSize)};// 檢查食物是否與蛇重疊onSnake = snake.some(part => part.x === foodPosition.x && part.y === foodPosition.y);} while (onSnake);food = foodPosition;
}
這個函數:
- 隨機生成食物的位置
- 確保食物不會出現在蛇身上
- 使用do-while循環直到找到合適的位置
3. 移動蛇
function moveSnake() {// 更新方向direction = nextDirection;// 獲取蛇頭的當前位置const head = {...snake[0]};// 根據方向移動蛇頭switch (direction) {case 'up':head.y -= 1;break;case 'down':head.y += 1;break;case 'left':head.x -= 1;break;case 'right':head.x += 1;break;}// 檢查碰撞if (checkCollision(head)) {gameOver();return;}// 將新頭部添加到蛇的開始snake.unshift(head);// 檢查是否吃到食物if (head.x === food.x && head.y === food.y) {// 吃到食物,增加分數score += 10;scoreElement.textContent = score;// 更新最高分if (score > highScore) {highScore = score;highScoreElement.textContent = highScore;localStorage.setItem('snakeHighScore', highScore);}// 生成新食物generateFood();// 增加游戲速度if (gameSpeed > 50) {gameSpeed -= 2;clearInterval(gameInterval);gameInterval = setInterval(gameLoop, gameSpeed);}} else {// 沒吃到食物,移除蛇尾snake.pop();}// 重新渲染游戲clearBoard();renderSnake();renderFood();
}
這個函數是游戲的核心,它:
- 根據當前方向移動蛇頭
- 檢查是否發生碰撞
- 如果吃到食物,增加分數,生成新食物,加快游戲速度
- 如果沒吃到食物,移除蛇尾(保持長度不變)
- 更新游戲界面
4. 碰撞檢測
function checkCollision(head) {// 檢查墻壁碰撞if (head.x < 0 || head.x >= boardSize || head.y < 0 || head.y >= boardSize) {return true;}// 檢查自身碰撞return snake.some((part, index) => {// 跳過第一個元素,因為它就是頭部if (index === 0) return false;return part.x === head.x && part.y === head.y;});
}
這個函數檢查兩種碰撞情況:
- 蛇頭撞到墻壁(超出游戲邊界)
- 蛇頭撞到自己的身體
5. 游戲控制
function startGame() {if (gameStarted) {// 如果游戲已經開始,暫停或繼續if (gamePaused) {// 繼續游戲gameInterval = setInterval(gameLoop, gameSpeed);startButton.textContent = '暫停游戲';gamePaused = false;} else {// 暫停游戲clearInterval(gameInterval);startButton.textContent = '繼續游戲';gamePaused = true;}} else {// 開始新游戲initGame();gameInterval = setInterval(gameLoop, gameSpeed);gameStarted = true;gamePaused = false;startButton.textContent = '暫停游戲';}
}
這個函數處理游戲的控制邏輯:
- 開始新游戲
- 暫停正在進行的游戲
- 繼續已暫停的游戲
五、完整代碼
最后,我們將上面的HTML、CSS和JavaScript代碼合并,得到完整的貪吃蛇游戲:
<!--創作者:Code_流蘇(CSDN)-->
<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>貪吃蛇小游戲</title><style>body {display: flex;flex-direction: column;align-items: center;justify-content: center;height: 100vh;margin: 0;background-color: #f0f0f0;font-family: Arial, sans-serif;}.game-container {display: flex;flex-direction: column;align-items: center;}.game-header {display: flex;justify-content: space-between;width: 400px;margin-bottom: 10px;}#game-board {width: 400px;height: 400px;border: 2px solid #333;position: relative;background-color: #eee;}.snake-part {width: 20px;height: 20px;background-color: #4CAF50;position: absolute;border-radius: 2px;}.snake-head {background-color: #388E3C;}.food {width: 20px;height: 20px;background-color: #F44336;position: absolute;border-radius: 50%;}.controls {margin-top: 20px;display: flex;flex-direction: column;align-items: center;}button {padding: 10px 20px;margin: 5px;font-size: 16px;cursor: pointer;background-color: #2196F3;color: white;border: none;border-radius: 4px;}button:hover {background-color: #0b7dda;}.mobile-controls {display: grid;grid-template-columns: 1fr 1fr 1fr;grid-template-rows: 1fr 1fr 1fr;gap: 5px;margin-top: 15px;max-width: 200px;}.mobile-controls button {padding: 15px;margin: 0;}.up {grid-column: 2;grid-row: 1;}.left {grid-column: 1;grid-row: 2;}.right {grid-column: 3;grid-row: 2;}.down {grid-column: 2;grid-row: 3;}@media (max-width: 500px) {#game-board {width: 300px;height: 300px;}.game-header {width: 300px;}}</style>
</head>
<body><h1>貪吃蛇小游戲</h1><div class="game-container"><div class="game-header"><div>分數: <span id="score">0</span></div><div>最高分: <span id="high-score">0</span></div></div><div id="game-board"></div><div class="controls"><button id="start-button">開始游戲</button><div class="mobile-controls"><button class="up">↑</button><button class="left">←</button><button class="right">→</button><button class="down">↓</button></div></div></div><script>document.addEventListener('DOMContentLoaded', () => {// 游戲變量const boardSize = 20; // 20x20 格子const gridSize = 20; // 每個格子的大小(像素)const board = document.getElementById('game-board');const scoreElement = document.getElementById('score');const highScoreElement = document.getElementById('high-score');const startButton = document.getElementById('start-button');let snake = []; // 蛇的身體部分坐標let food = null; // 食物坐標let direction = 'right'; // 初始方向let nextDirection = 'right';let gameInterval = null;let score = 0;let highScore = localStorage.getItem('snakeHighScore') || 0;let gameSpeed = 150; // 游戲速度,毫秒let gameStarted = false;let gamePaused = false;highScoreElement.textContent = highScore;// 初始化游戲function initGame() {clearBoard();// 初始化蛇snake = [{x: 5, y: 10}, // 頭部{x: 4, y: 10},{x: 3, y: 10}];// 重置游戲狀態direction = 'right';nextDirection = 'right';score = 0;scoreElement.textContent = score;// 生成第一個食物generateFood();// 渲染初始狀態renderSnake();renderFood();}// 清空游戲板function clearBoard() {board.innerHTML = '';}// 生成食物function generateFood() {let foodPosition;let onSnake;do {// 隨機生成食物位置foodPosition = {x: Math.floor(Math.random() * boardSize),y: Math.floor(Math.random() * boardSize)};// 檢查食物是否與蛇重疊onSnake = snake.some(part => part.x === foodPosition.x && part.y === foodPosition.y);} while (onSnake);food = foodPosition;}// 渲染蛇function renderSnake() {snake.forEach((part, index) => {const snakePart = document.createElement('div');snakePart.className = 'snake-part';if (index === 0) {snakePart.classList.add('snake-head');}snakePart.style.left = `${part.x * gridSize}px`;snakePart.style.top = `${part.y * gridSize}px`;board.appendChild(snakePart);});}// 渲染食物function renderFood() {const foodElement = document.createElement('div');foodElement.className = 'food';foodElement.style.left = `${food.x * gridSize}px`;foodElement.style.top = `${food.y * gridSize}px`;board.appendChild(foodElement);}// 移動蛇function moveSnake() {// 更新方向direction = nextDirection;// 獲取蛇頭的當前位置const head = {...snake[0]};// 根據方向移動蛇頭switch (direction) {case 'up':head.y -= 1;break;case 'down':head.y += 1;break;case 'left':head.x -= 1;break;case 'right':head.x += 1;break;}// 檢查碰撞if (checkCollision(head)) {gameOver();return;}// 將新頭部添加到蛇的開始snake.unshift(head);// 檢查是否吃到食物if (head.x === food.x && head.y === food.y) {// 吃到食物,增加分數score += 10;scoreElement.textContent = score;// 更新最高分if (score > highScore) {highScore = score;highScoreElement.textContent = highScore;localStorage.setItem('snakeHighScore', highScore);}// 生成新食物generateFood();// 增加游戲速度if (gameSpeed > 50) {gameSpeed -= 2;clearInterval(gameInterval);gameInterval = setInterval(gameLoop, gameSpeed);}} else {// 沒吃到食物,移除蛇尾snake.pop();}// 重新渲染游戲clearBoard();renderSnake();renderFood();}// 檢查碰撞function checkCollision(head) {// 檢查墻壁碰撞if (head.x < 0 || head.x >= boardSize || head.y < 0 || head.y >= boardSize) {return true;}// 檢查自身碰撞return snake.some((part, index) => {// 跳過第一個元素,因為它就是頭部if (index === 0) return false;return part.x === head.x && part.y === head.y;});}// 游戲結束function gameOver() {clearInterval(gameInterval);alert(`游戲結束! 你的得分: ${score}`);gameStarted = false;startButton.textContent = '開始游戲';}// 游戲循環function gameLoop() {moveSnake();}// 開始游戲function startGame() {if (gameStarted) {// 如果游戲已經開始,暫停或繼續if (gamePaused) {// 繼續游戲gameInterval = setInterval(gameLoop, gameSpeed);startButton.textContent = '暫停游戲';gamePaused = false;} else {// 暫停游戲clearInterval(gameInterval);startButton.textContent = '繼續游戲';gamePaused = true;}} else {// 開始新游戲initGame();gameInterval = setInterval(gameLoop, gameSpeed);gameStarted = true;gamePaused = false;startButton.textContent = '暫停游戲';}}// 處理鍵盤輸入document.addEventListener('keydown', e => {if (!gameStarted || gamePaused) return;// 防止方向鍵引起頁面滾動if(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', ' '].includes(e.key)) {e.preventDefault();}// 更新方向switch (e.key) {case 'ArrowUp':if (direction !== 'down') nextDirection = 'up';break;case 'ArrowDown':if (direction !== 'up') nextDirection = 'down';break;case 'ArrowLeft':if (direction !== 'right') nextDirection = 'left';break;case 'ArrowRight':if (direction !== 'left') nextDirection = 'right';break;}});// 移動設備控制按鈕document.querySelector('.up').addEventListener('click', () => {if (direction !== 'down' && gameStarted && !gamePaused) nextDirection = 'up';});document.querySelector('.down').addEventListener('click', () => {if (direction !== 'up' && gameStarted && !gamePaused) nextDirection = 'down';});document.querySelector('.left').addEventListener('click', () => {if (direction !== 'right' && gameStarted && !gamePaused) nextDirection = 'left';});document.querySelector('.right').addEventListener('click', () => {if (direction !== 'left' && gameStarted && !gamePaused) nextDirection = 'right';});// 開始游戲按鈕startButton.addEventListener('click', startGame);// 初始化游戲initGame();});</script>
</body>
</html>
很感謝你能看到這里,如果你有哪些想學習的項目,歡迎在評論區分享!
創作者:Code_流蘇(CSDN)(一個喜歡古詩詞和編程的Coder😊)