HTML实现俄罗斯方块

news2024/11/25 6:34:56

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

使用工具

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

传送门:363Ai工具箱


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部分
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实现。

初始化
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表示游戏是否暂停。

方块定义
const tetrominoes = {
    I: [[1, 1, 1, 1]],
    J: [[1, 0, 0], [1, 1, 1]],
    // 其他形状...
};

解释:

  • 定义了所有俄罗斯方块的形状。

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

解释:

  • drawBoard():根据board数组更新游戏界面。

方块移动与旋转
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():旋转方块的矩阵。

行消除功能
function clearFullRows() {
    board = board.reduce((acc, row) => {
        if (row.every(cell => cell !== '')) {
            acc.unshift(Array(cols).fill(''));
        } else {
            acc.push(row);
        }
        return acc;
    }, []);
}

解释:

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

游戏循环 

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()函数,使方块立即下降一格。

 

用户交互
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();
    }
});
  • 使用键盘箭头键控制方块的移动、旋转和加速下落。

运行界面:

 

 以下是完整代码:

<!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来做助手,减少出错性和重复性代码的时间。

感谢阅读!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2061503.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

认知杂谈20

今天分享 有人说的一段争议性的话 I I 程序员的高薪舒适圈&#xff1a;光鲜背后的挑战 一说起程序员这个职业&#xff0c;很多人马上就会想到高薪&#xff0c;觉得他们过着白领的生活。确实&#xff0c;程序员一般都能拿到比好多行业都高的工资&#xff0c;工作时间也比较稳…

谷粒商城实战笔记-232-商城业务-认证服务-框架效果演示-xxl-sso-徐雪里

文章目录 一&#xff0c;膜拜大神许雪里二&#xff0c;用开源框架xxl-sso演示单点登录1&#xff0c;我是老板&#xff0c;我有三个网站2&#xff0c;配置域名3&#xff0c;下载xxl-sso代码4&#xff0c;服务规划5&#xff0c;配置修改5.1 xxl-sso-server redis配置修改5.1 xxl-…

使用FModel提取黑神话悟空的资产

使用FModel提取黑神话悟空的资产 前言设置效果展示闲聊可能遇到的问题没有相应的UE引擎版本选项 前言 黑神话悟空昨天上线了&#xff0c;解个包looklook。 本文内容比较简洁&#xff0c;仅介绍解包黑神话所需的专项配置&#xff0c;关于FModel的基础使用流程&#xff0c;请见…

Python3学习(一)

目录 Python版本 标识符 保留字 注释 缩进 多行语句 同一行显示多条语句 import 与 from...import 变量 数据类型 Number&#xff08;数字&#xff09; 数字类型 数值运算 String&#xff08;字符串&#xff09; bool&#xff08;布尔类型) List&#xff08;列…

废品回收小程序,开启上门回收模式

废品回收一直是一个热门行业&#xff0c;市场发展空间巨大。随着科技的发展&#xff0c;废品回收也与时俱进&#xff0c;进行了转型&#xff01;“互联网上门回收”的新模式&#xff0c;运用信息技术的力量&#xff0c;让废品回收变得更加高效便捷&#xff0c;同时也为回收行业…

秋招红队面试经验分享

吉祥知识星球http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247485367&idx1&sn837891059c360ad60db7e9ac980a3321&chksmc0e47eebf793f7fdb8fcd7eed8ce29160cf79ba303b59858ba3a6660c6dac536774afb2a6330#rd 《网安面试指南》 《Java代码审计》 《Web安全…

【JS|第25期】探索HTTP POST请求:请求体的演变与应用

日期&#xff1a;2024年8月16日 作者&#xff1a;Commas 签名&#xff1a;(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释&#xff1a;如果您觉得有所帮助&#xff0c;帮忙点个赞&#xff0c;也可以关注我&#xff0c;我们一起成长&#xff1b;如果有不对的地方&#xf…

OpenLayers3, 缩放、平移、复位操作

文章目录 一、前言二、代码示例 一、前言 本文基于OpenLayers3实现地图缩放、平移和复位操作 二、代码示例 <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><htm…

【YOLO5 项目实战】(4)红外目标检测

欢迎关注『youcans动手学模型』系列 本专栏内容和资源同步到 GitHub/youcans 【YOLO5 项目实战】&#xff08;1&#xff09;YOLO5 环境配置与测试 【YOLO5 项目实战】&#xff08;2&#xff09;使用自己的数据集训练目标检测模型 【YOLO5 项目实战】&#xff08;3&#xff09;P…

