网页版的俄罗斯方块

news2025/2/24 13:31:38

1、新建一个txt文件
2、打开后将代码复制进去保存

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>俄罗斯方块</title>
    <link rel="stylesheet" href="styles.css">
</head>

<body>
  
    <div class="game-container">
        <div id="game-board"></div>
        <div class="sidebar">
            <div class="score-board">
                <h2>得分: <span id="score">0</span></h2>
            </div>
            <div class="next-piece-board">
                <h2>下一个方块</h2>
                <div id="next-piece"></div>
            </div>
            <div class="controls">
                <h2>操作说明</h2>
                <p>左箭头: 左移</p>
                <p>右箭头: 右移</p>
                <p>下箭头: 下落</p>
                <p>上箭头: 旋转</p>
                <div class="control-buttons">
                    <button id="left-btn">左移</button>
                    <button id="right-btn">右移</button>
                    <button id="down-btn">下落</button>
                    <button id="rotate-btn">旋转</button>
                </div>
            </div>
        </div>
    </div>
    <script src="script.js"></script>


</body>

</html>
<style>
body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
    background-color: #f0f0f0;
}

.game-container {
    display: flex;
    gap: 20px;
}

#game-board {
    display: grid;
    grid-template-columns: repeat(10, 20px);
    grid-template-rows: repeat(20, 20px);
    gap: 1px;
    background-color: #333;
    width: fit-content;
}

.cell {
    width: 20px;
    height: 20px;
    background-color: #000;
}

.cell.filled {
    background-color: #0f0;
}

.sidebar {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.score-board,
.next-piece-board,
.controls {
    background-color: #fff;
    padding: 10px;
    border-radius: 5px;
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
}

#next-piece {
    display: grid;
    grid-template-columns: repeat(4, 20px);
    grid-template-rows: repeat(4, 20px);
    gap: 1px;
    background-color: #333;
    width: fit-content;
}

.control-buttons {
    display: flex;
    gap: 10px;
}

.control-buttons button {
    padding: 5px 10px;
    cursor: pointer;
}

</style>
<script>
// 游戏板尺寸
const ROWS = 20;
const COLS = 10;

// 方块形状
const SHAPES = [
    [[1, 1, 1, 1]],
    [[1, 1], [1, 1]],
    [[1, 1, 0], [0, 1, 1]],
    [[0, 1, 1], [1, 1, 0]],
    [[1, 1, 1], [0, 1, 0]],
    [[1, 1, 1], [1, 0, 0]],
    [[1, 1, 1], [0, 0, 1]]
];

// 获取游戏板元素
const gameBoard = document.getElementById('game-board');
const nextPieceBoard = document.getElementById('next-piece');
const scoreElement = document.getElementById('score');

// 创建游戏板
function createBoard() {
    for (let row = 0; row < ROWS; row++) {
        for (let col = 0; col < COLS; col++) {
            const cell = document.createElement('div');
            cell.classList.add('cell');
            gameBoard.appendChild(cell);
        }
    }
}

// 创建下一个方块显示区域
function createNextPieceBoard() {
    for (let row = 0; row < 4; row++) {
        for (let col = 0; col < 4; col++) {
            const cell = document.createElement('div');
            cell.classList.add('cell');
            nextPieceBoard.appendChild(cell);
        }
    }
}

// 获取指定位置的单元格
function getCell(row, col, board) {
    return board.children[row * (board === gameBoard ? COLS : 4) + col];
}

// 随机生成一个方块
function randomShape() {
    const shapeIndex = Math.floor(Math.random() * SHAPES.length);
    return SHAPES[shapeIndex];
}

// 当前方块
let currentShape;
let currentX;
let currentY;
// 下一个方块
let nextShape;
// 得分
let score = 0;

// 生成新方块
function newShape() {
    currentShape = nextShape || randomShape();
    nextShape = randomShape();
    drawNextPiece();
    currentX = Math.floor(COLS / 2) - Math.floor(currentShape[0].length / 2);
    currentY = 0;
    if (!canMove(currentShape, currentX, currentY)) {
        // 游戏结束
        alert('游戏结束!最终得分: ' + score);
        location.reload();
    }
}

