使用js和canvas实现简单的网页贪吃蛇小游戏

玩法介绍

点击开始游戏后,使用键盘上的↑↓←→控制移动,吃到食物增加长度,碰到墙壁或碰到自身就游戏结束

代码实现

代码比较简单,直接阅读注释即可,复制即用

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Snake Game</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
        canvas {
            display: block;
            position: absolute;
            top: 0;
            left: 0;
            z-index: 1;
            background-color: #000;
        }
        .start-screen {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.8);
            color: white;
            text-align: center;
            z-index: 2;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 24px;
        }
        button {
            font-size: 24px;
            padding: 10px 20px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="start-screen">
        <h1>Snake Game</h1>
        <button id="startButton">Start Game</button>
    </div>
    <canvas id="gameCanvas" width="800" height="600"></canvas>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        // 设置 Canvas 为全屏
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        // 方块大小
        const blockSize = 20;

        // 游戏状态
        let snake = [{ x: 100, y: 100 }];
        let food = { x: 200, y: 200 };
        let direction = 'right';
        let score = 0;
        let isRunning = false;

        // 游戏速度
        const speed = 100;

        // 绘制蛇
        function drawSnake() {
            ctx.fillStyle = '#0f0';
            snake.forEach(segment => {
                ctx.fillRect(segment.x, segment.y, blockSize, blockSize);
            });
        }

        // 绘制食物
        function drawFood() {
            ctx.fillStyle = '#f00';
            ctx.fillRect(food.x, food.y, blockSize, blockSize);
        }

        // 检查碰撞
        function checkCollision() {
            // 检查蛇是否撞墙
            if (snake[0].x < 0 || snake[0].x >= canvas.width || snake[0].y < 0 || snake[0].y >= canvas.height) {
                alert('Game Over!');
                isRunning = false;
                return;
            }

            // 检查蛇是否撞到自己
            for (let i = 1; i < snake.length; i++) {
                if (snake[0].x === snake[i].x && snake[0].y === snake[i].y) {
                    alert('Game Over!');
                    isRunning = false;
                    return;
                }
            }

            // 检查蛇是否吃到食物
            if (snake[0].x === food.x && snake[0].y === food.y) {
                score++;
                placeFood();
            } else {
                snake.pop();
            }
        }

        // 放置新的食物
        function placeFood() {
            food = {
                x: Math.floor(Math.random() * (canvas.width / blockSize)) * blockSize,
                y: Math.floor(Math.random() * (canvas.height / blockSize)) * blockSize
            };
        }

        // 更新游戏状态
        function update() {
            if (!isRunning) return;

            let newX = snake[0].x;
            let newY = snake[0].y;

            if (direction === 'left') newX -= blockSize;
            if (direction === 'right') newX += blockSize;
            if (direction === 'up') newY -= blockSize;
            if (direction === 'down') newY += blockSize;

            snake.unshift({ x: newX, y: newY });

            checkCollision();
        }

        // 渲染游戏画面
        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            drawSnake();
            drawFood();
        }

        // 游戏主循环
        function gameLoop() {
            update();
            draw();
            setTimeout(gameLoop, speed);
        }

        // 键盘事件
        function handleKeyPress(event) {
            if (event.key === 'ArrowLeft' && direction !== 'right') direction = 'left';
            if (event.key === 'ArrowRight' && direction !== 'left') direction = 'right';
            if (event.key === 'ArrowUp' && direction !== 'down') direction = 'up';
            if (event.key === 'ArrowDown' && direction !== 'up') direction = 'down';
        }

        // 开始按钮事件
        document.getElementById('startButton').addEventListener('click', () => {
            const startScreen = document.querySelector('.start-screen');
            startScreen.style.display = 'none';

            // 添加键盘事件监听
            document.addEventListener('keydown', handleKeyPress);

            isRunning = true;
            placeFood();
            gameLoop();
        });

        // 游戏结束时移除键盘事件监听
        window.addEventListener('beforeunload', () => {
            document.removeEventListener('keydown', handleKeyPress);
        });
    </script>
</body>
</html>
相关推荐
子兮曰4 小时前
深入理解滑块验证码:那些你不知道的防破解机制
前端·javascript·canvas
Highcharts.js4 小时前
【Highcharts】如何用命令行渲染导出图片?
javascript·导出·开发文档·highcharts·命令行渲染·命令行功能
会一丢丢蝶泳的咻狗4 小时前
Sass实现,蛇形流动布局
前端·css
攀登的牵牛花5 小时前
前端向架构突围系列 - 状态数据设计 [8 - 4]:有限状态机 (FSM) 在复杂前端逻辑中的应用
前端
Lsx_5 小时前
前端视角下认识 AI Agent 和 LangChain
前端·人工智能·agent
陈振wx:zchen20085 小时前
JavaScript
javascript·js
我是伪码农5 小时前
Vue 智慧商城项目
前端·javascript·vue.js
不认输的西瓜5 小时前
fetch-event-source源码解读
前端·javascript
用户39051332192885 小时前
前端性能杀手竟然不是JS?图片优化才是绝大多数人忽略的"降本增效"方案
前端
朱昆鹏6 小时前
开源 Claude Code + Codex + 面板 的未来vibecoding平台
前端·后端·github