12 程序控制语句:循环控制(while、do-while、for、多重嵌套循环、死循环)

目录 1 while 循环 1.1 基本语法 1.2 流程图 1.3 计数循环 1.3.1 实现原则 1.3.2 案例&#xff1a;循环输出语句 1.3.3 案例&#xff1a;循环输出数字 7~15 1.3.4 案例&#xff1a;倒序输出数字 56 ~ 43 1.3.5 案例&#xff1a;输出 10&#xff08;包括 10&…

SAP 预扣税配置步骤文档【Withholding Tax]

1. 配置预扣税的基本概念 预扣税是对某些支付进行扣除的税&#xff0c;可能适用于各种财务交易&#xff08;例如&#xff0c;供应商支付、股息支付等&#xff09;。预扣税通常包括几种类型&#xff0c;如个人所得税、企业所得税和其他税务种类。 2. 配置步骤 以下是一般的预…

Notion使用详解

​ ​ 您好&#xff0c;我是程序员小羊&#xff01; 前言 Notion是一款集笔记、任务管理、知识库、文档协作等多功能于一体的生产力工具。其灵活性和可定制性使得它在个人和团队协作中都非常受欢迎。本教程将详细介绍如何使用Notion的基本功能&#xff0c;帮助你快速上手并充分…

Open3D mesh 模型切片

目录 一、概述 1.1简述 1.2实现步骤 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 3.1原始mesh 3.2切片后的mesh Open3D点云算法汇总及实战案例汇总的目录地址&#xff1a; Open3D点云算法与点云深度学习案例汇总&#xff08;长期更新&#xff09;-CSDN博客 一…

Python高光谱遥感数据处理与机器学习深度应用

高光谱遥感信息对于我们认识世界具有重要意义。尽管大部分物质在人眼中看似无异&#xff0c;然而高光谱遥感的观察下&#xff0c;它们呈现出独特的"光谱特征"。这种能够窥见事物的"本质"能力具备着革命性的潜能&#xff0c;对精准农业、地球观测、艺术分析…

php与nginx的高速缓存

memcache PHP的加速模块 本部分是对php的内存加速的配置 1. memcache安装 609 phpize # 生成./configure文件610 yum install -y autoconf # 安装包611 ls612 phpize613 ls614 ./configure615 make && make install616 ls /usr/local/php/lib/php/extensions…

网络UDP报文详细解析

目录 一、简介二、详细介绍三、其他相关链接1、TCP报文段的详细图总结2、TCP三次握手和四次挥手详解3、socket通信原理及相关函数详细总结4、网络包IP首部详细解析 一、简介 本文主要介绍UDP报文格式。 二、详细介绍 UDP是一种无连接、不可靠的用户数据报协议&#xff0c;其…

【软件文档大全】软件开发常用文档(程序开发过程-实施-运维-安全-交付-资质-标书)

软件项目常用文档有哪些&#xff1f; 工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&#xff0c;产品需求规格说明书&#xff0c;需求调研计划&#xff0c;用户需求调查单&#xff0c;用户需求说明书&#xff0c;概要设计说明书&#xff0c;技术解决方案…

2.pandas--读取文件夹中所有excel文件进行合并

文章目录 代码对应的本地文件文件夹目录三个文件夹中的内容test01.xlsxtest02.xlsxtest03.xlsx 三个文件合并后得到merge.xlsx文件文件内容 生成result.xlsx文件内容 代码 import glob import pandas as pddf_merge pd.DataFrame() # 创建一个空的DataFramefolder_path &qu…

接口隔离原则(Interface Segregation Principle

接口隔离原则&#xff08;Interface Segregation Principle&#xff09; 基本介绍 1&#xff09;客户端不应该依赖它不需要的接口&#xff0c;即一个类对另一个类的依赖应该建立在最小的接口上2&#xff09;先看一张图 3&#xff09;类 A 通过接口 Interface1 依赖类 B&#…

五、3 单目操作符关系操作符

1、单目操作符 1&#xff09;&#xff01; 2&#xff09;& 3&#xff09;sizeof sizeof是操作符&#xff0c;不是函数 strlen是库函数&#xff0c;用来求字符串长度 4&#xff09;~ 5&#xff09; 6&#xff09;*&#xff08;与指针配合使用&#xff09; 7&#xff09;强…