// 检查方块是否可以移动到指定位置
function canMove(shape, x, y) {
    for (let row = 0; row < shape.length; row++) {
        for (let col = 0; col < shape[row].length; col++) {
            if (shape[row][col]) {
                const newX = x + col;
                const newY = y + row;
                if (newX < 0 || newX >= COLS || newY >= ROWS || (newY >= 0 && getCell(newY, newX, gameBoard).classList.contains('filled'))) {
                    return false;
                }
            }
        }
    }
    return true;
}

// 绘制方块
function drawShape() {
    for (let row = 0; row < currentShape.length; row++) {
        for (let col = 0; col < currentShape[row].length; col++) {
            if (currentShape[row][col]) {
                const x = currentX + col;
                const y = currentY + row;
                if (y >= 0) {
                    getCell(y, x, gameBoard).classList.add('filled');
                }
            }
        }
    }
}

// 清除方块
function clearShape() {
    for (let row = 0; row < currentShape.length; row++) {
        for (let col = 0; col < currentShape[row].length; col++) {
            if (currentShape[row][col]) {
                const x = currentX + col;
                const y = currentY + row;
                if (y >= 0) {
                    getCell(y, x, gameBoard).classList.remove('filled');
                }
            }
        }
    }
}

// 绘制下一个方块
function drawNextPiece() {
    // 清除之前的显示
    for (let row = 0; row < 4; row++) {
        for (let col = 0; col < 4; col++) {
            getCell(row, col, nextPieceBoard).classList.remove('filled');
        }
    }
    // 绘制新的下一个方块
    for (let row = 0; row < nextShape.length; row++) {
        for (let col = 0; col < nextShape[row].length; col++) {
            if (nextShape[row][col]) {
                getCell(row, col, nextPieceBoard).classList.add('filled');
            }
        }
    }
}

// 方块下落
function moveDown() {
    clearShape();
    if (canMove(currentShape, currentX, currentY + 1)) {
        currentY++;
    } else {
        // 方块落地,固定方块
        drawShape();
        checkLines();
        newShape();
    }
    drawShape();
}

// 检查并清除满行
function checkLines() {
    let linesCleared = 0;
    for (let row = ROWS - 1; row >= 0; row--) {
        let isLineFull = true;
        for (let col = 0; col < COLS; col++) {
            if (!getCell(row, col, gameBoard).classList.contains('filled')) {
                isLineFull = false;
                break;
            }
        }
        if (isLineFull) {
            linesCleared++;
            // 清除满行
            for (let c = 0; c < COLS; c++) {
                getCell(row, c, gameBoard).classList.remove('filled');
            }
            // 上方方块下移
            for (let r = row; r > 0; r--) {
                for (let c = 0; c < COLS; c++) {
                    const aboveCell = getCell(r - 1, c, gameBoard);
                    const currentCell = getCell(r, c, gameBoard);
                    if (aboveCell.classList.contains('filled')) {
                        currentCell.classList.add('filled');
                    } else {
                        currentCell.classList.remove('filled');
                    }
                }
            }
            row++; // 再次检查当前行
        }
    }
    // 根据清除的行数增加得分
    if (linesCleared > 0) {
        score += linesCleared * 100;
        scoreElement.textContent = score;
    }
}

// 移动方块
function moveLeft() {
    clearShape();
    if (canMove(currentShape, currentX - 1, currentY)) {
        currentX--;
    }
    drawShape();
}

function moveRight() {
    clearShape();
    if (canMove(currentShape, currentX + 1, currentY)) {
        currentX++;
    }
    drawShape();
}

// 旋转方块
function rotateShape() {
    const rotatedShape = [];
    for (let col = 0; col < currentShape[0].length; col++) {
        const newRow = [];
        for (let row = currentShape.length - 1; row >= 0; row--) {
            newRow.push(currentShape[row][col]);
        }
        rotatedShape.push(newRow);
    }
    clearShape();
    if (canMove(rotatedShape, currentX, currentY)) {
        currentShape = rotatedShape;
    }
    drawShape();
}

// 键盘事件处理
document.addEventListener('keydown', function (event) {
    switch (event.key) {
        case 'ArrowLeft':
            moveLeft();
            break;
        case 'ArrowRight':
            moveRight();
            break;
        case 'ArrowDown':
            moveDown();
            break;
        case 'ArrowUp':
            rotateShape();
            break;
    }
});

// 按钮事件处理
document.getElementById('left-btn').addEventListener('click', moveLeft);
document.getElementById('right-btn').addEventListener('click', moveRight);
document.getElementById('down-btn').addEventListener('click', moveDown);
document.getElementById('rotate-btn').addEventListener('click', rotateShape);

