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

deepseek v3 0324实现俄罗斯方块游戏 (HTML + Canvas 实现)

俄罗斯方块游戏 (HTML + Canvas 实现)

下面是一个完整的俄罗斯方块游戏实现,使用HTML5 Canvas渲染,具有美观的界面和完整的游戏功能。

<!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 {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
            font-family: 'Arial', sans-serif;
            color: white;
            overflow: hidden;
        }
        
        .game-container {
            display: flex;
            gap: 30px;
            align-items: flex-start;
        }
        
        #game-board {
            border: 4px solid rgba(255, 255, 255, 0.3);
            border-radius: 8px;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
            background-color: rgba(0, 0, 0, 0.2);
        }
        
        .side-panel {
            display: flex;
            flex-direction: column;
            gap: 20px;
            width: 200px;
        }
        
        .panel {
            background-color: rgba(0, 0, 0, 0.2);
            border: 2px solid rgba(255, 255, 255, 0.2);
            border-radius: 8px;
            padding: 15px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
        }
        
        h2 {
            margin: 0 0 15px 0;
            font-size: 20px;
            text-align: center;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
        }
        
        .score {
            font-size: 24px;
            font-weight: bold;
            text-align: center;
            margin: 10px 0;
        }
        
        #next-piece {
            width: 160px;
            height: 160px;
            margin: 0 auto;
        }
        
        .controls {
            margin-top: 20px;
        }
        
        .controls p {
            margin: 5px 0;
            font-size: 14px;
        }
        
        button {
            display: block;
            width: 100%;
            padding: 10px;
            margin-top: 10px;
            background: rgba(255, 255, 255, 0.1);
            border: 1px solid rgba(255, 255, 255, 0.3);
            border-radius: 4px;
            color: white;
            cursor: pointer;
            transition: all 0.3s;
        }
        
        button:hover {
            background: rgba(255, 255, 255, 0.2);
        }
        
        .game-over {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 100;
            display: none;
        }
        
        .game-over h1 {
            font-size: 48px;
            margin-bottom: 20px;
            color: #ff5555;
            text-shadow: 0 2px 10px rgba(0, 0, 0, 0.8);
        }
        
        .game-over button {
            width: 200px;
            padding: 15px;
            font-size: 18px;
        }
    </style>
