HTML实现俄罗斯方块

本篇文章主要讲使用HTML、CSS和JavaScript实现一个简单的俄罗斯方块游戏,包含基本的游戏逻辑、行消除功能以及暂停和继续游戏的控制。

使用工具

本篇文章有用到ChatGPT-4o代码纠错,国内免翻且稳定,感兴趣的大佬试试。

传送门:363Ai工具箱


HTML部分
html 复制代码
<div id="game"></div>
<div id="message"></div>
<div id="controls">
    <button onclick="startGame()">继续游戏</button>
    <button onclick="pauseGame()">暂停游戏</button>
</div>

解释:

  • <div id="game">:游戏界面,使用CSS Grid布局。
  • <div id="message">:显示游戏失败信息。
  • 按钮:用于控制游戏的继续和暂停。

CSS部分
css 复制代码
body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: #f0f0f0;
}
#game {
    display: grid;
    grid-template-columns: repeat(10, 30px);
    grid-template-rows: repeat(20, 30px);
    gap: 1px;
    background-color: #333;
}
.cell {
    width: 30px;
    height: 30px;
    background-color: #fff;
}

解释:

  • 布局:使用Flexbox和Grid布局设计游戏界面。
  • 方块样式:不同形状的方块用不同的颜色表示。

JavaScript部分

游戏逻辑主要使用JavaScript实现。

初始化
javascript 复制代码
const rows = 20;
const cols = 10;
let board = Array.from({ length: rows }, () => Array(cols).fill(''));
let gameInterval;
let isPaused = false;
let dropInterval = 1000;

解释:

  • 游戏板:一个二维数组表示20行和10列的游戏区域。
  • 游戏状态:gameInterval用于控制方块下落的定时器,isPaused表示游戏是否暂停。
方块定义
javascript 复制代码
const tetrominoes = {
    I: [[1, 1, 1, 1]],
    J: [[1, 0, 0], [1, 1, 1]],
    // 其他形状...
};

解释:

  • 定义了所有俄罗斯方块的形状。
绘制函数
javascript 复制代码
function drawBoard() {
    game.innerHTML = '';
    board.forEach(row => {
        row.forEach(cell => {
            const div = document.createElement('div');
            div.className = `cell ${cell}`;
            game.appendChild(div);
        });
    });
}

解释:

  • drawBoard():根据board数组更新游戏界面。
方块移动与旋转
javascript 复制代码
function canMove(position, shape) {
    return shape.every((row, i) =>
        row.every((cell, j) =>
            !cell || (board[position.y + i] && board[position.y + i][position.x + j] === '')
        )
    );
}

function rotate(shape) {
    return shape[0].map((_, index) => shape.map(row => row[index]).reverse());
}

解释:

  • canMove():检查方块是否可以移动到指定位置。
  • rotate():旋转方块的矩阵。
行消除功能
javascript 复制代码
function clearFullRows() {
    board = board.reduce((acc, row) => {
        if (row.every(cell => cell !== '')) {
            acc.unshift(Array(cols).fill(''));
        } else {
            acc.push(row);
        }
        return acc;
    }, []);
}

解释:

  • clearFullRows()函数:遍历游戏板,检查是否有行被填满。
  • 若有,则移除该行,并在顶部添加一行空行。

游戏循环

javascript 复制代码
function drop() {
    if (isPaused) return;
    clearTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
    currentTetromino.position.y++;
    if (!canMove(currentTetromino.position, currentTetromino.shape)) {
        currentTetromino.position.y--;
        drawTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
        if (currentTetromino.position.y === 0) {
            message.textContent = '你失败啦';
            clearInterval(gameInterval);
        } else {
            clearFullRows();
            currentTetromino = {
                type: Object.keys(tetrominoes)[Math.floor(Math.random() * 7)],
                position: { x: 3, y: 0 },
                shape: tetrominoes[Object.keys(tetrominoes)[Math.floor(Math.random() * 7)]]
            };
        }
    }
    drawTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
    drawBoard();
}
加速下降功能
  • 按键事件:在keydown事件中,添加对ArrowDown的监听。
  • 加速下降实现:当按下下箭头键时,调用drop()函数,使方块立即下降一格。