// 游戏主循环
function gameLoop() {
    moveDown();
    setTimeout(gameLoop, 500);
}

// 初始化游戏
createBoard();
createNextPieceBoard();
newShape();
gameLoop();


</script>

3、修改文件后缀名为,将txt修改为html
4、打开方式选择浏览器打开,或者打开浏览器直接拖动到里面即可。如果后缀名修改html后,图标显示的是浏览器的图标,直接双击打开即可。
5、效果如下:
在这里插入图片描述

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

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

相关文章

创建虚拟环境以及配置对应的项目依赖

文章目录 首先创建一个虚拟环境&#xff0c;创建一个名字为myenv,并且版本为xxx的虚拟环境 conda create --name myenv pythonxxx激活虚拟环境 conda activate myenv下载所需的依赖&#xff0c;如果有requirements.txt文件 pip install -r requirements.txt容易出现的错误&a…

网络安全第三次练习

一、实验拓扑 二、实验要求 配置真实DNS服务信息&#xff0c;创建虚拟服务&#xff0c;配置DNS透明代理功能 三、需求分析 1.创建用户并配置认证策略 2.安全策略划分接口 3.ip与策略配置 四、实验步骤 1.划分安全策略接口 2.创建用户并进行策略认证 3.配置安全策略 4.NAT配…

写大论文的word版本格式整理,实现自动生成目录、参考文献序号、公式序号、图表序号

前情提要&#xff1a;最近开始写大论文&#xff0c;发现由于内容很多导致用老方法一个一个改的话超级麻烦&#xff0c;需要批量自动化处理&#xff0c;尤其是序号&#xff0c;在不断有增添删减的情况时序号手动调整很慢也容易出错&#xff0c;所以搞一个格式总结&#xff0c;记…

STM32——HAL库开发笔记22(定时器3—呼吸灯实验)(参考来源:b站铁头山羊)

本文利用前几节所学知识来实现一个呼吸灯实验&#xff1a;两颗led灯交替呼吸。 一、STM32CubeMX配置 step1&#xff1a;配置调试接口 step2&#xff1a;配置定时器 定时器1位于APB2总线上&#xff0c;如上图所示。 step3&#xff1a;配置时基单元 按照下图配置 时钟来源配置…

玩转 Java 与 Python 交互,JEP 库来助力

文章目录 玩转 Java 与 Python 交互&#xff0c;JEP 库来助力一、背景介绍二、JEP 库是什么&#xff1f;三、如何安装 JEP 库&#xff1f;四、JEP 库的简单使用方法五、JEP 库的实际应用场景场景 1&#xff1a;数据处理场景 2&#xff1a;机器学习场景 3&#xff1a;科学计算场…

【单片机毕业设计14-基于stm32c8t6的智能宠物养护舱系统设计】

【单片机毕业设计14-基于stm32c8t6的智能宠物养护舱系统设计】 前言一、功能介绍二、硬件部分三、软件部分总结 前言 &#x1f525;这里是小殷学长&#xff0c;单片机毕业设计篇14-基于stm32c8t6的智能宠物养护舱系统设计 &#x1f9ff;创作不易&#xff0c;拒绝白嫖可私 一、功…

DevEco Studio常用快捷键以及如何跟AndroidStudio的保持同步

DevEco Studio快捷键 DevEco Studio是华为推出的用于开发HarmonyOS应用的集成开发环境&#xff0c;它提供了丰富的快捷键以提高开发效率&#xff0c;以下为你详细介绍不同操作场景下的常用快捷键&#xff1a; 通用操作快捷键 操作描述Windows/Linux 快捷键Mac 快捷键打开设置窗…

[Windows] 全国油价实时查询,可具体到城市

[Windows] 全国油价实时查询&#xff0c;可具体到城市 链接&#xff1a;https://pan.xunlei.com/s/VOJnS3aOPeBwGaSvS0O0E1hwA1?pwdx83j# 出于代码练习的目的&#xff0c;调用公共免费api做的py程序&#xff0c;已经一键打包&#xff0c;双击启动即可 使用&#xff1a;选择…

【CSS】---- CSS 变量,实现样式和动画函数复用

