200行C++代码写一个Qt俄罗斯方块小游戏

小小演示一下:

大体思路:

 其实很早就想写一个俄罗斯方块了,但是一想到那么多方块还要变形,还要判断落地什么的就脑壳疼。直到现在才写出来。

俄罗斯方块这个小游戏的小难点其实就一个,就是方块的变形,看似每个方块的变形都不一样,找不到共同点,实现起来比较麻烦,不过只要有了思路其实还是可以的。

方块变形:

俄罗斯方块实际上是只有五种(其中有两种“L”形和“Z”形每种有两种对称的)。

每个方块以及变形的样子我都放下面了。

咋一看好像看不出共同点,不过也确实没有啥共同点,实际上我们不需要有共同点,我们只需要知道每个方块变形都是怎么变的。

上面看不出来我们再换个形式。

我们知道,方块变形的本质实际上是旋转,而旋转我们是绕着某个中心点去旋转的,因此我们只需要记录每个方块的中心点以及不同形态时的每个小方块对于中心点的相对位置。

除了正方形怎么变形都一样,其他方块的变形情况都在下面,中心点我加重了颜色。

可以看得出来,方块的每个小方块的位置都可以通过与中心点的相对坐标来获取。

要变换姿势的时候,只要有中心点的坐标,就可以切换姿势。

下面是不同方块不同姿势的不同小方块与中心点的相对位置关系,套了个四维数组写起来好费劲

//第一层选择方块种类,第二层选择方块形态,第三层装小方块,//第四层装每个小方块对于中心点坐标的相对位置用于变换姿势vector<vector<vector<vector<int>>>>mode{{{{1,0},{1,1},{0,0},{0,1}}},								//方形{{{2,0},{1,0},{0,0},{-1,0}},{{0,-1},{0,0},{0,1},{0,2}}},	//长条形{{{1,0},{1,-1},{0,-1},{-1,-1}},{{1,-1},{1,0},{1,1},{0,1}},	//L形1{{1,1},{0,1},{-1,1},{-1,0}},{{0,-1},{-1,-1},{-1,0},{-1,1}}},{{{1,0},{1,1},{0,1},{-1,1}},{{1,-1},{1,1},{1,0},{0,-1}},	//L形2{{0,1},{-1,0},{-1,1},{-1,-1}},{{1,-1},{0,-1},{-1,-1},{-1,0}}},{{{1,0},{0,0},{0,1},{-1,0}},{{0,-1},{0,0},{0,1},{-1,0}},	//凸形{{1,0},{0,0},{0,-1},{-1,0}},{{1,0},{0,0},{0,-1},{0,1}}},{{{1,-1},{0,-1},{0,0},{-1,0}},{{1,0},{1,1},{0,0},{0,-1}}},	//Z形1{{{1,1},{0,0},{0,1},{-1,0}},{{1,-1},{1,0},{0,0},{0,1}}}		//Z形2};

 下面是换姿势的代码:

其中 whichOne是选择哪一种方块,index是选择方块的哪一种姿势

