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

news2024/11/20 7:10:25

小小演示一下:

大体思路:

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

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

方块变形:

俄罗斯方块实际上是只有五种(其中有两种“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;
    }
    //一切合法返回1
    return 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.coloradmin.cn/o/1046369.html

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

相关文章

【智能家居项目】裸机版本——项目介绍 | 输入子系统(按键) | 单元测试

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《智能家居项目》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3c0;项目简介&#x1f3c0;输入子系统(按键)⚽应用层⚽设备层⚽ 内核层抽象层⚽…

基于谷歌Transeformer构建人工智能问答系统

目录 1 项目背景 2 关键技术 2.1 Transeformer模型 2.2 Milvus向量数据库 3 系统代码实现 3.1 运行环境构建 3.2 数据集介绍 3.3 预训练模型下载 3.4 代码实现 3.4.1 创建向量表和索引 3.4.2 构建向量编码模型 3.4.3 数据向量化与加载 3.4.4 构建检索web 3.5 运行结…

VS+Qt+C++ GDAL读取tif图像数据显示

程序示例精选 VSQtC GDAL读取tif图像数据显示 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《VSQtC GDAL读取tif图像数据显示》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;…

基于SpringBoot的美容院管理系统设计与实现

目录 前言 一、技术栈 二、系统功能介绍 管理员功能实现 美容部位管理 销量信息统计 已支付订单 技师功能实现 统计美容用品库存 预约信息管理 前台功能实现 普通用户管理 会员管理 普通用户功能实现 美容用品 购物车 我的订单 会员功能实现 美容项目 预约信…

PyCharm中使用pyqt5的方法2-1

qt可以用来设计界面&#xff0c;而pyqt是将qt移植到Python上&#xff0c;通过python语言设计界面&#xff0c;目前最新的版本是qt5。 在PyCharm中使用pyqt5的步骤分为下载和配置两个部分。 1 在PyCharm中下载安装pyqt5相关模块 1.1 下载步骤 PyCharm中要下载的pyqt5相关模块…

kafka集群是如何选择leader,你知道吗?

前言 kafka集群是由多个broker节点组成&#xff0c;这里面包含了许多的知识点&#xff0c;以下的这些问题你都知道吗? 你知道topic的分区leader是怎么选举的吗&#xff1f;你知道zookeeper中存储了kafka的什么信息吗&#xff1f;起到什么做呢&#xff1f;你知道kafka消息文件…

【精彩回顾】 用sCrypt在Bitcoin上构建智能合约

2023年3月24日&#xff0c;sCrypt在英国Exeter大学举办了关于智能合约的大学讲学。sCrypt首席执行官刘晓晖做了题为“用sCrypt在Bitcoin上构建智能合约”的演讲&#xff0c;并与到场的老师、学生进行了深入交流、互动。这次课程着重讲解了 BSV 智能合约的基础概念&#xff0c;以…

一图读懂「五度易链」企业创新服务解决方案,打造卓越营商环境!

“五度易链”紧密围绕园区企业及产业发展需求&#xff0c;基于数据积累和应用&#xff0c;创新企业服务机制&#xff0c;提升企业服务效能&#xff0c;以数字化手段为企业发展纾困解难&#xff0c;赋能企业高质量发展。并帮助园区在运营方面打破数据壁垒&#xff0c;实现数据监…

调度算法+等待/周转时间计算

周转时间 作业完成时刻 - 到达时刻 等待时间 开始时刻 - 到达时刻 平均时间就是用总时间除以作业个数 先来先服务调度算法&#xff08;FCFS&#xff09; 非抢占 优先级调度算法 系统总是调度优先级最高的那个进程运行。 优先级可以分为静态优先级和动态优先级。静态优先…

113. 路径总和ii

力扣题目链接(opens new window) 给定一个二叉树和一个目标和&#xff0c;找到所有从根节点到叶子节点路径总和等于给定目标和的路径。 说明: 叶子节点是指没有子节点的节点。 示例: 给定如下二叉树&#xff0c;以及目标和 sum 22&#xff0c; 在路径总和题目的基础上&…

新媒体运营的未来:ChatGPT的智能助手

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 新媒体运营是数字时代的…

Java括号匹配

目录 一、题目描述 二、题解 一、题目描述 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭…

LwIP笔记01:LwIP入门

1. LwIP简介 小型开源的TCP/IP协议栈交换机、路由器、光纤收发器、云台接入、无线网关、远程模块、工业控制器、网络摄像头 TCP/IP模型 &#xff08;1&#xff09;应用层&#xff1a;HTTP、MQTT、NTP、FTP、...... &#xff08;2&#xff09;传输层&#xff1a;TCP、UDP &…

【kubernetes】【基础资源使用】kubernetes中的Deployment使用

1 Why need Deployment? K8S中Pod是用户管理工作负载的基本单位&#xff0c;Pod通常通过Service进行暴露&#xff0c;因此&#xff0c;通常需要管理一组Pod&#xff0c;RC和RS主要就实现了一组Pod的管理工作&#xff0c;其中&#xff0c;RC和RS的区别在于&#xff0c;RS提供更…

如何使用pycharm连接Mysql数据库!!!

1、Mysql的安装&#xff1a; MySQL针对不同的用户提供了2中不同的版本&#xff1a; MySQL Community Server&#xff1a;社区版。由MySQL开源社区开发者和爱好者提供技术支持&#xff0c;对开发者开放源代码并提供免费下载。MySQL Enterprise Server&#xff1a;企业版。包括最…

新手程序员怎么接单?

程序员如何在自己年富力强的时候&#xff0c;最大化发挥自己的能力&#xff1f;将超能力转化为“钞能力”&#xff1f; 有人还在苦哈哈当老黄牛&#xff0c;一身使不完的牛劲&#xff0c;有人已经另辟蹊径&#xff0c;开创了自己的一片致富小天地。 接单找兼职&#xff0c;就…

MyBatis-Plus多数据源——如何在一个项目中使用多个MySQL数据库

前言 MyBatis-Plus (opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window) 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 本系列博客结合实际应用场景&#xff0c;阐述MyBatis-Plus实际…

小程序中如何同步公众号的文章

小程序为了更好的服务客户&#xff0c;有时候需要显示公众号的文章&#xff0c;用于更具体介绍产品、关注公众号和会员服务等。下面就将具体介绍&#xff1a;小程序中如何同步显示公众号的文章。 1. 关联公众号。在管理员后台->会员管理->通知处&#xff0c;关联服务号。…

【大数据开发技术】实验05-HDFS目录与文件的创建删除与查询操作

文章目录 HDFS目录与文件的创建删除与查询操作一、实验目标二、实验要求三、实验内容四、实验步骤附&#xff1a;系列文章 HDFS目录与文件的创建删除与查询操作 一、实验目标 熟练掌握hadoop操作指令及HDFS命令行接口掌握HDFS目录与文件的创建方法和文件写入到HDFS文件的方法…

软件测试工作步骤详情

软件测试步骤按照研发阶段一般分为5个部分&#xff1a;单元测试、集成测试、确认测试、系统测试、验收测试&#xff0c;下面将不同阶段需要的一些工作内容做一下梳理希望可以帮助到大家。 一、单元测试的内容&#xff1a;&#xff08;白盒为主&#xff0c;黑盒为辅&#xff09;…