使用HTML、CSS和JavaScript实现的俄罗斯方块游戏

俄罗斯方块游戏

一个使用纯HTML、CSS和JavaScript实现的俄罗斯方块游戏。

游戏概述

俄罗斯方块是一款经典的益智游戏,本实现使用纯HTML、CSS和JavaScript构建,无需任何外部框架或库。游戏保留了经典俄罗斯方块的核心玩法,同时加入了现代界面设计和增强功能。

游戏特点

  • 🎮 经典玩法:包含7种不同形状的方块,通过旋转和移动来消除行
  • 👁️ 方块预览:显示下一个将出现的方块,帮助玩家提前规划
  • 👻 幽灵方块:显示当前方块落地位置的半透明提示
  • 🔢 分数系统:根据消除行数计算得分,并显示当前等级
  • 🎚️ 难度选择:提供初级、中级、高级三种难度选择
  • 🎛️ 游戏控制:支持暂停/继续、重新开始功能

操作说明

  • ← → : 左右移动方块
  • ↑ : 旋转方块
  • ↓ : 加速方块下落
  • 空格 : 方块直接落到底部
  • P : 暂停/继续游戏
  • R : 重新开始游戏

游戏截图

俄罗斯方块游戏截图

在线体验

🎮 点击这里在线体验游戏

喜欢的话,可以去我的github上Fork一下
俄罗斯方块github仓库

使用git复制下面代码即可下载到本地

git clone https://github.com/Forminio/tetris-game.git

打开index.html文件即可开始游戏

核心实现逻辑

数据结构

  1. 游戏板网格:使用二维数组 boardGrid 表示游戏板,0表示空白,非0值表示已固定的方块类型
  2. 方块形状:使用 SHAPES 数组存储7种不同形状的方块及其类型
  3. 当前方块:使用 currentShapecurrentTypecurrentRowcurrentCol 跟踪当前活动方块
  4. 下一个方块:使用 nextShapenextType 存储下一个将出现的方块

主要功能模块

1. 游戏初始化

游戏初始化时,设置基本参数(行数、列数、方块大小等),创建游戏板网格,并添加键盘和按钮事件监听器。

2. 方块生成与移动

方块生成时,会随机选择一种形状,并设置初始位置。方块移动时,会先检查移动是否有效(是否会与其他方块或边界碰撞),然后更新位置并重绘。

3. 碰撞检测与方块固定

碰撞检测用于判断方块是否可以移动到指定位置。当方块无法继续下落时,会将其固定到游戏板上,然后检查是否有可消除的行,并生成新的方块。

4. 行消除与分数计算

当一行被方块填满时,该行会被消除,并在顶部添加新的空行。消除行数会影响得分和游戏等级,等级提升会加快方块下落速度。

5. 用户交互

游戏支持键盘和按钮操作,用户可以通过键盘控制方块移动、旋转和加速下落,也可以通过按钮开始、暂停和重新开始游戏,以及选择难度级别。

核心功能详解

1. 方块旋转算法

方块旋转是通过矩阵转置和行反转实现的:

旋转算法会创建方块矩阵的副本,然后进行90度旋转。如果旋转后的位置发生碰撞,会尝试"墙踢"(wall kick)操作,即尝试向左右移动以适应旋转。

2. 幽灵方块实现

幽灵方块是当前方块在不移动的情况下,能够下落到的最低位置的半透明提示:

幽灵方块通过模拟当前方块下落直到碰撞来确定位置,然后在该位置绘制半透明的方块,帮助玩家规划落点。

3. 游戏状态管理

游戏状态管理确保游戏在不同状态下有正确的行为,例如在暂停状态下停止方块下落,在游戏结束状态下显示结束界面等。

实现亮点

  1. 模块化设计:游戏逻辑被分解为多个功能模块,如方块生成、碰撞检测、行消除等,使代码结构清晰。

  2. 响应式界面:游戏界面使用CSS实现响应式设计,适配不同屏幕尺寸。

  3. 高效渲染:使用DOM操作而非Canvas绘制,通过只更新变化的部分来提高性能。

  4. 增强游戏体验:添加了幽灵方块、方块预览、难度选择等功能,提升游戏体验。

  5. 状态管理:实现了完整的游戏状态管理,包括开始、暂停、继续和结束状态。

