当前位置: 首页 > news >正文

使用HTML+JavaScript生成一个贪吃蛇游戏-demo

源码

<!DOCTYPE html>
<html lang="zh-CN">
<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 {
            position: relative;
        }
        #gameCanvas {
            border: 2px solid #333;
            background-color: #fff;
        }
        #score {
            position: absolute;
            top: -30px;
            left: 0;
            font-size: 20px;
            font-weight: bold;
        }
        #game-over {
            display: none;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
            background-color: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 20px;
            border-radius: 10px;
        }
        #restart-btn {
            margin-top: 10px;
            padding: 8px 16px;
            font-size: 16px;
            cursor: pointer;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
        }
        #restart-btn:hover {
            background-color: #45a049;
        }
    </style>
</head>
<body>
    <div id="game-container">
        <div id="score">分数: 0</div>
        <canvas id="gameCanvas" width="400" height="400"></canvas>
        <div id="game-over">
            <h2>游戏结束!</h2>
            <p>最终分数: <span id="final-score">0</span></p>
            <button id="restart-btn">重新开始</button>
        </div>
    </div>
    <script src="game.js"></script>
</body>
</html>
// 游戏配置
const config = {
    gridSize: 20,
    initialSpeed: 200,
    speedIncrease: 5
};

// 游戏状态
let snake = [];
let food = null;
let direction = 'right';
let nextDirection = 'right';
let score = 0;
let gameLoop = null;
let currentSpeed = config.initialSpeed;

// 获取DOM元素
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const gameOverElement = document.getElementById('game-over');
const finalScoreElement = document.getElementById('final-score');
const restartButton = document.getElementById('restart-btn');

// 计算网格大小
const cellSize = canvas.width / config.gridSize;

// 初始化游戏
function initGame() {
    // 初始化蛇
    snake = [
        { x: 5, y: 5 },
        { x: 4, y: 5 },
        { x: 3, y: 5 }
    ];
    
    // 重置游戏状态
    direction = 'right';
    nextDirection = 'right';
    score = 0;
    currentSpeed = config.initialSpeed;
    scoreElement.textContent = `分数: ${score}`;
    gameOverElement.style.display = 'none';
    
    // 生成第一个食物
    generateFood();
    
    // 开始游戏循环
    if (gameLoop) clearInterval(gameLoop);
    gameLoop = setInterval(gameStep, currentSpeed);
}

// 生成食物
function generateFood() {
    let newFood;
    do {
        newFood = {
            x: Math.floor(Math.random() * config.gridSize),
            y: Math.floor(Math.random() * config.gridSize)
        };
    } while (snake.some(segment => segment.x === newFood.x && segment.y === newFood.y));
    food = newFood;
}

// 游戏步骤
function gameStep() {
    // 更新方向
    direction = nextDirection;
    
    // 获取蛇头
    const head = { ...snake[0] };
    
    // 根据方向移动蛇头
    switch (direction) {
        case 'up': head.y--; break;
        case 'down': head.y++; break;
        case 'left': head.x--; break;
        case 'right': head.x++; break;
    }
    
    // 检查碰撞
    if (isCollision(head)) {
        gameOver();
        return;
    }
    
    // 移动蛇
    snake.unshift(head);
    
    // 检查是否吃到食物
    if (head.x === food.x && head.y === food.y) {
        score += 10;
        scoreElement.textContent = `分数: ${score}`;
        generateFood();
        
        // 加快游戏速度
        currentSpeed = Math.max(50, currentSpeed - config.speedIncrease);
        clearInterval(gameLoop);
        gameLoop = setInterval(gameStep, currentSpeed);
    } else {
        snake.pop();
    }
    
    // 绘制游戏
    draw();
}

// 碰撞检测
function isCollision(head) {
    // 检查是否撞墙
    if (head.x < 0 || head.x >= config.gridSize || head.y < 0 || head.y >= config.gridSize) {
        return true;
    }
    
    // 检查是否撞到自己
    return snake.some(segment => segment.x === head.x && segment.y === head.y);
}

// 绘制游戏
function draw() {
    // 清空画布
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // 绘制蛇
    snake.forEach((segment, index) => {
        ctx.fillStyle = index === 0 ? '#2ecc71' : '#27ae60';
        ctx.fillRect(segment.x * cellSize, segment.y * cellSize, cellSize - 1, cellSize - 1);
    });
    
    // 绘制食物
    ctx.fillStyle = '#e74c3c';
    ctx.fillRect(food.x * cellSize, food.y * cellSize, cellSize - 1, cellSize - 1);
}

// 游戏结束
function gameOver() {
    clearInterval(gameLoop);
    gameOverElement.style.display = 'block';
    finalScoreElement.textContent = score;
}

// 键盘控制
document.addEventListener('keydown', (event) => {
    switch (event.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;
    }
});

// 重启按钮事件
restartButton.addEventListener('click', initGame);

// 开始游戏
initGame();

相关文章:

  • 案例5_1:单位数码管显示0
  • ERC-6909 最小多代币标准
  • 2000-2023年各地级市二氧化碳排放量数据/地级市CO2排放量
  • 高数1.4 无穷小与无穷大
  • React-state响应式内部数据(类组件Hook两种方式整理)
  • Infura 简介
  • 英文LaTeX中左右引号怎么打
  • Unet nn-Unet
  • 【动手学深度学习】简单多层感知机实现图像分类处理
  • linux 常用命令及命令作用
  • 驱动通信封装
  • 【VUE】ant design vue实现表格table上下拖拽排序
  • Node.js框架Express、Koa、Koa2、Egg 和 NestJS 的对比分析
  • 4张图,9个方法,搞定 “信贷风控策略调优”
  • 在vue项目中,使用Patch请求,实现根据id修改某张发票的日结状态
  • 【前端】入门基础(二)格式化标签、img标签
  • 【免费】2004-2017年各地级市进出口总额数据
  • 单片机外设快速入门篇(六)——中断篇
  • kali通过永恒之蓝漏洞攻击目标机
  • 解决diffusers加载stablediffusion模型,输入prompt总是报错token数超出clip最大长度限制
  • 诠释微末处的丰盈:“上海制造佳品汇”首届海外专场即将亮相日本大阪
  • 融创中国:境外债务重组计划聆讯定于9月15日召开
  • 中美是否计划讨论美方以芬太尼为由对华征收的特别关税?外交部回应
  • 工人日报:“鼠标手”被纳入职业病,劳动保障网越织越密
  • 张笑宇:物质极大丰富之后,我们该怎么办?
  • 从采购到销售!市场监管总局指导行业协会防控肉品风险