</head>
<body>
    <div class="game-container">
        <canvas id="game-board" width="300" height="600"></canvas>
        
        <div class="side-panel">
            <div class="panel">
                <h2>分数</h2>
                <div class="score" id="score">0</div>
                <h2>等级</h2>
                <div class="score" id="level">1</div>
                <h2>行数</h2>
                <div class="score" id="lines">0</div>
            </div>
            
            <div class="panel">
                <h2>下一个</h2>
                <canvas id="next-piece" width="160" height="160"></canvas>
            </div>
            
            <div class="panel controls">
                <h2>操作</h2>
                <p>← → : 左右移动</p>
                <p>↑ : 旋转</p>
                <p>↓ : 加速下落</p>
                <p>空格 : 直接落下</p>
                <button id="pause-btn">暂停 (P)</button>
                <button id="new-game-btn">新游戏 (N)</button>
            </div>
        </div>
    </div>
    
    <div class="game-over" id="game-over">
        <h1>游戏结束!</h1>
        <div class="score" id="final-score">分数: 0</div>
        <button id="restart-btn">重新开始</button>
    </div>
    
    <script>
        // 游戏常量
        const COLS = 10;
        const ROWS = 20;
        const BLOCK_SIZE = 30;
        const COLORS = [
            null,
            '#FF0D72', // I
            '#0DC2FF', // J
            '#0DFF72', // L
            '#F538FF', // O
            '#FF8E0D', // S
            '#FFE138', // T
            '#3877FF'  // Z
        ];
        
        // 方块形状定义
        const SHAPES = [
            null,
            [[0, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [0, 0, 0, 0]], // I
            [[2, 0, 0], [2, 2, 2], [0, 0, 0]],                         // J
            [[0, 0, 3], [3, 3, 3], [0, 0, 0]],                         // L
            [[0, 4, 4], [0, 4, 4], [0, 0, 0]],                         // O
            [[0, 5, 5], [5, 5, 0], [0, 0, 0]],                         // S
            [[0, 6, 0], [6, 6, 6], [0, 0, 0]],                         // T
            [[7, 7, 0], [0, 7, 7], [0, 0, 0]]                          // Z
        ];
        
        // 游戏变量
        let canvas, ctx;
        let nextCanvas, nextCtx;
        let board;
        let piece, nextPiece;
        let score, level, lines;
        let dropCounter, dropInterval;
        let lastTime;
        let gameOver, paused;
        let animationId;
        
        // 初始化游戏
        function init() {
            canvas = document.getElementById('game-board');
            ctx = canvas.getContext('2d');
            
            nextCanvas = document.getElementById('next-piece');
            nextCtx = nextCanvas.getContext('2d');
            
            // 设置画布实际大小
            canvas.width = COLS * BLOCK_SIZE;
            canvas.height = ROWS * BLOCK_SIZE;
            
            // 缩放画布以适应CSS大小
            canvas.style.width = `${COLS * BLOCK_SIZE}px`;
            canvas.style.height = `${ROWS * BLOCK_SIZE}px`;
            
            ctx.scale(1, 1);
            
            resetGame();
            addEventListeners();
            
            lastTime = 0;
            animationId = requestAnimationFrame(update);
        }
        
        // 重置游戏状态
        function resetGame() {
            board = createMatrix(COLS, ROWS);
            score = 0;
            level = 1;
            lines = 0;
            dropInterval = 1000;
            gameOver = false;
            paused = false;
            
            updateScore();
            
            // 创建第一个方块和下一个方块
            piece = createPiece(Math.floor(Math.random() * 7) + 1);
            nextPiece = createPiece(Math.floor(Math.random() * 7) + 1);
            
            document.getElementById('pause-btn').textContent = '暂停 (P)';
            document.getElementById('game-over').style.display = 'none';
        }
        
        // 创建矩阵
        function createMatrix(width, height) {
            const matrix = [];
            while (height--) {
                matrix.push(new Array(width).fill(0));
            }
            return matrix;
        }
        
        // 创建方块
        function createPiece(type) {
            return {
                position: {x: Math.floor(COLS / 2) - 1, y: 0},
                shape: SHAPES[type],
                type: type
            };
        }
        
        // 绘制矩阵
        function drawMatrix(matrix, offset) {
            matrix.forEach((row, y) => {
                row.forEach((value, x) => {
                    if (value !== 0) {
                        ctx.fillStyle = COLORS[value];
                        ctx.fillRect(
                            x + offset.x,
                            y + offset.y,
                            1, 1
                        );
                        
                        // 添加方块边框和光泽效果
                        ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
                        ctx.lineWidth = 0.05;
                        ctx.strokeRect(
                            x + offset.x,
                            y + offset.y,
                            1, 1
                        );
                        
                        // 添加光泽效果
                        ctx.fillStyle = 'rgba(255, 255, 255, 0.1)';
                        ctx.fillRect(
                            x + offset.x + 0.1,
                            y + offset.y + 0.1,
                            0.3, 0.3
                        );
                    }
                });
            });
        }
        
        // 绘制下一个方块预览
        function drawNextPiece() {
            nextCtx.clearRect(0, 0, nextCanvas.width, nextCanvas.height);
            
            // 计算居中位置
            const offsetX = (nextCanvas.width / BLOCK_SIZE - nextPiece.shape[0].length) / 2;
            const offsetY = (nextCanvas.height / BLOCK_SIZE - nextPiece.shape.length) / 2;
            
            nextPiece.shape.forEach((row, y) => {
                row.forEach((value, x) => {
                    if (value !== 0) {
                        nextCtx.fillStyle = COLORS[value];
                        nextCtx.fillRect(
                            (x + offsetX) * BLOCK_SIZE,
                            (y + offsetY) * BLOCK_SIZE,
                            BLOCK_SIZE, BLOCK_SIZE
                        );
                        
                        // 添加方块边框和光泽效果
                        nextCtx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
                        nextCtx.lineWidth = 2;
                        nextCtx.strokeRect(
                            (x + offsetX) * BLOCK_SIZE,
                            (y + offsetY) * BLOCK_SIZE,
                            BLOCK_SIZE, BLOCK_SIZE
                        );
                        
                        // 添加光泽效果
                        nextCtx.fillStyle = 'rgba(255, 255, 255, 0.1)';
                        nextCtx.fillRect(
                            (x + offsetX) * BLOCK_SIZE + 3,
                            (y + offsetY) * BLOCK_SIZE + 3,
                            BLOCK_SIZE * 0.3, BLOCK_SIZE * 0.3
                        );
                    }
                });
            });
        }
        
        // 绘制游戏板
        function draw() {
            // 清除画布
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            
            // 绘制游戏板
            drawMatrix(board, {x: 0, y: 0});
            
            // 绘制当前方块
            drawMatrix(piece.shape, piece.position);
            
            // 绘制网格线
            ctx.strokeStyle = 'rgba(255, 255, 255, 0.05)';
            ctx.lineWidth = 0.5;
            
            // 垂直线
            for (let i = 0; i <= COLS; i++) {
                ctx.beginPath();
                ctx.moveTo(i * BLOCK_SIZE, 0);
                ctx.lineTo(i * BLOCK_SIZE, ROWS * BLOCK_SIZE);
                ctx.stroke();
            }
            
            // 水平线
            for (let i = 0; i <= ROWS; i++) {
                ctx.beginPath();
                ctx.moveTo(0, i * BLOCK_SIZE);
                ctx.lineTo(COLS * BLOCK_SIZE, i * BLOCK_SIZE);
                ctx.stroke();
            }
            
            // 绘制下一个方块
            drawNextPiece();
        }
        
        // 合并方块到游戏板
        function merge() {
            piece.shape.forEach((row, y) => {
                row.forEach((value, x) => {
                    if (value !== 0) {
                        board[y + piece.position.y][x + piece.position.x] = value;
                    }
                });
            });
        }
        
        // 碰撞检测
        function collide() {
            const [m, o] = [piece.shape, piece.position];
            for (let y = 0; y < m.length; ++y) {
                for (let x = 0; x < m[y].length; ++x) {
                    if (m[y][x] !== 0 &&
                        (board[y + o.y] === undefined ||
                         board[y + o.y][x + o.x] === undefined ||
                         board[y + o.y][x + o.x] !== 0)) {
                        return true;
                    }
                }
            }
            return false;
        }
        
        // 旋转方块
        function rotate() {
            const originalShape = piece.shape;
            
            // 转置矩阵
            for (let y = 0; y < piece.shape.length; ++y) {
                for (let x = 0; x < y; ++x) {
                    [piece.shape[x][y], piece.shape[y][x]] = 
                    [piece.shape[y][x], piece.shape[x][y]];
                }
            }
            
            // 反转每一行
            piece.shape.forEach(row => row.reverse());
            
            // 如果旋转后发生碰撞,则恢复原状
            if (collide()) {
                piece.shape = originalShape;
            }
        }
        
        // 移动方块
        function movePiece(direction) {
            piece.position.x += direction;
            if (collide()) {
                piece.position.x -= direction;
            }
        }
        
        // 方块下落
        function dropPiece() {
            piece.position.y++;
            if (collide()) {
                piece.position.y--;
                merge();
                removeLines();
                
                // 检查游戏是否结束
                if (piece.position.y === 0) {
                    gameOver = true;
                    document.getElementById('final-score').textContent = `分数: ${score}`;
                    document.getElementById('game-over').style.display = 'flex';
                    return;
                }
                
                // 生成新方块
                piece = nextPiece;
                nextPiece = createPiece(Math.floor(Math.random() * 7) + 1);
            }
            dropCounter = 0;
        }
        
        // 快速下落
        function hardDrop() {
            while (!collide()) {
                piece.position.y++;
            }
            piece.position.y--;
            dropPiece();
        }
        
        // 移除已填满的行
        function removeLines() {
            let linesCleared = 0;
            
            outer: for (let y = board.length - 1; y >= 0; --y) {
                for (let x = 0; x < board[y].length; ++x) {
                    if (board[y][x] === 0) {
                        continue outer;
                    }
                }
                
                // 移除当前行
                const row = board.splice(y, 1)[0].fill(0);
                board.unshift(row);
                ++y; // 重新检查当前行,因为所有行都下移了一行
                
                linesCleared++;
            }
            
            if (linesCleared > 0) {
                // 更新分数
                updateScore(linesCleared);
            }
        }
        
        // 更新分数
        function updateScore(linesCleared = 0) {
            if (linesCleared > 0) {
                // 根据消除的行数计算得分
                const points = [0, 100, 300, 500, 800][linesCleared] * level;
                score += points;
                lines += linesCleared;
                
                // 每消除10行升一级
                level = Math.floor(lines / 10) + 1;
                
                // 随着等级提高,下落速度加快
                dropInterval = Math.max(100, 1000 - (level - 1) * 100);
            }
            
            document.getElementById('score').textContent = score;
            document.getElementById('level').textContent = level;
            document.getElementById('lines').textContent = lines;
        }
        
        // 暂停/继续游戏
        function togglePause() {
            paused = !paused;
            document.getElementById('pause-btn').textContent = paused ? '继续 (P)' : '暂停 (P)';
            
            if (!paused) {
                lastTime = 0;
                animationId = requestAnimationFrame(update);
            } else {
                cancelAnimationFrame(animationId);
            }
        }
        
        // 游戏主循环
        function update(time = 0) {
            if (gameOver || paused) return;
            
            const deltaTime = time - lastTime;
            lastTime = time;
            
            dropCounter += deltaTime;
            if (dropCounter > dropInterval) {
                dropPiece();
            }
            
            draw();
            animationId = requestAnimationFrame(update);
        }
        
        // 添加事件监听器
        function addEventListeners() {
            document.addEventListener('keydown', event => {
                if (gameOver) return;
                
                if (event.key === 'p' || event.key === 'P') {
                    togglePause();
                    return;
                }
                
                if (paused) return;
                
                switch (event.key) {
                    case 'ArrowLeft':
                        movePiece(-1);
                        break;
                    case 'ArrowRight':
                        movePiece(1);
                        break;
                    case 'ArrowDown':
                        dropPiece();
                        break;
                    case 'ArrowUp':
                        rotate();
                        break;
                    case ' ':
                        hardDrop();
                        break;
                }
            });
            
            document.getElementById('pause-btn').addEventListener('click', togglePause);
            document.getElementById('new-game-btn').addEventListener('click', () => {
                cancelAnimationFrame(animationId);
                resetGame();
                lastTime = 0;
                animationId = requestAnimationFrame(update);
            });
            document.getElementById('restart-btn').addEventListener('click', () => {
                cancelAnimationFrame(animationId);
                resetGame();
                lastTime = 0;
                animationId = requestAnimationFrame(update);
            });
        }
        
        // 启动游戏
        window.addEventListener('load', init);
    </script>
</body>
</html>

游戏功能说明

  1. 基本功能

    • 完整的俄罗斯方块游戏逻辑
    • 7种经典方块形状
    • 方块旋转、移动、加速下落和直接落下
    • 行消除和分数计算
    • 等级系统(下落速度随等级提高)
    • 下一个方块预览
  2. 操作方式

    • 左右箭头:移动方块
    • 上箭头:旋转方块
    • 下箭头:加速下落
    • 空格键:直接落下
    • P键:暂停/继续游戏
    • N键:新游戏
  3. 界面特点

    • 渐变背景和半透明面板
    • 精美的方块渲染(带光泽效果)
    • 游戏网格线
    • 分数、等级和消除行数显示
    • 游戏结束画面
  4. 响应式设计

    • 游戏界面居中显示
    • 适合各种屏幕尺寸

您可以将此代码保存为HTML文件,然后在浏览器中打开即可开始游戏。游戏完全在客户端运行,不需要任何服务器支持。

相关文章:

  • React状态管理器的应用
  • Python小练习系列 Vol.6:单词搜索(网格回溯)
  • 测试cursor编辑器
  • Java基础 3.29
  • C++11·部分重要语法II
  • android11关机安卓充电的UI定制化
  • 练习题:110
  • Mybatis逆向工程
  • 【商城实战(94)】构建高并发的负载均衡与集群架构
  • RedHatLinux(2025.3.22)
  • 解决 macOS (M1 Pro) 上使用 Vite 进行 Build 打包时 Node 进程内存溢出的问题
  • 复现GitHub上`https://github.com/tobiasfshr/map4d`这个项目
  • Android学习总结之ContentProvider跨应用数据共享
  • 无需docker三步安装deepseek可视化操作软件-Open-WebUI
  • RabbitMQ消息相关
  • #C8# UVM中的factory机制 #S8.5# 对factory机制的重载进一步思考(二)
  • Hyperlane:Rust Web开发的未来,释放极致性能与简洁之美
  • 2025-3-29算法打卡
  • epoll 和ractor模型学习
  • Docker 的实质作用是什么
  • 青海省林业和草原局副局长旦增主动投案,正接受审查调查
  • 工信部:加快自动驾驶系统安全要求强制性国家标准研制
  • 秦洪看盘|浮现新预期,存量资金积极调仓
  • 马上评|“AI神医宇宙”欺诈,连演员都不请了
  • 媒体:每一个“被偷走的人生”,都该得到公道和正义
  • 央视曝光假进口保健品:警惕!保税仓发货不等于真进口