1. 游戏概述:我们想要实现什么。
  2. HTML 结构:游戏画布和基本布局。
  3. CSS 样式:让游戏看起来更美观。
  4. JavaScript 游戏逻辑:核心代码,分步讲解。
  5. 完整代码:将所有部分整合在一起。

游戏概述

我们的贪吃蛇游戏将包含以下功能:

javascript编写网页游戏脚本
(图片来源网络,侵删)
  • 一个网格画布,蛇和食物在其中移动。
  • 玩家通过键盘方向键(或 WASD)控制蛇的移动方向。
  • 蛇吃到食物后,身体会变长,并且得分增加。
  • 如果蛇撞到墙壁或自己的身体,游戏结束,并显示最终得分。

HTML 结构

我们需要一个 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>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="game-container">
        <h1>贪吃蛇</h1>
        <div class="score-container">
            <span>得分: <span id="score">0</span></span>
        </div>
        <canvas id="gameCanvas" width="400" height="400"></canvas>
        <div id="gameOver" class="hidden">
            <h2>游戏结束!</h2>
            <p>最终得分: <span id="finalScore">0</span></p>
            <button id="restartButton">重新开始</button>
        </div>
    </div>
    <script src="script.js"></script>
</body>
</html>

解释:

  • <canvas id="gameCanvas">: 这是我们的游戏画布,所有图形都将在这里绘制,我们设置了宽度和高度为 400px。
  • <span id="score">: 用于实时显示当前得分。
  • <div id="gameOver">: 游戏结束时显示的界面,默认是隐藏的 (hidden 类)。
  • <script src="script.js">: 引入我们的 JavaScript 文件。

CSS 样式

创建一个 style.css 文件来美化我们的游戏。

body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #f0f0f0;
    font-family: Arial, sans-serif;
}
.game-container {
    text-align: center;
}
h1 {
    color: #333;
}
.score-container {
    margin: 10px 0;
    font-size: 1.2em;
    font-weight: bold;
}
#gameCanvas {
    background-color: #111;
    border: 2px solid #333;
    display: block; /* 移除 canvas 底部的小间隙 */
}
#gameOver {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: rgba(0, 0, 0, 0.8);
    color: white;
    padding: 20px;
    border-radius: 10px;
    text-align: center;
}
#gameOver h2 {
    margin-top: 0;
}
#restartButton {
    margin-top: 15px;
    padding: 10px 20px;
    font-size: 1em;
    cursor: pointer;
    background-color: #4CAF50;
    color: white;
    border: none;
    border-radius: 5px;
}
#restartButton:hover {
    background-color: #45a049;
}
.hidden {
    display: none;
}

JavaScript 游戏逻辑

这是最核心的部分,我们将创建一个 script.js 文件,并逐步构建游戏逻辑。

javascript编写网页游戏脚本
(图片来源网络,侵删)

步骤 1: 初始化和变量定义

// 1. 获取画布和上下文
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const finalScoreElement = document.getElementById('finalScore');
const gameOverElement = document.getElementById('gameOver');
const restartButton = document.getElementById('restartButton');
// 2. 游戏变量
const gridSize = 20; // 每个格子的大小
const tileCount = canvas.width / gridSize; // 网格数量 (20x20)
let snake = [
    {x: 10, y: 10} // 蛇的初始位置,用一个数组表示身体
];
let food = {}; // 食物的位置
let dx = 0; // 蛇在 x 轴上的移动速度 (0表示静止)
let dy = 0; // 蛇在 y 轴上的移动速度
let score = 0;
let gameRunning = true;

步骤 2: 生成食物

我们需要一个函数来随机生成食物的位置,并且不能生成在蛇的身体上。

function generateFood() {
    food = {
        x: Math.floor(Math.random() * tileCount),
        y: Math.floor(Math.random() * tileCount)
    };
    // 简单起见,我们不检查食物是否生成在蛇身上,因为概率很低
    // 更健壮的做法是循环检查,直到生成一个不与蛇身重叠的位置
}

步骤 3: 绘制游戏元素

我们需要绘制蛇和食物。

function drawGame() {
    // 清空画布
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    // 绘制蛇
    ctx.fillStyle = 'lime';
    snake.forEach(segment => {
        ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize - 2, gridSize - 2);
    });
    // 绘制食物
    ctx.fillStyle = 'red';
    ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize - 2, gridSize - 2);
}

步骤 4: 移动蛇和碰撞检测

这是游戏的核心逻辑。

function moveSnake() {
    if (!gameRunning) return;
    const head = {x: snake[0].x + dx, y: snake[0].y + dy};
    // 检查是否撞墙
    if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
        gameOver();
        return;
    }
    // 检查是否撞到自己
    for (let segment of snake) {
        if (head.x === segment.x && head.y === segment.y) {
            gameOver();
            return;
        }
    }
    snake.unshift(head); // 将新的头部添加到蛇身体数组的前面
    // 检查是否吃到食物
    if (head.x === food.x && head.y === food.y) {
        score += 10;
        scoreElement.textContent = score;
        generateFood(); // 生成新的食物
    } else {
        snake.pop(); // 如果没吃到食物,移除蛇的尾部
    }
}

步骤 5: 游戏循环

使用 setInterval 来控制游戏的节奏。

javascript编写网页游戏脚本
(图片来源网络,侵删)
function gameLoop() {
    moveSnake();
    drawGame();
}
// 初始化游戏
generateFood();
drawGame();
// 每 100毫秒 执行一次游戏循环,控制游戏速度
setInterval(gameLoop, 100);

