使用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>
相关推荐
卸任11 小时前
Vibe coding工具使用心得
前端·ai编程
brien911 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance12 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M12 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写12 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李12 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易12 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding12 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马12 小时前
前沿视界
前端
kyriewen12 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员