以下是完整实现代码

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>俄罗斯方块</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        /* 创建隐形盒子撑开页面 */
        .page-container {
            width: 100%;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
            background-color: transparent;
        }
        
        body {
            font-family: 'Microsoft YaHei', sans-serif;
            background-color: #000;
            color: #ffffff;
            margin: 0;
            padding: 0;
            width: 100%;
            min-height: 100vh;
            background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><rect fill="none" width="100" height="100"/><rect fill="%23111" width="50" height="50"/><rect fill="%23111" x="50" y="50" width="50" height="50"/></svg>');
            background-size: 20px 20px;
        }
 
        .outer-container {
            width: 800px;
            background-color: #c0c0c0;
            border: 3px outset #eee;
            border-radius: 8px;
            padding: 15px;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
        }
        
        .header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
            padding: 0 10px;
        }
        
        .title {
            font-size: 24px;
            font-weight: bold;
            color: #333;
            text-shadow: 1px 1px 1px #fff;
        }
        
        .counter {
            background-color: #000;
            color: #f00;
            font-family: 'Digital', monospace;
            font-size: 24px;
            padding: 5px 10px;
            border: 2px inset #888;
            min-width: 80px;
            text-align: center;
        }
        
        .difficulty-buttons {
            display: flex;
            justify-content: center;
            gap: 10px;
            margin-bottom: 15px;
        }
        
        .difficulty-button {
            padding: 8px 15px;
            background-color: #d9d9d9;
            border: 2px outset #eee;
            color: #333;
            font-weight: bold;
            cursor: pointer;
            border-radius: 4px;
        }
        
        .difficulty-button:active, .difficulty-button.active {
            border-style: inset;
            background-color: #bbb;
        }
        
        .game-area {
            display: flex;
            justify-content: center;
            background-color: #d9d9d9;
            border: 3px inset #aaa;
            padding: 20px;
        }
        
        .game-container {
            display: flex;
            gap: 20px;
        }
 
        #tetris {
            width: 300px;
            display: flex;
            flex-direction: column;
            gap: 15px;
        }
 
        #game-board {
            width: 300px;
            height: 600px;
            border: 4px solid #4b6014;
            position: relative;
            border-radius: 10px;
            background-color: rgba(0, 0, 0, 0.8);
            overflow: hidden;
        }
 
        .info-panel {
            width: 150px;
            display: flex;
            flex-direction: column;
            gap: 20px;
        }
 
        .panel-box {
            background-color: rgba(0, 0, 0, 0.6);
            border-radius: 10px;
            padding: 15px;
            border: 2px solid #4b6014;
        }
 
        .panel-title {
            font-size: 18px;
            margin-bottom: 10px;
            color: #61dafb;
            text-align: center;
        }
 
        #next-piece {
            width: 120px;
            height: 120px;
            position: relative;
            margin: 0 auto;
        }
 
        #score, #level, #lines {
            text-align: center;
            font-size: 18px;
            margin: 5px 0;
        }
 
        #score-value, #level-value, #lines-value {
            font-weight: bold;
            color: #ffcc00;
        }
 
        .controls {
            margin-top: 10px;
        }
 
        .controls p {
            margin: 5px 0;
            font-size: 14px;
        }
 
        .block {
            width: 30px;
            height: 30px;
            position: absolute;
            box-sizing: border-box;
            border-radius: 3px;
        }
        
        /* 方块颜色 */
        .block-i { background-color: #00f0f0; border: 2px solid #00d0d0; }
        .block-o { background-color: #f0f000; border: 2px solid #d0d000; }
        .block-t { background-color: #a000f0; border: 2px solid #8000d0; }
        .block-s { background-color: #00f000; border: 2px solid #00d000; }
        .block-z { background-color: #f00000; border: 2px solid #d00000; }
        .block-j { background-color: #0000f0; border: 2px solid #0000d0; }
        .block-l { background-color: #f0a000; border: 2px solid #d08000; }
        
        .game-over {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.8);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 10;
            display: none;
        }
        
        .game-over h2 {
            color: #f00;
            font-size: 32px;
            margin-bottom: 20px;
        }
        
        .game-over button {
            padding: 10px 20px;
            font-size: 18px;
            background-color: #4b6014;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        
        .game-over button:hover {
            background-color: #5c7018;
        }
        
        .footer {
            display: flex;
            justify-content: center;
            margin-top: 15px;
            gap: 10px;
        }
        
        .new-game-btn {
            padding: 10px 20px;
            background-color: #d9d9d9;
            border: 2px outset #eee;
            color: #333;
            font-weight: bold;
            cursor: pointer;
            border-radius: 4px;
            font-size: 16px;
        }
        
        .new-game-btn:active {
            border-style: inset;
            background-color: #bbb;
        }
        
        .start-screen {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.8);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 20;
        }
        
        .start-screen h2 {
            color: #61dafb;
            font-size: 32px;
            margin-bottom: 20px;
        }
        
        .start-screen button {
            padding: 10px 20px;
            font-size: 18px;
            background-color: #4b6014;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            margin: 5px 0;
        }
        
        .start-screen button:hover {
            background-color: #5c7018;
        }
        
        @font-face {
            font-family: 'Digital';
            src: url('https://fonts.cdnfonts.com/css/ds-digital') format('woff2');
        }
    </style>
</head>

<body>
    <div class="page-container">
        <div class="outer-container">
            <div class="header">
                <div class="counter" id="lines-counter">0</div>
                <div class="title">俄罗斯方块</div>
                <div class="counter" id="score-counter">0</div>
            </div>
            
            <div class="difficulty-buttons">
                <div class="difficulty-button active" data-speed="1000">初级</div>
                <div class="difficulty-button" data-speed="700">中级</div>
                <div class="difficulty-button" data-speed="400">高级</div>
            </div>
            
            <div class="game-area">
                <div class="game-container">
                    <div id="tetris">
                        <div id="game-board">
                            <div class="start-screen" id="start-screen">
                                <h2>俄罗斯方块</h2>
                                <button id="start-btn">开始游戏</button>
                                <button id="how-to-play-btn">游戏说明</button>
                            </div>
                            <div class="game-over">
                                <h2>游戏结束!</h2>
                                <button id="restart-btn">重新开始</button>
                            </div>
                        </div>
                    </div>
                    <div class="info-panel">
                        <div class="panel-box">
                            <div class="panel-title">下一个方块</div>
                            <div id="next-piece"></div>
                        </div>
                        <div class="panel-box">
                            <div id="score">分数: <span id="score-value">0</span></div>
                            <div id="level">等级: <span id="level-value">1</span></div>
                            <div id="lines">消除行数: <span id="lines-value">0</span></div>
                        </div>
                        <div class="panel-box">
                            <div class="panel-title">操作说明</div>
                            <div class="controls">
                                <p>← → : 左右移动</p>
                                <p>↑ : 旋转方块</p>
                                <p>↓ : 加速下落</p>
                                <p>空格 : 直接落下</p>
                                <p>P : 暂停游戏</p>
                                <p>R : 重新开始</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            
            <div class="footer">
                <button class="new-game-btn" id="new-game-btn">新游戏</button>
                <button class="new-game-btn" id="pause-btn">暂停</button>
            </div>
        </div>
    </div>
</body>

<script>
    document.addEventListener('DOMContentLoaded', () => {
        let board = document.getElementById('game-board');
        let nextPieceDisplay = document.getElementById('next-piece');
        let scoreValue = document.getElementById('score-value');
        let levelValue = document.getElementById('level-value');
        let linesValue = document.getElementById('lines-value');
        let scoreCounter = document.getElementById('score-counter');
        let linesCounter = document.getElementById('lines-counter');
        let restartBtn = document.getElementById('restart-btn');
        let newGameBtn = document.getElementById('new-game-btn');
        let pauseBtn = document.getElementById('pause-btn');
        let startBtn = document.getElementById('start-btn');
        let howToPlayBtn = document.getElementById('how-to-play-btn');
        let startScreen = document.getElementById('start-screen');
        let gameOverScreen = document.querySelector('.game-over');
        let difficultyButtons = document.querySelectorAll('.difficulty-button');
        
        let blockSize = 30;
        let rows = 20;
        let cols = 10;
        let score = 0;
        let level = 1;
        let lines = 0;
        let gameSpeed = 1000; // 初始下落速度(毫秒)
        let gameInterval;
        let isPaused = false;
        let isGameStarted = false;
        
        let boardGrid = Array.from(Array(rows), () => new Array(cols).fill(0));
        let currentShape;
        let currentType;
        let currentRow;
        let currentCol;
        let nextShape;
        let nextType;
        
        // 方块类型和颜色
        const SHAPES = [
            { shape: [[1, 1, 1, 1]], type: 'i' },           // I
            { shape: [[1, 1], [1, 1]], type: 'o' },         // O
            { shape: [[0, 1, 0], [1, 1, 1]], type: 't' },   // T
            { shape: [[1, 1, 0], [0, 1, 1]], type: 's' },   // S
            { shape: [[0, 1, 1], [1, 1, 0]], type: 'z' },   // Z
            { shape: [[1, 0, 0], [1, 1, 1]], type: 'j' },   // J
            { shape: [[0, 0, 1], [1, 1, 1]], type: 'l' }    // L
        ];
        
        // 设置难度按钮点击事件
        difficultyButtons.forEach(button => {
            button.addEventListener('click', () => {
                if (!isGameStarted) return;
                
                difficultyButtons.forEach(btn => btn.classList.remove('active'));
                button.classList.add('active');
                gameSpeed = parseInt(button.dataset.speed);
                
                // 如果游戏正在进行,更新速度
                if (!isPaused && gameInterval) {
                    clearInterval(gameInterval);
                    gameInterval = setInterval(moveDown, gameSpeed);
                }
            });
        });
        
        function createShape() {
            // 如果有下一个方块,使用它
            if (nextShape) {
                currentShape = nextShape;
                currentType = nextType;
            } else {
                // 第一次运行时生成当前方块
                let randomIndex = Math.floor(Math.random() * SHAPES.length);
                currentShape = JSON.parse(JSON.stringify(SHAPES[randomIndex].shape));
                currentType = SHAPES[randomIndex].type;
            }
            
            // 生成下一个方块
            let nextIndex = Math.floor(Math.random() * SHAPES.length);
            nextShape = JSON.parse(JSON.stringify(SHAPES[nextIndex].shape));
            nextType = SHAPES[nextIndex].type;
            
            // 设置当前方块的初始位置
            currentRow = 0;
            currentCol = Math.floor(cols / 2) - Math.floor(currentShape[0].length / 2);
            
            // 显示下一个方块
            drawNextPiece();
        }
        
        function drawNextPiece() {
            nextPieceDisplay.innerHTML = '';
            
            // 计算居中位置
            let centerX = (120 - nextShape[0].length * blockSize) / 2;
            let centerY = (120 - nextShape.length * blockSize) / 2;
            
            for (let row = 0; row < nextShape.length; row++) {
                for (let col = 0; col < nextShape[row].length; col++) {
                    if (nextShape[row][col]) {
                        let block = document.createElement('div');
                        block.className = `block block-${nextType}`;
                        block.style.top = (centerY + row * blockSize) + 'px';
                        block.style.left = (centerX + col * blockSize) + 'px';
                        nextPieceDisplay.appendChild(block);
                    }
                }
            }
        }
        
        function drawBoard() {
            // 清除所有现有方块
            const existingBlocks = board.querySelectorAll('.block');
            existingBlocks.forEach(block => {
                if (!block.classList.contains('current')) {
                    block.remove();
                }
            });
            
            // 绘制固定的方块
            for (let row = 0; row < rows; row++) {
                for (let col = 0; col < cols; col++) {
                    if (boardGrid[row][col]) {
                        let block = document.createElement('div');
                        block.className = `block block-${boardGrid[row][col]}`;
                        block.style.top = row * blockSize + 'px';
                        block.style.left = col * blockSize + 'px';
                        board.appendChild(block);
                    }
                }
            }
        }
        
        function drawCurrentShape() {
            // 移除当前活动方块
            const currentBlocks = board.querySelectorAll('.block.current');
            currentBlocks.forEach(block => block.remove());
            
            // 绘制当前活动方块
            for (let row = 0; row < currentShape.length; row++) {
                for (let col = 0; col < currentShape[row].length; col++) {
                    if (currentShape[row][col]) {
                        let block = document.createElement('div');
                        block.className = `block block-${currentType} current`;
                        block.style.top = (currentRow + row) * blockSize + 'px';
                        block.style.left = (currentCol + col) * blockSize + 'px';
                        board.appendChild(block);
                    }
                }
            }
        }
        
        function drawGhostPiece() {
            // 移除之前的幽灵方块
            const ghostBlocks = board.querySelectorAll('.block.ghost');
            ghostBlocks.forEach(block => block.remove());
            
            // 找到当前方块可以下落的最低位置
            let ghostRow = currentRow;
            while (!checkCollision(ghostRow + 1, currentCol, currentShape)) {
                ghostRow++;
            }
            
            // 如果幽灵位置与当前位置不同,才绘制幽灵方块
            if (ghostRow !== currentRow) {
                for (let row = 0; row < currentShape.length; row++) {
                    for (let col = 0; col < currentShape[row].length; col++) {
                        if (currentShape[row][col]) {
                            let block = document.createElement('div');
                            block.className = `block ghost`;
                            block.style.top = (ghostRow + row) * blockSize + 'px';
                            block.style.left = (currentCol + col) * blockSize + 'px';
                            block.style.backgroundColor = 'rgba(255, 255, 255, 0.2)';
                            block.style.border = '1px dashed rgba(255, 255, 255, 0.5)';
                            board.appendChild(block);
                        }
                    }
                }
            }
        }
        
        function checkCollision(row = currentRow, col = currentCol, shape = currentShape) {
            for (let r = 0; r < shape.length; r++) {
                for (let c = 0; c < shape[r].length; c++) {
                    if (shape[r][c]) {
                        let newRow = row + r;
                        let newCol = col + c;
                        if (
                            newRow >= rows ||
                            newCol < 0 ||
                            newCol >= cols ||
                            (newRow >= 0 && boardGrid[newRow][newCol])
                        ) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        
        function mergeShape() {
            for (let row = 0; row < currentShape.length; row++) {
                for (let col = 0; col < currentShape[row].length; col++) {
                    if (currentShape[row][col]) {
                        let newRow = currentRow + row;
                        let newCol = currentCol + col;
                        if (newRow >= 0) {
                            boardGrid[newRow][newCol] = currentType;
                        }
                    }
                }
            }
        }
        
        function clearRows() {
            let clearedRows = 0;
            
            for (let row = rows - 1; row >= 0; row--) {
                if (boardGrid[row].every(cell => cell)) {
                    boardGrid.splice(row, 1);
                    boardGrid.unshift(new Array(cols).fill(0));
                    clearedRows++;
                    row++; // 重新检查当前行,因为上面的行已经下移
                }
            }
            
            if (clearedRows > 0) {
                // 更新消除的行数
                lines += clearedRows;
                linesValue.textContent = lines;
                linesCounter.textContent = lines;
                
                // 更新等级
                level = Math.floor(lines / 10) + 1;
                levelValue.textContent = level;
                
                // 更新游戏速度(仅在自动难度调整时)
                if (!document.querySelector('.difficulty-button.active').dataset.speed) {
                    gameSpeed = Math.max(100, 1000 - (level - 1) * 100);
                    clearInterval(gameInterval);
                    gameInterval = setInterval(moveDown, gameSpeed);
                }
                
                // 根据消除的行数计算得分
                let points;
                switch (clearedRows) {
                    case 1: points = 40 * level; break;
                    case 2: points = 100 * level; break;
                    case 3: points = 300 * level; break;
                    case 4: points = 1200 * level; break;
                    default: points = 0;
                }
                
                score += points;
                updateScore();
            }
        }
        
        function updateScore() {
            scoreValue.textContent = score;
            scoreCounter.textContent = score;
        }
        
        function moveDown() {
            if (!isGameStarted || isPaused) return;
            
            currentRow++;
            if (checkCollision()) {
                currentRow--;
                mergeShape();
                clearRows();
                createShape();
                
                // 检查游戏是否结束
                if (checkCollision()) {
                    gameOver();
                    return;
                }
            }
            
            drawBoard();
            drawGhostPiece();
            drawCurrentShape();
        }
        
        function moveLeft() {
            if (!isGameStarted || isPaused) return;
            
            currentCol--;
            if (checkCollision()) {
                currentCol++;
            } else {
                drawBoard();
                drawGhostPiece();
                drawCurrentShape();
            }
        }
        
        function moveRight() {
            if (!isGameStarted || isPaused) return;
            
            currentCol++;
            if (checkCollision()) {
                currentCol--;
            } else {
                drawBoard();
                drawGhostPiece();
                drawCurrentShape();
            }
        }
        
        function rotateShape() {
            if (!isGameStarted || isPaused) return;
            
            let rotatedShape = [];
            for (let col = 0; col < currentShape[0].length; col++) {
                let newRow = [];
                for (let row = currentShape.length - 1; row >= 0; row--) {
                    newRow.push(currentShape[row][col]);
                }
                rotatedShape.push(newRow);
            }
            
            let prevShape = currentShape;
            currentShape = rotatedShape;
            
            // 墙踢算法:如果旋转后碰撞,尝试左右移动
            if (checkCollision()) {
                // 尝试向右移动
                currentCol++;
                if (checkCollision()) {
                    currentCol--;
                    // 尝试向左移动
                    currentCol--;
                    if (checkCollision()) {
                        currentCol++;
                        // 尝试向上移动
                        currentRow--;
                        if (checkCollision()) {
                            currentRow++;
                            // 如果所有尝试都失败,恢复原来的形状
                            currentShape = prevShape;
                        }
                    }
                }
            }
            
            drawBoard();
            drawGhostPiece();
            drawCurrentShape();
        }
        
        function hardDrop() {
            if (!isGameStarted || isPaused) return;
            
            while (!checkCollision(currentRow + 1, currentCol)) {
                currentRow++;
            }
            moveDown(); // 这将触发合并和生成新方块
        }
        
        function gameOver() {
            clearInterval(gameInterval);
            gameOverScreen.style.display = 'flex';
            isGameStarted = false;
        }
        
        function resetGame() {
            score = 0;
            level = 1;
            lines = 0;
            gameSpeed = parseInt(document.querySelector('.difficulty-button.active').dataset.speed) || 1000;
            boardGrid = Array.from(Array(rows), () => new Array(cols).fill(0));
            
            updateScore();
            levelValue.textContent = level;
            linesValue.textContent = lines;
            linesCounter.textContent = lines;
            
            gameOverScreen.style.display = 'none';
            
            createShape();
            drawBoard();
            drawGhostPiece();
            drawCurrentShape();
            
            clearInterval(gameInterval);
            gameInterval = setInterval(moveDown, gameSpeed);
            
            isGameStarted = true;
            isPaused = false;
            pauseBtn.textContent = "暂停";
        }
        
        function startGame() {
            startScreen.style.display = 'none';
            resetGame();
        }
        
        function showHowToPlay() {
            alert("游戏操作说明:\n\n← → : 左右移动方块\n↑ : 旋转方块\n↓ : 加速下落\n空格 : 直接落下\nP : 暂停游戏\nR : 重新开始");
        }
        
        function togglePause() {
            if (!isGameStarted) return;
            
            isPaused = !isPaused;
            if (isPaused) {
                clearInterval(gameInterval);
                pauseBtn.textContent = "继续";
            } else {
                gameInterval = setInterval(moveDown, gameSpeed);
                pauseBtn.textContent = "暂停";
            }
        }
        
        function handleKeyPress(event) {
            switch (event.key.toLowerCase()) {
                case 'arrowdown':
                    if (!isGameStarted || isPaused) return;
                    moveDown();
                    event.preventDefault();
                    break;
                case 'arrowleft':
                    if (!isGameStarted || isPaused) return;
                    moveLeft();
                    event.preventDefault();
                    break;
                case 'arrowright':
                    if (!isGameStarted || isPaused) return;
                    moveRight();
                    event.preventDefault();
                    break;
                case 'arrowup':
                    if (!isGameStarted || isPaused) return;
                    rotateShape();
                    event.preventDefault();
                    break;
                case ' ':
                    if (!isGameStarted || isPaused) return;
                    hardDrop();
                    event.preventDefault();
                    break;
                case 'p':
                    togglePause();
                    event.preventDefault();
                    break;
                case 'r':
                    resetGame();
                    event.preventDefault();
                    break;
            }
        }
        
        function initGame() {
            // 初始化游戏状态
            isGameStarted = false;
            isPaused = false;
            
            // 设置事件监听器
            document.addEventListener('keydown', handleKeyPress);
            startBtn.addEventListener('click', startGame);
            howToPlayBtn.addEventListener('click', showHowToPlay);
            restartBtn.addEventListener('click', resetGame);
            newGameBtn.addEventListener('click', resetGame);
            pauseBtn.addEventListener('click', togglePause);
            
            // 给游戏区域添加焦点,以便更好地捕获键盘事件
            board.setAttribute('tabindex', '0');
            board.focus();
            
            // 显示开始界面
            startScreen.style.display = 'flex';
        }
        
        initGame();
    });
</script>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值