步骤 6: 键盘控制

监听键盘事件来改变蛇的移动方向。

document.addEventListener('keydown', (e) => {
    if (!gameRunning) return;
    // 防止蛇直接掉头
    if (e.key === 'ArrowUp' && dy === 0) {
        dx = 0;
        dy = -1;
    } else if (e.key === 'ArrowDown' && dy === 0) {
        dx = 0;
        dy = 1;
    } else if (e.key === 'ArrowLeft' && dx === 0) {
        dx = -1;
        dy = 0;
    } else if (e.key === 'ArrowRight' && dx === 0) {
        dx = 1;
        dy = 0;
    }
    // 你也可以添加 WASD 控制
});

步骤 7: 游戏结束和重新开始

function gameOver() {
    gameRunning = false;
    finalScoreElement.textContent = score;
    gameOverElement.classList.remove('hidden');
}
restartButton.addEventListener('click', () => {
    // 重置所有游戏变量
    snake = [{x: 10, y: 10}];
    dx = 0;
    dy = 0;
    score = 0;
    scoreElement.textContent = score;
    gameRunning = true;
    generateFood();
    gameOverElement.classList.add('hidden');
});

完整代码

将以上所有 JavaScript 代码合并到 script.js 文件中。

script.js

// 1. 获取画布和上下文
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const finalScoreElement = document.getElementById('finalScore');
const gameOverElement = document.getElementById('gameOver');
const restartButton = document.getElementById('restartButton');
// 2. 游戏变量
const gridSize = 20; // 每个格子的大小
const tileCount = canvas.width / gridSize; // 网格数量 (20x20)
let snake = [
    {x: 10, y: 10} // 蛇的初始位置,用一个数组表示身体
];
let food = {}; // 食物的位置
let dx = 0; // 蛇在 x 轴上的移动速度 (0表示静止)
let dy = 0; // 蛇在 y 轴上的移动速度
let score = 0;
let gameRunning = true;
// 生成食物
function generateFood() {
    food = {
        x: Math.floor(Math.random() * tileCount),
        y: Math.floor(Math.random() * tileCount)
    };
}
// 绘制游戏
function drawGame() {
    // 清空画布
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    // 绘制蛇
    ctx.fillStyle = 'lime';
    snake.forEach(segment => {
        ctx.fillRect(segment.x * gridSize, segment.y * gridSize, gridSize - 2, gridSize - 2);
    });
    // 绘制食物
    ctx.fillStyle = 'red';
    ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize - 2, gridSize - 2);
}
// 移动蛇和碰撞检测
function moveSnake() {
    if (!gameRunning) return;
    const head = {x: snake[0].x + dx, y: snake[0].y + dy};
    // 检查是否撞墙
    if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
        gameOver();
        return;
    }
    // 检查是否撞到自己
    for (let segment of snake) {
        if (head.x === segment.x && head.y === segment.y) {
            gameOver();
            return;
        }
    }
    snake.unshift(head); // 将新的头部添加到蛇身体数组的前面
    // 检查是否吃到食物
    if (head.x === food.x && head.y === food.y) {
        score += 10;
        scoreElement.textContent = score;
        generateFood(); // 生成新的食物
    } else {
        snake.pop(); // 如果没吃到食物,移除蛇的尾部
    }
}
// 游戏循环
function gameLoop() {
    moveSnake();
    drawGame();
}
// 键盘控制
document.addEventListener('keydown', (e) => {
    if (!gameRunning) return;
    // 防止蛇直接掉头
    if (e.key === 'ArrowUp' && dy === 0) {
        dx = 0;
        dy = -1;
    } else if (e.key === 'ArrowDown' && dy === 0) {
        dx = 0;
        dy = 1;
    } else if (e.key === 'ArrowLeft' && dx === 0) {
        dx = -1;
        dy = 0;
    } else if (e.key === 'ArrowRight' && dx === 0) {
        dx = 1;
        dy = 0;
    }
});
// 游戏结束
function gameOver() {
    gameRunning = false;
    finalScoreElement.textContent = score;
    gameOverElement.classList.remove('hidden');
}
// 重新开始
restartButton.addEventListener('click', () => {
    snake = [{x: 10, y: 10}];
    dx = 0;
    dy = 0;
    score = 0;
    scoreElement.textContent = score;
    gameRunning = true;
    generateFood();
    gameOverElement.classList.add('hidden');
});
// 初始化游戏
generateFood();
drawGame();
setInterval(gameLoop, 100);

如何运行

  1. 创建一个项目文件夹,snake-game
  2. 在该文件夹中创建三个文件:index.htmlstyle.cssscript.js
  3. 将上面提供的代码分别复制到对应的文件中。
  4. 用浏览器打开 index.html 文件,即可开始游戏!

进一步的改进方向

这个贪吃蛇游戏已经具备了基本功能,你还可以尝试以下改进:

  • 难度选择:增加速度选择(Easy, Medium, Hard)。
  • 音效:添加吃食物和游戏结束的音效。
  • 最高分记录:使用 localStorage 来保存和显示历史最高分。
  • 更复杂的食物:例如不同颜色的食物有不同效果(加分、减速、变长等)。
  • 优化食物生成:确保食物不会生成在蛇身上。

希望这个详细的教程能帮助你理解如何用 JavaScript 编写一个网页游戏!