用户交互
javascript 复制代码
document.addEventListener('keydown', (e) => {
    if (e.key === 'ArrowUp') {
        rotateTetromino();
    } else if (e.key === 'ArrowLeft') {
        moveLeft();
    } else if (e.key === 'ArrowRight') {
        moveRight();
    } else if (e.key === 'ArrowDown') {
        drop();
    }
});
  • 使用键盘箭头键控制方块的移动、旋转和加速下落。

运行界面:

以下是完整代码:

html 复制代码
<!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 {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #f0f0f0;
        }
        #game {
            display: grid;
            grid-template-columns: repeat(10, 30px);
            grid-template-rows: repeat(20, 30px);
            gap: 1px;
            background-color: #333;
        }
        .cell {
            width: 30px;
            height: 30px;
            background-color: #fff;
        }
        .I { background-color: #00f0f0; }
        .J { background-color: #0000f0; }
        .L { background-color: #f0a000; }
        .O { background-color: #f0f000; }
        .S { background-color: #00f000; }
        .T { background-color: #a000f0; }
        .Z { background-color: #f00000; }
        #message, #score {
            margin-top: 20px;
            font-size: 24px;
        }
        #message {
            color: red;
        }
        #controls {
            margin-top: 10px;
        }
        button {
            padding: 10px;
            font-size: 16px;
            margin: 5px;
        }
    </style>
</head>
<body>
    <div id="game"></div>
    <div id="message"></div>
    <div id="score"></div>
    <div id="controls">
        <button onclick="startGame()">开始游戏</button>
        <button onclick="pauseGame()">暂停游戏</button>
        <button onclick="restartGame()">重新开始</button>
    </div>
    <script>
        const game = document.getElementById('game');
        const message = document.getElementById('message');
        const scoreDisplay = document.getElementById('score');
        const rows = 20;
        const cols = 10;
        let board, gameInterval, isPaused, dropInterval, score, level, currentTetromino;

        const tetrominoes = {
            I: [[1, 1, 1, 1]],
            J: [[1, 0, 0], [1, 1, 1]],
            L: [[0, 0, 1], [1, 1, 1]],
            O: [[1, 1], [1, 1]],
            S: [[0, 1, 1], [1, 1, 0]],
            T: [[0, 1, 0], [1, 1, 1]],
            Z: [[1, 1, 0], [0, 1, 1]]
        };

        function initGame() {
            board = Array.from({ length: rows }, () => Array(cols).fill(''));
            currentTetromino = {
                type: Object.keys(tetrominoes)[Math.floor(Math.random() * 7)],
                position: { x: 3, y: 0 },
                shape: tetrominoes[Object.keys(tetrominoes)[Math.floor(Math.random() * 7)]]
            };
            message.textContent = '';
            score = 0;
            level = 1;
            dropInterval = 1000;
            updateScore();
            drawBoard();
        }

        function drawBoard() {
            game.innerHTML = '';
            board.forEach(row => {
                row.forEach(cell => {
                    const div = document.createElement('div');
                    div.className = `cell ${cell}`;
                    game.appendChild(div);
                });
            });
        }

        function drawTetromino(type, position, shape) {
            shape.forEach((row, i) => {
                row.forEach((cell, j) => {
                    if (cell) {
                        board[position.y + i][position.x + j] = type;
                    }
                });
            });
        }

        function clearTetromino(type, position, shape) {
            shape.forEach((row, i) => {
                row.forEach((cell, j) => {
                    if (cell) {
                        board[position.y + i][position.x + j] = '';
                    }
                });
            });
        }

        function canMove(position, shape) {
            return shape.every((row, i) =>
                row.every((cell, j) =>
                    !cell || (board[position.y + i] && board[position.y + i][position.x + j] === '')
                )
            );
        }

        function rotate(shape) {
            return shape[0].map((_, index) => shape.map(row => row[index]).reverse());
        }

        function clearFullRows() {
            let linesCleared = 0;
            board = board.reduce((acc, row) => {
                if (row.every(cell => cell !== '')) {
                    acc.unshift(Array(cols).fill(''));
                    linesCleared++;
                } else {
                    acc.push(row);
                }
                return acc;
            }, []);
            if (linesCleared > 0) {
                score += linesCleared * 100;
                if (score >= level * 1000) {
                    level++;
                    dropInterval = Math.max(100, dropInterval - 100);
                    clearInterval(gameInterval);
                    startGame();
                }
                updateScore();
            }
        }

        function updateScore() {
            scoreDisplay.textContent = `得分: ${score} 级别: ${level}`;
        }

        function drop() {
            if (isPaused) return;
            clearTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
            currentTetromino.position.y++;
            if (!canMove(currentTetromino.position, currentTetromino.shape)) {
                currentTetromino.position.y--;
                drawTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
                if (currentTetromino.position.y === 0) {
                    message.textContent = '你失败啦';
                    setTimeout(restartGame, 2000);
                    clearInterval(gameInterval);
                } else {
                    clearFullRows();
                    currentTetromino = {
                        type: Object.keys(tetrominoes)[Math.floor(Math.random() * 7)],
                        position: { x: 3, y: 0 },
                        shape: tetrominoes[Object.keys(tetrominoes)[Math.floor(Math.random() * 7)]]
                    };
                }
            }
            drawTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
            drawBoard();
        }

        function rotateTetromino() {
            if (isPaused) return;
            clearTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
            const rotatedShape = rotate(currentTetromino.shape);
            if (canMove(currentTetromino.position, rotatedShape)) {
                currentTetromino.shape = rotatedShape;
            }
            drawTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
            drawBoard();
        }

        function moveLeft() {
            if (isPaused) return;
            clearTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
            currentTetromino.position.x--;
            if (!canMove(currentTetromino.position, currentTetromino.shape)) {
                currentTetromino.position.x++;
            }
            drawTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
            drawBoard();
        }

        function moveRight() {
            if (isPaused) return;
            clearTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
            currentTetromino.position.x++;
            if (!canMove(currentTetromino.position, currentTetromino.shape)) {
                currentTetromino.position.x--;
            }
            drawTetromino(currentTetromino.type, currentTetromino.position, currentTetromino.shape);
            drawBoard();
        }

        function startGame() {
            isPaused = false;
            clearInterval(gameInterval);
            gameInterval = setInterval(drop, dropInterval);
        }

        function pauseGame() {
            isPaused = true;
            clearInterval(gameInterval);
        }

        function restartGame() {
            initGame();
            clearInterval(gameInterval);
        }

        document.addEventListener('keydown', (e) => {
            if (e.key === 'ArrowUp') {
                rotateTetromino();
            } else if (e.key === 'ArrowLeft') {
                moveLeft();
            } else if (e.key === 'ArrowRight') {
                moveRight();
            } else if (e.key === 'ArrowDown') {
                drop();
            }
        });

        initGame();
    </script>
</body>
</html>

这段代码展示了如何用JavaScript实现一个基础的俄罗斯方块游戏,支持基本的方块操作、行消除和游戏状态控制。可以在此基础上添加更多功能,比如计分系统、关卡设计等。

对于编程新手或正在学习新知识的程序员,可以使用ChatGPT来做助手,减少出错性和重复性代码的时间。

感谢阅读!!!

相关推荐
Myli_ing15 分钟前
考研倒计时-配色+1
前端·javascript·考研
余道各努力,千里自同风17 分钟前
前端 vue 如何区分开发环境
前端·javascript·vue.js
PandaCave24 分钟前
vue工程运行、构建、引用环境参数学习记录
javascript·vue.js·学习
软件小伟26 分钟前
Vue3+element-plus 实现中英文切换(Vue-i18n组件的使用)
前端·javascript·vue.js
醉の虾1 小时前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧1 小时前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm1 小时前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep7011 小时前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王2 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue