使用C++的QT框架实现俄罗斯方块

编程入门 行业动态 更新时间:2024-10-09 03:22:21

使用C++的QT框架实现<a href=https://www.elefans.com/category/jswz/34/1769307.html style=俄罗斯方块"/>

使用C++的QT框架实现俄罗斯方块

今天实现一个简单的俄罗斯方块,网上别人写的都比较长还复杂,我就写了一个简单的,可以实现功能的俄罗斯方块,使用的是C++语言,框架都可以,主要是逻辑思路有都可以实现

我这边实现的逻辑为两个数组包含各个动态的点为下落进行绘画,通过判断实现这个游戏

1.绘画游戏框

// 构造函数,创建一个 Widget 对象,继承自 QWidget
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)  // 创建一个 Ui::Widget 对象
{// 在 Widget 上设置用户界面ui->setupUi(this);// 设置窗口标题为 "俄罗斯方块"this->setWindowTitle("俄罗斯方块");// 使用当前时间作为随机数生成器的种子qsrand((unsigned int)time(NULL));// 设置 Widget 的固定大小为 400x800 像素this->setFixedSize(QSize(400, 800));// 创建一个定时器对象 time1,间隔时间为 300 毫秒this->time1.setInterval(300);// 启动定时器time1.start();// 在开局时调用 addwan() 函数,随机生成四个方块形状addwan();// 连接定时器 time1 的 timeout 信号到 xialuo() 函数的槽connect(&time1, &QTimer::timeout, this, [=]() { xialuo(); });
}

在上述代码中我先设置了游戏的标题,大小等,还设置了一个定时器,没300毫秒绘画刷新一次,之后就是画线,代码如下

void Widget::paintEvent(QPaintEvent *event)
{// 创建一个 QPainter 对象,用于在当前 Widget 上绘制图形QPainter huajia(this);// 绘制垂直方向的网格线,总共10条,间隔40像素for (int a = 0; a < 10; a++) {huajia.drawLine(40 * a, 0, 40 * a, 800);}// 绘制水平方向的网格线,总共20条,间隔40像素for (int a = 0; a < 20; a++) {huajia.drawLine(0, 40 * a, 400, 40 * a);}// 调用基类 QWidget 的 paintEvent 函数,以便处理默认的绘制操作return QWidget::paintEvent(event);
}

2.之后画方块,方块的我我这边设置了四种情况,如下

// widget.h 文件#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QVector>
#include <QPoint>// Widget 类,继承自 QWidget
class Widget : public QWidget
{Q_OBJECTpublic:// 存储坐标点的 QVectorQVector<QPoint> quandian;// 构造函数,可指定父对象,默认为 nullptrWidget(QWidget *parent = nullptr);// 析构函数~Widget();// 重写绘制事件的函数void paintEvent(QPaintEvent *event);// 重写按键事件的函数void keyPressEvent(QKeyEvent *event);// 函数用于向 quandian 中添加ling形状的坐标点void addling();// 函数用于向 quandian 中添加yi形状的坐标点void addyi();// 函数用于向 quandian 中添加er形状的坐标点void adder();// 函数用于向 quandian 中添加san形状的坐标点void addsan();// 函数用于向 quandian 中添加wan形状的坐标点void addwan();// 存储坐标点的另一个 QVectorQVector<QPoint> quanku;private:// 指向 UI 对象的指针Ui::Widget *ui;
};#endif // WIDGET_H

 先不看quandian和quanku这两个点容器,add...是初始方块容器的点,我这边使用随机数实现,代码如下

void Widget::addwan()
{// 调用 jiance 函数,可能是检查函数jiance(quanku);// 随机生成一个 0 到 3 之间的整数this->zhu = qrand() % 4;// 根据生成的随机数执行不同的操作switch (this->zhu) {case 0:// 调用 addling 函数addling();break;case 1:// 调用 addyi 函数addyi();break;case 2:// 调用 adder 函数adder();break;case 3:// 调用 addsan 函数addsan();break;}
}

 函数实现如下

void Widget::addling()
{ // 生成一个 0 到 5 之间的随机整数this->suijishu = qrand() % 6;// 将四个坐标点添加到 'quandian' 集合中,X 坐标逐次递增this->quandian.push_back(QPoint(suijishu, 0));this->quandian.push_back(QPoint(suijishu + 1, 0));this->quandian.push_back(QPoint(suijishu + 2, 0));this->quandian.push_back(QPoint(suijishu + 3, 0));
}void Widget::addyi()
{ // 生成一个 0 到 5 之间的随机整数this->suijishu = qrand() % 6;// 将四个坐标点添加到 'quandian' 集合中,前三个的 X 坐标逐次递增,第四个的 X 坐标与第一个相同,Y 坐标加 1this->quandian.push_back(QPoint(suijishu, 0));this->quandian.push_back(QPoint(suijishu + 1, 0));this->quandian.push_back(QPoint(suijishu + 2, 0));this->quandian.push_back(QPoint(suijishu, 1));
}void Widget::adder()
{ // 生成一个 0 到 5 之间的随机整数this->suijishu = qrand() % 6;// 将四个坐标点添加到 'quandian' 集合中,前三个的 X 坐标逐次递增,第四个的 X 坐标与第二个相同,Y 坐标加 1this->quandian.push_back(QPoint(suijishu, 0));this->quandian.push_back(QPoint(suijishu + 1, 0));this->quandian.push_back(QPoint(suijishu + 2, 0));this->quandian.push_back(QPoint(suijishu + 1, 1));
}void Widget::addsan()
{// 生成一个 0 到 5 之间的随机整数this->suijishu = qrand() % 6;// 将四个坐标点添加到 'quandian' 集合中,前两个的 X 坐标逐次递增,后两个的 X 坐标相同,Y 坐标递增this->quandian.push_back(QPoint(suijishu, 0));this->quandian.push_back(QPoint(suijishu + 1, 0));this->quandian.push_back(QPoint(suijishu, 1));this->quandian.push_back(QPoint(suijishu + 1, 1));
}

随机数是俄罗斯方块上部的任意点,y为0,比如addsan()

这边最快只能截到这里了,本来应该在最上方

之后使用绘画技术实现quandian这个点容器,如上图所示

void Widget::paintEvent(QPaintEvent *event)
{// 遍历 'quandian' 集合中的坐标点for (int a = 0; a < quandian.size(); a++) {// 在画布上绘制矩形,每个矩形的左上角坐标为 (x * 40, y * 40),宽度和高度均为 40 像素huajia.drawRect(quandian[a].x() * 40, quandian[a].y() * 40, 40, 40);}// 设置画刷的颜色为绿色huashua.setColor(Qt::green);// 设置画刷的样式为实心填充huashua.setStyle(Qt::SolidPattern);// 为绘制的矩形设置画刷huajia.setBrush(huashua);// 调用基类的 paintEvent 函数,完成绘制操作return QWidget::paintEvent(event);
}

或者addyi()这个函数进行绘画

3.方块下落,这个只需要遍历点的每一个y都加一就行了

void Widget::xialuo()
{// 遍历 'quandian' 集合中的坐标点for (int a = 0; a < quandian.size(); a++){// 将每个坐标点的 Y 坐标增加 1,实现向下移动quandian[a].setY(quandian[a].y() + 1);}// 调用 update 函数触发重绘事件,以便在界面上更新坐标点的位置this->update();
}

如下

会一直定时器下落进行绘画 

由于这个截图不会停止,就只能到这里了

4.方块可以根据按键进行移动,这个只需要写一个按键事件,之后根据速度调换xy坐标进行绘画就行

