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;从而对存储技术…

安卓将图片分割或者拉伸或者旋转到指定尺寸并保存到本地

直接上代码吧:你们要用的话可以按照想法改 package com.demo.util;import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.os.Environment; import android.util.Log;import java.io.File; import java.io.…

代码随想录算法训练营 动态规划part11

一、买卖股票的最佳时机III 123. 买卖股票的最佳时机 III - 力扣&#xff08;LeetCode&#xff09; 请选一个喜欢的吧/(ㄒoㄒ)/~~123. 买卖股票的最佳时机 III - 力扣&#xff08;LeetCode&#xff09; class Solution {public int maxProfit(int[] prices) {if(pricesnul…

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

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

stable diffusion model训练遇到的问题【No module named ‘triton‘】

一天早晨过来&#xff0c;发现昨天还能跑的diffusion代码&#xff0c;突然出现了【No module named ‘triton’】的问题&#xff0c;导致本就不富裕的显存和优化速度雪上加霜&#xff0c;因此好好探究了解决方案。 首先是原因&#xff0c;由于早晨过来发现【电脑重启】导致了【…

【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 在哪里? ##

LuatOS-SOC接口文档(air780E)--camera - codec - 多媒体-编解码

常量 常量 类型 解释 codec.MP3 number MP3格式 codec.WAV number WAV格式 codec.AMR number AMR-NB格式&#xff0c;一般意义上的AMR codec.AMR_WB number AMR-WB格式 codec.create(type, isDecoder) 创建编解码用的codec 参数 传入值类型 解释 int 多媒…

VSCode开发go手记

断点调试&#xff1a; 安装delve&#xff08;windows&#xff09;&#xff1a; go get -u github.com/go-delve/delve/cmd/dlv 设置 launch.json 配置文件&#xff1a; ctrlshiftp 输入 Debug: Open launch.json 打开 launch.json 文件&#xff0c;如果第一次打开,会新建一…

为什么使用命令行

一提到Linux&#xff0c;许多人都会说到“自由”&#xff0c;但他们也许并不知道“自由”的真正涵义。“自由”是指一台没有任何秘密的计算机&#xff0c;并且你可以决定你的计算机能做什么。“自由”是一种权力&#xff0c;但是在过去的二三十年里&#xff0c;这种基本的权力正…

[论文笔记]RE2

引言 今天带来论文Simple and Effective Text Matching with Richer Alignment Features的笔记,论文标题为基于更丰富特征对齐结构的简单高效文本匹配模型。 这篇工作是2019年发表的,在Bert出来之后发表的,在四个著名的文本匹配任务(SNLI,SciTail,QQP,WikiQA)上取得了SOTA…

分块压缩算法及例程

分块压缩算法是一种数据压缩方法&#xff0c;它将输入数据划分为不同的块&#xff0c;并对每个块进行独立的压缩。这种算法通常用于处理大型文件或流式数据&#xff0c;可以提高压缩和解压缩的效率。 以下是一个基本的分块压缩算法的示例&#xff1a; 将输入数据分成固定大小的…

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…

Java:关于mybatis框架mapper.xml编写小于号<的问题

目录 方案一&#xff1a;转义字符方案二&#xff1a;原样字符总结参考文章 xml中小于号< 和 小于等于< 不能直接使用 select * from tb_user where age < #{user.age};方案一&#xff1a;转义字符 使用转义字符 含义符号转义字符小于<<大于>> 示例 s…

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;分析…

【PostgreSQL内核学习(十三)—— (PortalRun)】

PortalRun 概述PortalRun 函数MarkPortalActive 函数PotalSetIoState 函数FillPortalStore 函数DoPortalRunFetch 函数PortalRunSelect 函数PortalRunMulti 函数MarkPortalDone 函数 声明&#xff1a;本文的部分内容参考了他人的文章。在编写过程中&#xff0c;我们尊重他人的…