手撸俄罗斯方块(一)——简单介绍

news2024/9/24 15:25:58

手撸俄罗斯方块

简单介绍

《俄罗斯方块》(俄语:Тетрис,英语:Tetris),是1980年末期至1990年代初期风靡全世界的电脑游戏,是落下型益智游戏的始祖,电子游戏领域的代表作之一,为苏联首个在美国发布的娱乐软件。此游戏最初由阿列克谢·帕基特诺夫在苏联设计和编写,于1984年6月6日首次发布,当时他正在苏联科学院电算中心工作。此游戏的名称是由希腊语数字“四”的前缀“tetra-”(因所有落下方块皆由四块组成)和帕基特诺夫最喜欢的运动网球(“tennis”)拼接而成,华语地区则因游戏为俄罗斯人发明普遍称为“俄罗斯方块”。

数字“四”,显而易见,最初的图形都是由4个小方块组成的,这也是俄罗斯方块的一个特点。游戏的目标是通过控制不同形状的方块,使它们在一个矩形的游戏区域中排列成完整的一行或多行,然后这些完整的行就会消除,给玩家得分。

游戏规则

  • 游戏开始时,游戏区域是一个空白的矩形,玩家通过控制方块的移动和旋转,使它们在游戏区域中排列成完整的一行或多行;
  • 当一行或多行被完整填满时,这些行就会消除,给玩家得分;
  • 当方块堆积到游戏区域的顶部时,游戏结束。

游戏特点

  • 游戏简单易上手,但是难度逐渐增加;
  • 游戏的速度会随着游戏的进行而逐渐加快;
  • 游戏的随机性较大,玩家需要根据当前的情况,灵活地调整方块的位置和旋转。

形状

俄罗斯方块中的方块有7种不同的形状,分别是:

  • I型:一字型;
  • J型:J型;
  • L型:L型。
  • O型:方块型;
  • S型:S型;
  • T型:T型;
  • Z型:Z型;

这些形状是由4个小方块组成的,每个小方块都可以旋转,但是旋转的中心不同。如下图:

在这里插入图片描述
各种四格骨牌由左至右,上至下的英文字母代号:I、J、L、O、S、T、Z

操作

玩家通过键盘控制方块的移动和旋转,具体操作如下:

  • :向左移动方块;
  • :向右移动方块;
  • :旋转方块;
  • :加速下落。

得分

  • 消除一行:得100分;
  • 消除两行:得300分;
  • 消除三行:得700分;
  • 消除四行:得1500分。

游戏结束

  • 当方块堆积到游戏区域的顶部时,游戏结束;
  • 游戏结束后,显示游戏结束的提示,并显示玩家的得分。

从开发角度看俄罗斯方块

坐标系

对于所有二维游戏来说,坐标系是一个非常重要的概念。在俄罗斯方块中,我们可以使用一个二维数组来表示游戏区域,数组的每一个元素表示一个方块,数组的索引表示方块的坐标。如下图:

在这里插入图片描述

图中区域表示正数的范围。但是实际情况下,我们可以使用一个二维数组来表示游戏区域。而且计算机在绘画过程中也是自上而下自左而右进行的,因此我们需要将坐标进行变换。如下图:

在这里插入图片描述

x轴表示列,y轴表示行。这样我们就可以通过一个二维数组来表示游戏区域。

对于执行的一个元素,我们可以通过二维数组快速定位到它。

const points = [[]]; // 二维数组
const x = 1; // 列
const y = 2; // 行
const point = points[y][x]; // 获取坐标为(1, 2)的元素

需要注意的是,数组的索引是从0开始的,因此在实际过程中我们将y = 0看成第一行,x = 0看成第一列。

方块的表示

按照上述坐标体系的定义,我们可以表示任何一个方块,如当表示I型方块时,我们可以定义一个数组来表示它的形状:

const IHorizonal = [
  [0, 1, 2, 3]
]
const IVertical = [
  [0],
  [1],
  [2],
  [3]
]

如下图:
在这里插入图片描述

这样我们就可以通过一个数组来表示一个方块的形状。通过类似的方法,我们可以表示其他的6个方块。但是,I方块有两种形态,我们到底使用哪一种作为初始形态呢?

这里面需要做一个约定,我们定义每个方块的初始化形态。定义如下:

  • I型:
// 口口口口
  • J型:
// 口
// 口口口
  • L型:
//    口
// 口口口
  • O型:
// 口口
// 口口
  • S型:
//   口口
// 口口
  • T型:
//   口
// 口口口
  • Z型:
// 口口
//   口口

方块的移动