void Widget::keyPressEvent(QKeyEvent *event)
{switch (event->key()) {case Qt::Key_W:// 处理按下"W"键的逻辑// 这里可以添加相关的代码break;case Qt::Key_A:// 处理按下"A"键的逻辑for (int a = 0; a < quandian.size(); a++){for (int b = 0; b < quandian.size(); b++){// 检查如果任何坐标点的 X 坐标为 0,就不执行移动if (quandian[b].x() == 0){return;  // 返回,不执行移动操作}}// 移动所有坐标点的 X 坐标减 1,实现向左移动quandian[a].setX(quandian[a].x() - 1);}break;case Qt::Key_S:// 处理按下"S"键的逻辑for (int a = 0; a < quandian.size(); a++){// 将所有坐标点的 Y 坐标加 1,实现向下移动quandian[a].setY(quandian[a].y() + 1);}break;case Qt::Key_D:// 处理按下"D"键的逻辑for (int a = 0; a < quandian.size(); a++){for (int b = 0; b < quandian.size(); b++){// 检查如果任何坐标点的 X 坐标为 9,就不执行移动if (quandian[b].x() == 9){return;  // 返回,不执行移动操作}}// 移动所有坐标点的 X 坐标加 1,实现向右移动quandian[a].setX(quandian[a].x() + 1);}break;case Qt::Key_F:// 处理按下"F"键的逻辑if (qw == false){// 如果 'qw' 为假,启动计时器time1.start();qw = true;}else{// 如果 'qw' 为真,停止计时器time1.stop();qw = false;}break;}
}

如下

5.下落到地上时的变色绘画

我主要是使用两点,quandian和quanku这两个点容器的数据传输实现,先绘画遍历这两个数组的点,代码如下

void Widget::paintEvent(QPaintEvent *event)
{// 绘制游戏中的坐标点for (int a = 0; a < quandian.size(); a++) {// 在指定位置绘制方块,每个方块的大小为40x40huajia.drawRect(quandian[a].x() * 40, quandian[a].y() * 40, 40, 40);}// 设置笔刷颜色为绿色huashua.setColor(Qt::green);// 设置笔刷风格为实色填充huashua.setStyle(Qt::SolidPattern);huajia.setBrush(huashua);// 绘制游戏中的块(或方块)for (int c = 0; c < quanku.size(); c++) {// 在指定位置绘制方块,每个方块的大小为40x40huajia.drawRect(quanku[c].x() * 40, quanku[c].y() * 40, 40, 40);}// 调用父类的绘制函数,确保事件被正确处理return QWidget::paintEvent(event);
}

如何判断呢,我这边使用的是遍历quandian的所有点,如果quanjian的元素有y达到了19,那么为最低点,如下

最下面的点会执行这个函数

for (int a = 0; a < quandian.size(); a++) {// 检查当前 'quandian' 中的坐标点的 Y 值是否为 19if (quandian[a].y() == 19) {// 如果条件满足,则执行以下操作// 将 'quandian' 中的所有坐标点添加到 'quanku' 集合中for (int b = 0; b < quandian.size(); b++) {quanku.push_back(quandian[b]);}// 清空 'quandian' 集合quandian.clear();// 调用 'addwan()' 函数addwan();// 跳出当前循环break;} else {// 如果 'quandian' 中的任何坐标点的 Y 值不为 19,则执行这里的逻辑// 可以在此处添加相应的操作}
}

 还有就是碰撞也要变色,如下

下落后碰撞

需要再上述代码中加上else,遍历两个数组如果碰撞元素也会从quandian转移到quanku中,详细代码如下 

void Widget::paintEvent(QPaintEvent *event) {// 遍历名为 'quandian' 的集合中的所有坐标点for (int a = 0; a < quandian.size(); a++) {// 如果当前坐标点的 Y 坐标等于 19if (quandian[a].y() == 19) {// 如果条件满足,执行以下操作:// 将 'quandian' 中的所有坐标点添加到 'quanku' 集合中for (int b = 0; b < quandian.size(); b++) {quanku.push_back(quandian[b]);}// 清空 'quandian' 集合quandian.clear();// 调用 'addwan()' 函数addwan();// 跳出当前循环break;} else {// 如果条件不满足,执行以下操作:// 再次遍历 'quandian' 集合for (int a = 0; a < quandian.size(); a++) {// 遍历 'quanku' 集合for (int b1 = 0; b1 < quanku.size(); b1++) {// 如果 'quandian' 中的某个坐标点的 X 和 Y 坐标与 'quanku' 中的某个坐标点的 X 和 Y 坐标相邻if (quandian[a].x() == quanku[b1].x() && quandian[a].y() == quanku[b1].y() - 1) {// 执行以下操作:// 将 'quandian' 中的所有坐标点添加到 'quanku' 集合中for (int b = 0; b < quandian.size(); b++) {quanku.push_back(quandian[b]);}// 清空 'quandian' 集合quandian.clear();// 调用 'addwan()' 函数addwan();// 跳出内部循环break;}}}}}// 返回 QWidget::paintEvent(event) 的结果return QWidget::paintEvent(event);
}

6.最后就是失败提醒了,这个只需要判断quanku(绿色)的y是否为最上方,代码如下

void Widget::jiance(QVector<QPoint> &zxc) {// 遍历名为 'zxc' 的 QVector 集合中的所有坐标点for (int a = 0; a < zxc.size(); a++) {// 如果当前坐标点的 Y 坐标等于 0if (zxc[a].y() == 0) {// 如果条件满足,执行以下操作:// 显示一个消息框,提示用户失败了QMessageBox::information(this, "失败了", "你个猪");// 清空名为 'quanku' 的集合this->quanku.clear();// 跳出当前循环break;}}
}

点击ok之后清空

这样的简单的俄罗斯方块就实现好了

更多推荐

使用C++的QT框架实现俄罗斯方块

本文发布于:2023-11-17 13:10:38,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1643526.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:俄罗斯方块   框架   QT

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!