//切换模式
vector<vector<int>> block::changeMode(){if (whichOne == 0) return coordinate;vector<vector<int>>res;index++;index %= (mode[whichOne].size());for (auto& m : mode[whichOne][index]) {//根据中心坐标和缓存的模式关系来获取切换模式之后的方块坐标res.push_back({ center[0] - m[0],center[1] - m[1] });}//没有直接切换,而是返回新坐标return res;
}

 在获取新姿势的小方块坐标之后没有马上更新,而是返回出去了,因为可能变形之后会不符合要求,例如下面的例子:

 变形之后把返回的新坐标返回,我们再用一个函数去检测新坐标是否合法,合法再去修改当前方块的具体坐标,检测函数也很简单:

//检测移动是否合法
int Tetris::checkMove(vector<vector<int>>temp){for (auto& c : temp) {if (c[1] < 0 || c[1] >= 10) return -1;      //左右越界返回-1;if (cache[c[0]][c[1]] == 1) return 0;       //遇到落地方块返回0;}//一切合法返回1return 1;
}

 返回1就是移动合法,我们修改坐标,返回-1就是移动不合法,我们什么也不改。

还剩一个返回-1,就是移动后遇到了已经落地的方块,这时候在调用这个检测函数的函数之中还需要做个判断。

如果是因此下落而造成的移动,那么检测获取-1则将方块的坐标的位置更新对应在缓存中的位置为1,然后生成新方块。

而其他情况,例如是左右移动或是变换姿势而造成的碰到落地方块则是和-1一样不做处理。

否则会有这样的问题:

落地判断:

用Qt来绘图,我向来都是用二维数组来缓存界面,然后通过相应的位置的不同元素来绘制不同的图案。

在这个俄罗斯方块中,我的写法是缓存中的元素一共只有两种情况,0和1,0表示什么都没有,不需要绘制,而1表示已经落地的方块。

那么正在下落的方块呢,缓存里不用存一下吗。我的做法是不需要,等等会说明原因。

因此我们正在下落的方块的坐标我是拿另一个二维数组存起来的。

每次下落时只需要做个判断,我们正在下落的方块之中,只要有一个小方块在下落之后在缓存中对应的位置元素为1,就表示接触到了已经落地的方块,那么当前方块也会变成他们的一部分,然后更新缓存,并且重新生成新的方块。

这里有个小问题,就是在游戏的一开始缓存是全为0的,还没有落地的方块,因此我们上述的判断在游戏的一开始不会触发,解法有两种,一种是多一层判断,如果方块最下面的小方块已经到了界面最下面的地方(对应缓存中的下标为0),那么也算落地。

第二种解法是我的做法,就是直接在缓存下标为0的位置先给铺一层落地的方块也就是1。

消除检测:

消除检测很容易,界面缓存中的元素只有0或1,分别用来表示什么都没有以及已经落地的方块,如果缓存中有一行的元素之和等于10,那么就表示本行塞满了,可以消除。

缓存中下标为0的行在最下面,也就是下标越大,代表的位置就在界面的越上方。

如果检测到了某一行可以消除,那么我们可以直接把这一行从缓存之中直接删除,然后从缓存的尾部再添加上一个长度为10,元素为0的数组即可。

关于消除还有最后一个问题,那就是一个方块落下,可能消除的不止一行,因此我们像上述那样操作,应该从下标较大的地方开始往下标较小的地方遍历寻找,否则可能会漏掉。

并且我们可以想象的到,一个方块落地之后,如果可以消除,那么可以消除的那一行方块一定是在刚落地方块所在的行,因此每次检测的时候,我们只需要检测落地方块的每个小方块所在的行即可。

//检测是否能清除一行方块
void Tetris::clearBlocks(){set<int>s;vector<int>v;//获取方块的y轴,因为能清除方块的话,行数一定在方块的y轴之中for (auto& c : curBlock.coordinate) {if (accumulate(cache[c[0]].begin(), cache[c[0]].end(), 0) == 10) s.insert(c[0]);}//从大到小去清除一整行的界面缓存for (int i : s) v.insert(v.begin(), i);for (int i : v) {score++;                                //得分增加//删除一行方块后再后面补上一行.cache.erase(cache.begin() + i);cache.push_back(vector<int>(10, 0));}
}

代码获取:

完整的项目文件我已经上传到了CSDN,可以直接免费下载,也可以关注我的公众号“折途想要敲代码”回复关键词“qt俄罗斯方块”免费获取、

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

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

相关文章

如何将本地的项目上传到Git

一、GitHub or GitLab or Gitee创建一个新的仓库 二、仓库路径创建成功后&#xff0c;将本地项目上传到git 1. 进入本地项目所在文件夹位置&#xff0c;右击 2.出现git命令框 输入git init 在当前项目的目录中生成本地的git管理&#xff08;会发现在当前目录下多了一个.git文件…

转转闲鱼交易猫链接源码 支持二维码收款

最新仿二手闲置链接源码 后台一键生成链接&#xff0c;后台管理教程&#xff1a;解压源码&#xff0c;修改数据库config/Congig 不会可以看源码里有教程 下载程序&#xff1a;https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

30.链表练习题(1)(王道2023数据结构2.3.7节1-15题)

【前面使用的所有链表的定义在第29节】 试题1&#xff1a; 设计一个递归算法&#xff0c;删除不带头结点的单链表L中所有值为x的结点。 首先来看非递归算法&#xff0c;暴力遍历&#xff1a; int Del(LinkList &L,ElemType x){ //此函数实现删除链表中为x的元素LNode *…

科技云报道:分布式存储红海中,看天翼云HBlock如何突围?

科技云报道原创。 过去十年&#xff0c;随着技术的颠覆性创新和新应用场景的大量涌现&#xff0c;企业IT架构出现了稳态和敏态的混合化趋势。 在持续产生海量数据的同时&#xff0c;这些新应用、新场景在基础设施层也普遍基于敏态的分布式架构构建&#xff0c;从而对存储技术…

SpringBoot项目(百度AI整合)——如何在Springboot中使用语音文件识别 ffmpeg的安装和使用

前言 前言&#xff1a;在实际使用中&#xff0c;经常要参考官方的案例&#xff0c;但有时候因为工具的不一样&#xff0c;比如idea 和 eclipse&#xff0c;普通项目和spring项目等的差别&#xff1b;还有时候因为水平有限&#xff0c;难以在散布于官方的各个文档读懂&#xff…

【owt】vs2022 + v141 : 查看WINDOWSSDKDIR

confmfc改为vs2022 + v141 构建 去掉这几个boost库,一样可以链接ok libboost_system-vc141-mt-sgd-x32-1_67.lib libboost_date_time-vc141-mt-sgd-x32-1_67.lib libboost_random-vc141-mt-sgd-x32-1_67.libSDK不在2022或者2017 里面? WINDOWSSDKDIR 在哪里? ##

1786_MTALAB代码生成把通用函数生成独立文件

全部学习汇总&#xff1a; GitHub - GreyZhang/g_matlab: MATLAB once used to be my daily tool. After many years when I go back and read my old learning notes I felt maybe I still need it in the future. So, start this repo to keep some of my old learning notes…

PCIE基础知识-3

PCIE 三种传输方式&#xff1a;IO中断&#xff0c;DMA&#xff0c;peer to peer 中断&#xff1a;PCI设备需要向内存&#xff08;SDRAM&#xff09;中写入一些数据&#xff0c;该PCI设备会向CPU请求一个中断&#xff0c;然后CPU首先先通过PCI总线把该PCI设备的数据读取到CPU内…

解读未知--文档图像大模型的探索与应用

前言&#xff1a; 近日&#xff0c;合合信息在多模态大模型与文档图像智能理解专题论坛上进行了分享。多模态大模型指的是能够处理多种语义信息的一种深度学习模型。文档图像智能理解则是指对文档和图像进行智能化解析和理解的技术。合合信息在这个领域的分享&#xff0c;无疑将…

编译原理.龙书学习1

第一章&#xff1a; 编译器&#xff1a;将程序翻译成一种能够被计算机执行的形式 解释器&#xff1a;解释器直接利用用户提供的输入执行源程序中指定的操作 一个编译器的结构 编译器将源程序映射为语义上等价的目标程序&#xff0c;这个映射过程由两部分组成&#xff1a;分析…

黑马JVM总结(二十二)

&#xff08;1&#xff09;类的结构-field 成员变量信息 类字节码里的一些简单表示&#xff1a; &#xff08;2&#xff09;类文件结构-method-init &#xff08;3&#xff09;类文件结构-method-main &#xff08;4&#xff09;类文件结构-附加属性

Mojo:新型AI语言中的7个令人惊叹的Python升级,用简单的英语解释人工智能

Mojo&#xff1a;新型AI语言中的7个令人惊叹的Python升级 编程之美 用简单的英语解释人工智能 编程之美 由Coding Beauty设计的图像&#xff0c;使用Mojo标志和Python标志。 它比C更快&#xff0c;与Python一样简单&#xff0c;但速度提高了35000倍。 进入Mojo&#xff1a;一种…

Northstar 量化平台

基于 B/S 架构、可替代付费商业软件的一站式量化交易平台。具备历史回放、策略研发、模拟交易、实盘交易等功能。兼顾全自动与半自动的使用场景。 已对接国内期货股票、外盘美股港股。 面向程序员的量化交易软件&#xff0c;用于期货、股票、外汇、炒币等多种交易场景&#xff…

【MySQL集群二】使用MyCat和ProxySql代理MySQL集群

中间件代理MySQL MyCat安装MyCat介绍&#xff1a;步骤1&#xff1a;安装Java环境步骤2&#xff1a;下载并解压Mycat步骤3&#xff1a;配置Mycat步骤4&#xff1a;启动Mycat ProxySql安装ProxySql介绍&#xff1a;步骤1&#xff1a;更新系统步骤2&#xff1a;安装ProxySQL步骤3&…

微信小程序快速入门01(含案例)

文章目录 前言一、组件1.常用视图容器类组件viewscroll-viewswiper、swiper-item 2.text、rich-text3.其他常用组件buttonimagenavigator 二、小程序API三、数据绑定1.定义页面数据2.绑定数据 四、事件绑定1.什么是事件2.小程序中常用的事件3.事件对象 的属性列表target和curre…

详解Renko图表如何表现价格变动

相信大多数投资者与FPmarkets澳福一样&#xff0c;都已发现Renko图表与日本烛台图一样&#xff0c;具有上升和下降的特性。增长期间的典型砖块颜色为绿色或白色&#xff0c;而衰退期前的Renko则呈现红色或黑色。 今天&#xff0c;FPmarkets澳福将与各位投资者共同探讨Renko图表…

第一个 Go 程序“hello,world“ 与 main 函数

第一个 Go 程序"hello&#xff0c;world" 与 main 函数 文章目录 第一个 Go 程序"hello&#xff0c;world" 与 main 函数一.创建“hello&#xff0c;world”示例程序二. “hello&#xff0c;world” 程序结构拆解三、main 函数四、Go 语言中程序是怎么编译…

PowerDesigner 连接 MYSQL

我使用的是powerDesigner16的版本&#xff0c;使用前先保证安装了 mysql odbc 驱动包 选择&#xff1a;文件 -> 反向工程 -> database… 一大波图片正在来袭。。。 点击确认 至此连接成功

【JavaScript保姆级教程】Javascript常量

文章目录 前言一、常量1.1 常量是什么1.2 常量的作用 二、示例代码2.1 示例1&#xff1a;声明一个常量2.2 示例2&#xff1a;常量的命名规则2.3 示例3&#xff1a;常量与变量的区别 总结 前言 欢迎来到【JavaScript保姆级教程】&#xff01;在本篇教程中&#xff0c;我们将讨论…

【激光雷达码盘偏摆角的真假点映射关系】

激光雷达码盘偏摆角的真假点映射关系 一、概要二、完架构流程三、技术细节四、完整代码 一、概要 本代码主要计算激光雷达码盘偏摆角&#xff08;也可以理解为雷达的零位角&#xff09;导致的实际slam建图距离的偏差&#xff0c;只取了第一个象限作为分析目标。最终得出的结论是…