在游戏过程中,方块是可以移动的。分别可以向左移动、向右移动、向下移动。同时移动必须满足如下条件:

  1. 移动后的方块不能超出游戏区域;即不能超出游戏区域的左边界、右边界和底边界;翻译成程序语言为:
// 向左移动
if (x - 1 >= 0) {
  x -= 1;
}
// 向右移动
if (x + 1 < width) {
  x += 1;
}
// 向下移动
if (y + 1 < height) {
  y += 1;
}
  1. 移动后的方块不能与其他方块重叠;即不能与其他方块的坐标重叠;翻译成程序语言为:
// 向左移动
if (x - 1 >= 0 && !isOverlap(x - 1, y)) {
  x -= 1;
}
// 向右移动
if (x + 1 < width && !isOverlap(x + 1, y)) {
  x += 1;
}
// 向下移动
if (y + 1 < height && !isOverlap(x, y + 1)) {
  y += 1;
}

上面是描述某个点的情况,实际上判断方块情况,需要所有的点都满足条件。

方块的转换

在游戏过程中,方块是可以旋转的。如下图:

在这里插入图片描述

同样的,在旋转过程中,也必须满足如下条件:

  1. 旋转后的方块不能超出游戏区域;即不能超出游戏区域的左边界、右边界和底边界;

  2. 旋转后的方块不能与其他方块重叠;即不能与其他方块的坐标重叠。

使用程序语言表述如下:

// 旋转
const isValid = (newShape) => {
  for (let y = 0; y < newShape.length; y++) {
    for (let x = 0; x < newShape[y].length; x++) {
      if (newShape[y][x] && (x < 0 || x >= width || y >= height || isOverlap(x, y))) {
        return false;
      }
    }
  }
  return true;
}
const newShape = rotate(shape);
if (isValid(newShape)) {
  shape = newShape;
}

接下来问题来,如何实现rotate函数呢?这里面就涉及到了方块的旋转。对于不同的方块,旋转的方式是不同的。

如I型方块,其旋转形态只有两种,分别是横向和纵向。

// I型方块
// 横向
// 口口口口
// 纵向
// 口
// 口
// 口
// 口

但是对于T型等其他方块,其旋转形态是四种的。

// T型方块
// 1
//  口
// 口口口
// 2
// 口
// 口口
// 口
// 3
// 口口口
//  口
// 4
//  口
// 口口
//  口

我们当然可以通过枚举的方式将所有的旋转形态都列出来,但是这样的方式是不可取的。因为这样的方式会使得代码变得复杂,而且不易维护。因此我们需要找到一种更好的方式来实现方块的旋转。

实际上,我们可以通过观察发现,方块的旋转是围绕一个中心点进行的。且旋转方向和角度是固定的。

因此我们可以得出如下结论:

  1. 方块的旋转是围绕一个中心点进行的;选择的中心点是不动的。

  2. 方块的旋转方向和角度是固定,我们可以选取逆时针旋转,相对我们定义的坐标系统旋转角度为 π / 2。 故根据旋转公式,新坐标定义如下:

  const newX = Math.cos(Math.PI / 2) * (x - centerX) - Math.sin(Math.PI / 2) * (y - centerY) + centerX;

  const newY = Math.cos(Math.PI / 2) * (y - centerY) + Math.sin(Math.PI / 2) * (x - centerX) + centerY;

  const newX = -y + centerY + centerX;
  const newY =  x - centerX +  centerY;

此处不太了解的可以去看看坐标旋转。

小结

上面我们讨论了俄罗斯方块的基本介绍,从开发的角度来看,我们讨论了坐标系、方块的表示、方块的移动和方块的旋转。那么我们可以通过如下两个实体在表示方块的基本情况。

  1. Point,坐标点
interface PointAttr {
  color?: string; // 颜色
  isReadyToClean?: boolean; // 是否准备消除
  [key: string]: any; // 其他属性
}

class Point {
  private x: number;
  private y: number;
  private attr: PointAttr;
  constructor(x, y, attr?: PointAttr) {
    this.x = x;
    this.y = y;
    this.attr = attr || {};
  }
}

每个坐标点均包含了x、y坐标,以及其他属性,如颜色等;

  1. Block,方块

我们通过Block来抽象方块,定义如下:

class Block {
  private points: Point[];
  private rotateIndex: number; /// 旋转因子
  constructor(points: Point[]) {
    this.points = points;
  }
  abstract getCenterIndex(): number; // 获取中心点
  abstract getRotateArray(); number[]; // 获取旋转数组
}

其他的方块均继承自Block,实现getCenterIndexgetRotateArray方法。

如IBlcok,其实现如下:

class IBlock extends Block {
  getCenterIndex() {
    return 1;
  }
  getRotateArray() {
    return [
      Math.PI / 2, // 第一次旋转相对于初始位置的角度
      -Math.PI / 2 // 第二次旋转相对于第一次旋转的角度
    ]
  }
}

通过继承的关系,分别实现LBlockJBlockOBlockTBlockSBlockZBlock

本章内容暂时就到这里,后续章节我们将继续讨论如何实现俄罗斯方块的游戏逻辑。

详细内容可以关注我的github账号: https://github.com/shushanfx/tetris

接下来我将从如下几个方面来阐述:

  • 手撸俄罗斯方块——游戏设计
  • 手撸俄罗斯方块——游戏核心模块设计
  • 手撸俄罗斯方块——渲染与交互
  • 手撸俄罗斯方块——游戏主题

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

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

相关文章

关于气象探测设备的介绍

气象探测设备概述 气象探测设备是用于收集、记录和分析大气环境信息的专用工具。它们能够实时监测气温、湿度、气压、风速、风向、降雨量等多种气象要素&#xff0c;为天气预报、气候研究、农业生产和环境保护等领域提供重要数据支持。气象探测设备种类繁多&#xff0c;包括地…

【UML用户指南】-33-对体系结构建模-系统和模型

目录 1、系统和子系统 2、模型和视图 3、跟踪 4、常用建模技术 4.1、对系统的体系结构建模 4.2、对系统的系统建模 模型是对现实世界的简化——即对系统的抽象&#xff0c;建立模型的目的是为了更好地理解系统。 1、系统和子系统 一个系统可能被分解成一组子系统&#…

MySQL超详细学习教程,2023年硬核学习路线

文章目录 前言1. 数据库的相关概念1.1 数据1.2 数据库1.3 数据库管理系统1.4 数据库系统1.5 SQL 2. MySQL数据库2.1 MySQL安装2.2 MySQL配置2.2.1 添加环境变量2.2.2 新建配置文件2.2.3 初始化MySQL2.2.4 注册MySQL服务2.2.5 启动MySQL服务 2.3 MySQL登录和退出2.4 MySQL卸载2.…

推荐3款电脑必备专业软件,错过拍大腿

SolveigMM Video Splitter SolveigMM Video Splitter是一款功能强大的视频编辑工具&#xff0c;主要用于视频的无损剪切和合并。该软件支持多种常见的视频格式&#xff0c;如AVI、WMV、ASF、MP3、WMA等。此外&#xff0c;它还支持AVCHD、MPEG-2、WebM、FLV等格式&#xff0c;并…

论文 | REACT: SYNERGIZING REASONING AND ACTING INLANGUAGE MODELS

本文首先认为&#xff0c;到目前为止&#xff0c;LLM 在语言理解方面令人印象深刻&#xff0c;它们已被用来生成 CoT&#xff08;思想链&#xff09;来解决一些问题&#xff0c;它们也被用于执行和计划生成。 尽管这两者是分开研究的&#xff0c;但本文旨在以交错的方式将推理…

JDBC编程的学习——MYsql版本

目录 前言 什么是JDBC ??? 前置准备 使用JDBC的五个关键步骤 1.建立与数据库的连接 2.创建具体的sql语句和Statement 3.执行SQL语句 4.处理结果集 5.释放资源 完整流程展示 前言 笔者在先前的博客就提过会写关于JDBC的内容 [Mysql] 的基础知识和sql 语句.教你速成…

python怎么调用cmd命令

关于python调用cmd命令&#xff1a; 1、python的OS模块 OS模块调用CMD命令有两种方式&#xff1a;os.popen()、os.system()都是用当前进程来调用。 OS.system是无法获取返回值的。当运行结束后接着往下面执行程序。用法如&#xff1a;OS.system("ipconfig"). OS.…

Invoice OCR

Invoice OCR 发票识别 其他类型ORC&#xff1a; DIPS_YTPC OCR-CSDN博客

【AI大模型】检索增强生成(RAG)模型在企业中的应用

彩蛋 ChatGPT4相比于ChatGPT3.5,有着诸多不可比拟的优势&#xff0c;比如图片生成、图片内容解析、GPTS开发、更智能的语言理解能力等&#xff0c;但是在国内使用GPT4存在网络及充值障碍等问题&#xff0c;如果您对ChatGPT4.0感兴趣&#xff0c;可以私信博主为您解决账号和环境…

基于Make的c工程No compilation commands found报错

