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

canvas snake game

在线演示
play

移动原理

在这里插入图片描述

代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Snake Game</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="game-container">
        <canvas id="gameCanvas"></canvas>
        <div class="score" id="score">Score: 0</div>
        <div class="game-over" id="gameOver">Game Over!<br><button onclick="restartGame()">Restart</button></div>
    </div>

    <script src="script.js"></script>
</body>
</html>

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-family: 'Arial', sans-serif;
    background: radial-gradient(circle, #1e3c72, #2a5298);
    color: #fff;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    overflow: hidden;
}

.game-container {
    position: relative;
    width: 90vw;
    height: 90vw;
    max-width: 600px;
    max-height: 600px;
    background: linear-gradient(135deg, #0d1117, #161b22);
    border-radius: 20px;
    overflow: hidden;
    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.5);
}

canvas {
    width: 100%;
    height: 100%;
    display: block;
}

.score {
    position: absolute;
    top: 10px;
    left: 10px;
    background: rgba(255, 255, 255, 0.1);
    padding: 10px 15px;
    border-radius: 5px;
    font-size: 18px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
}

.game-over {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: rgba(0, 0, 0, 0.9);
    padding: 30px 50px;
    border-radius: 20px;
    text-align: center;
    font-size: 24px;
    color: #fff;
    display: none;
    box-shadow: 0 8px 15px rgba(0, 0, 0, 0.6);
}

.game-over button {
    margin-top: 15px;
    padding: 10px 20px;
    background: #e63946;
    color: #fff;
    border: none;
    border-radius: 10px;
    font-size: 18px;
    cursor: pointer;
    transition: background 0.3s ease;
}

.game-over button:hover {
    background: #d62839;
}

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
canvas.width = canvas.height = Math.min(window.innerWidth * 0.9, 600);

const box = canvas.width / 30;
let score = 0;
let speed = 150;
let snake = [{ x: box * 5, y: box * 5 }];
let direction = 'RIGHT';
let food = generateFood();
let gameLoop;

function generateFood() {
    let foodX, foodY;
    do {
        foodX = Math.floor((Math.random() * canvas.width) / box) * box;
        foodY = Math.floor((Math.random() * canvas.height) / box) * box;
    } while (snake.some(segment => segment.x === foodX && segment.y === foodY));
    return { x: foodX, y: foodY };
}

document.addEventListener('keydown', changeDirection);

function changeDirection(event) {
    const key = event.key;
    const oppositeDirections = {
        UP: 'DOWN',
        DOWN: 'UP',
        LEFT: 'RIGHT',
        RIGHT: 'LEFT'
    };
    const newDirection = {
        ArrowUp: 'UP',
        ArrowDown: 'DOWN',
        ArrowLeft: 'LEFT',
        ArrowRight: 'RIGHT'
    }[key];
    if (newDirection && newDirection !== oppositeDirections[direction]) {
        direction = newDirection;
    }
}

function drawSnake() {
    snake.forEach((segment, index) => {
        ctx.fillStyle = index === 0 ? '#00ff88' : '#00cc66';
        ctx.fillRect(segment.x, segment.y, box, box);
        ctx.strokeStyle = '#161b22';
        ctx.strokeRect(segment.x, segment.y, box, box);
    });
}

function drawFood() {
    ctx.fillStyle = '#ff0033';
    ctx.beginPath();
    ctx.arc(food.x + box / 2, food.y + box / 2, box / 2.5, 0, Math.PI * 2);
    ctx.fill();
}

function moveSnake() {
    const head = { ...snake[0] };
    if (direction === 'UP') head.y -= box;
    else if (direction === 'DOWN') head.y += box;
    else if (direction === 'LEFT') head.x -= box;
    else if (direction === 'RIGHT') head.x += box;

    snake.unshift(head);

    if (head.x === food.x && head.y === food.y) {
        score += 10;
        document.getElementById('score').innerText = `Score: ${score}`;
        food = generateFood();
        if (speed > 50) speed -= 5;
        clearInterval(gameLoop);
        gameLoop = setInterval(update, speed);
    } else {
        snake.pop();
    }
}

function checkCollision() {
    const head = snake[0];
    if (
        head.x < 0 ||
        head.x >= canvas.width ||
        head.y < 0 ||
        head.y >= canvas.height ||
        snake.slice(1).some(segment => segment.x === head.x && segment.y === head.y)
    ) {
        document.getElementById('gameOver').style.display = 'block';
        clearInterval(gameLoop);
    }
}

function restartGame() {
    snake = [{ x: box * 5, y: box * 5 }];
    direction = 'RIGHT';
    score = 0;
    speed = 150;
    document.getElementById('score').innerText = `Score: 0`;
    document.getElementById('gameOver').style.display = 'none';
    food = generateFood();
    gameLoop = setInterval(update, speed);
}

function update() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawFood();
    moveSnake();
    drawSnake();
    checkCollision();
}

gameLoop = setInterval(update, speed);

window.addEventListener('resize', () => {
    canvas.width = canvas.height = Math.min(window.innerWidth * 0.9, 600);
});


http://www.kler.cn/a/511959.html

相关文章:

  • 服务器一次性部署One API + ChatGPT-Next-Web
  • JavaFx + SpringBoot 快速开始脚手架
  • 农业农村大数据应用场景|珈和科技“数字乡村一张图”解决方案
  • elasticsearch基础
  • C 语言的void*到底是什么?
  • Java开发提速秘籍:巧用Apache Commons Lang工具库
  • 面向CTF的python_requests库的学习笔记
  • 二十项零信任相关的前沿和趋势性技术-Extranet as a Service
  • 中国综合算力指数(2024年)报告汇总PDF洞察(附原数据表)
  • C#集合排序指南:掌握自定义排序的多种方法
  • 汇编学习笔记(自用)
  • LLM(3) : 浏览器录制16K的音频并上传到后端
  • UG NX二次开发(C#)-创建三维直线段并倒圆
  • 研1如何准备才能找到大厂实习?
  • Sudo命令的配置及使用
  • 【前端】CSS学习笔记(1)
  • Unity自学之旅01
  • JupyterLab 安装以及部分相关配置
  • WSL 2 自动更新 虚拟 IP 到 window hosts
  • 说说HashMap 的位操作以及HashSet的contains方法复杂度是多少?
  • std::forward实现原理与应用场景
  • Linux之socket编程(上)
  • Excel 技巧14 - 如何批量删除表格中的空行(★)
  • 工业现场数据实时采集:解锁工业智能化转型的关键
  • 深入理解Linux系统内存中文件结构以及缓冲区,模拟实现c语言库文件接口
  • 《重生到现代之从零开始的C++生活》—— 类和对象2