1. 前言 本文介绍 CSS 的自定义属性(变量)来实现样式、动画等 CSS 的复用。都是知道在 CSS 和 JS 复用一个很重要的事情,比如 JS 的函数封装,各个设计模式的使用等等,CSS 中样式的复用,同样重要。MDN 使用 CSS 自定义属性(变量):自定义属性(有时候也被称作CSS 变量或…

装修流程图: 装修前准备 → 设计阶段 → 施工阶段 → 安装阶段 → 收尾阶段 → 入住

文章目录 引言I 毛坯房装修的全流程**1. 装修前准备****1.1 确定装修预算****1.2 选择装修方式****1.3 选择装修公司****1.4 办理装修手续****2. 设计阶段****2.1 量房****2.2 设计方案****2.3 确认方案****3. 施工阶段****3.1 主体拆改****3.2 水电改造****3.3 防水工程****3.…

【论文解读】《Training Large Language Models to Reason in a Continuous Latent Space》

论文链接 1. 背景与动机 语言空间与推理的矛盾 目前大多数大语言模型&#xff08;LLMs&#xff09;在解决复杂问题时采用链式思维&#xff08;Chain-of-Thought, CoT&#xff09;方法&#xff0c;即利用自然语言逐步推导出答案。然而&#xff0c;论文指出&#xff1a; 自然语言…

深度剖析 C 语言函数递归:原理、应用与优化

在 C 语言的函数世界里&#xff0c;递归是一个独特且强大的概念。它不仅仅是函数调用自身这么简单&#xff0c;背后还蕴含着丰富的思想和广泛的应用。今天&#xff0c;让我们跟随这份课件&#xff0c;深入探索函数递归的奥秘。 一、递归基础&#xff1a;概念与思想 递归是一种…

goredis常见基础命令

基本操作 //删除键 exists,err: rdb.Exists(ctx,"key").Result() if err!nil{panic(err) } if exists>0{err rdb.Del(ctx,"key").Err()if err!nil{panic(err)} }string类型 //设置一个键值对 //0表示没有过期时间 err:rdb.Set(ctx,"key1",…

【Linux网络】序列化、守护进程、应用层协议HTTP、Cookie和Session

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1、序列化和反序列化2、守护进程2.1 什么是进程组&#xff1f;2.2 什么是会话&#xff1f; 3、应用层协议HTTP3.1 HTTP协议3.2 HT…

system verilog的流操作符

流操作符&#xff0c;有分为操作对象是一整个数组和单独的数据两种&#xff0c;例如bit [7:0] a[4]和bit [31:0] b&#xff0c;前者操作对象是数组&#xff0c;后者是单独一个较大位宽的数。 流操作符有<<和>>&#xff0c;代表从右向左打包和从左向右打包。 打包的…

LLM2CLIP论文学习笔记:强大的语言模型解锁更丰富的视觉表征

1. 写在前面 今天分享的一篇论文《LLM2CLIP: P OWERFUL L ANGUAGE M ODEL U NLOCKS R ICHER V ISUAL R EPRESENTATION》&#xff0c; 2024年9月微软和同济大学的一篇paper&#xff0c; 是多模态领域的一篇工作&#xff0c;主要探索了如何将大模型融合到Clip模型里面来进一步提…

计算机毕业设计SpringBoot+Vue.jst网上超市系统(源码+LW文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

HTTP SSE 实现

参考&#xff1a; SSE协议 SSE技术详解&#xff1a;使用 HTTP 做服务端数据推送应用的技术 一句概扩 SSE可理解为&#xff1a;服务端和客户端建立连接之后双方均保持连接&#xff0c;但仅支持服务端向客户端推送数据。推送完毕之后关闭连接&#xff0c;无状态行。 下面是基于…

二分图检测算法以及最大匹配算法(C++)

上一节我们学习了有向图中的最大连通分量. 本节我们来学习二分图. 二分图是一种特殊的图结构, 能够帮助我们高效地解决这些匹配和分配问题. 本文将带你了解二分图的基本概念, 判定方法, 最大匹配算法以及实际应用场景. 环境要求 本文所用样例在Windows 11以及Ubuntu 24.04上面…

Keepalive基础

一。简介和功能 vrrp协议的软件实现&#xff0c;原生设计目的是为了高可用ipvs服务 功能&#xff1a; 1.基于vrrp协议完成地址流动 2.为vip地址所在的节点生成ipvs规则&#xff08;在配置文件中预先定义&#xff09; 3.为ipvs集群的各RS做健康状况检测 4.基于脚本调用接口…