由于安装gcc时只安装了build-essential&#xff0c;没有将其添加到环境变量中&#xff0c;因此打开Make工程时&#xff0c;CLion会产生如下错误&#xff1a; 要解决这个问题&#xff0c;一个方法是将GCC添加到环境变量中&#xff0c;但是这个方法需要修改至少两个配置文件&…

校园外卖系统带万字文档在线外卖管理系统java项目java课程设计java毕业设计

文章目录 校园外卖系统一、项目演示二、项目介绍三、万字项目文档四、部分功能截图五、部分代码展示六、底部获取项目源码带万字文档&#xff08;9.9&#xffe5;带走&#xff09; 校园外卖系统 一、项目演示 校园外卖服务系统 二、项目介绍 语言&#xff1a;java 数据库&…

MySQL实现数据备份的方式可以基于哪几种?

MySQL 数据库实现数据备份的方式主要有以下几种&#xff1a; 物理备份 (Physical Backup)&#xff1a; 冷备份 (Cold Backup)&#xff1a;在数据库关闭的情况下&#xff0c;直接复制数据库文件&#xff08;数据文件、日志文件等&#xff09;。这种方式操作简单&#xff0c;但是…

pd虚拟机去虚拟化是什么意思?pd虚拟机去虚拟化教程 PD虚拟机优化设置

Parallels Desktop for Mac&#xff08;PD虚拟机&#xff09;去虚拟化是指在虚拟机&#xff08;Virtual Machine&#xff0c;简称 VM&#xff09;中禁用或减少虚拟化层的影响&#xff0c;使其表现更接近于物理机。这种操作通常用于提高虚拟机的性能或解决某些软件兼容性问题。具…

【BUG】Python3|COPY 指令合并 ts 文件为 mp4 文件时长不对(含三种可执行源代码和解决方法)

文章目录 前言源代码FFmpeg的安装1 下载2 安装 前言 参考&#xff1a; python 合并 ts 视频&#xff08;三种方法&#xff09;使用 FFmpeg 合并多个 ts 视频文件转为 mp4 格式 Windows 平台下&#xff0c;用 Python 合并 ts 文件为 mp4 文件常见的有三种方法&#xff1a; 调用…

系统数据加密传输的实现

文章目录 1、背景2、需求3、实现思路3.1 密码加密3.2 密码解密3.3 nacos密码加密 4、相关工具类4.1 非对称加密RSA4.2 对称加密AES4.3 Nacos加解密的实现&#xff1a;Jasypt 5、历史数据兼容处理 1、背景 用户在浏览器发送请求数据到后台系统&#xff0c;期间数据在网络传输&a…

osgverse浏览器端编译

目录 1 WSL安装(Windows subsystem for Linux)2 emsdk准备3 SetUp.sh安装(osgverse源码目录下)4 显示与问题 内容 WSL安装(Windows subsystem for Linux) 安装wsl&#xff1a;wsl --install 将版本设置为wsl1(因为版本2比版本1慢很多)&#xff1a;wsl --set-version ubuntu 1…

防火墙基础实验配置

一&#xff0c;实验拓扑 二&#xff0c;实验需求&#xff1a; 1.DMZ区内的服务器&#xff0c;办公区仅能在办公时间内&#xff08;9&#xff1a;00 - 18&#xff1a;00&#xff09;可以访问&#xff0c;生产区的设备全天可以访问 2.生产区不允许访问互联网&#xff0c;办公区…

迂回战术:“另类“全新安装 macOS 15 Sequoia beta2 的极简方法

概述 随着 WWDC 24 的胜利闭幕&#xff0c;Apple 平台上各种 beta 版的系统也都“跃跃欲出”&#xff0c;在 mac 上自然也不例外。 本次全新的 macOS 15 Sequoia&#xff08;红杉&#xff09;包含了诸多重磅升级&#xff0c;作为秃头开发者的我们怎么能不先睹为快呢&#xff1…

什么是边缘计算?创造一个更快、更智慧、更互联的世界

前言 如今&#xff0c;数十亿物联网传感器广泛部署在零售商店、城市街道、仓库和医院等各种场所&#xff0c;正在生成大量数据。从这些数据中更快地获得洞察&#xff0c;意味着可以改善服务、简化运营&#xff0c;甚至挽救生命。但要做到这一点&#xff0c;企业需要实时做出决策…

网络协议 — Keepalived 高可用方案

目录 文章目录 目录Keepalived 是实现了 VRRP 协议的软件Keepalived 的软件架构VRRP StackCheckersKeepalived 的配置Global configurationvrrp_scriptVRRP Configurationvrrp synchroization groupvrrp instancevirtual ip addressesvirtual routesLVS Configurationvirtual_s…