使用c++和QT图形框架进行实现(QT 5.8)

采用QT提供的图形开发库QGraphicsView QGraphicsScene QGraphicsItem.

项目完整的代码:https://github.com/qiny1012/Tetris

建立一个子类MyItem继承QGraphicsItem。构造一个矩形元素,可以给这个元素贴图设置颜色美化程序。

建立一个类MyGroup用来设置方块组,有o型,L型,J型等,包含一个MyItem的链表。

建立一个类MyScene继承QGraphicsScene,来实现方块的显示和运动。

类的核心参数

  1. MyItem,

MyItem(int w,int h);//构造一个宽为w,高为h的矩形方块

  1. MyGroup:

int pos_x;

int pos_y;//设置方块组的位置

QList<QGraphicsItem * > list;//方块的链表

int Type_rotation;

int Type_style;//设置当前的状态。方块组的方块有7中类型,每一种类型有4中旋转的状态。

MyGroup();

MyGroup(int pos_x,int pos_y,int type);//构造函数,前两个是方块组放到位置,第三个参数是方块的类型,默认的旋转类型是0.

int isColliding();//碰撞检测

void zhuangLeft();//顺时针旋转90

void zhuangRigth();//逆时针旋转90

void setPos(int x,int y);//设置方块组中各个元素的坐标

void moveBy(int x,int y);//移动方块组中的全部元素。

  1. MyScene

QGraphicsLineItem * lineItem1;

QGraphicsLineItem * lineItem2;

QGraphicsLineItem * lineItem3;//用于构造界面的线元素,也用于碰撞检测

QTimer *timer;//定时器

MyGroup * curGroup;//当前可以移动的方块组

MyGroup * nextGroup;//下一个方块组,设置在游戏的右上角

QGraphicsItem * type_ret[20][10];//界面上方块的数组,把地图看成一个10*20的数组,通过这个元素,确定是否可以销毁一行数据

int score;//得分,并没有使用

int testEnd;//检测游戏是否结束的一个变量

explicit MyScene(QObject *parent = 0);使用信号和槽函数就需要这样写,explicit表示参数不可以强制类型转化

void initScene();//初始化场景

int IsColliding(); //碰撞检测

void addGroup(MyGroup * group);//添加一个方块组到场景中

void creatNewGroup();  //产生一个方块组并且放在场景中

void setRet(); //方块放置完成记录方块。

int testRet(int row); //如果有放置之后要检测这一行是不是已经数据完成了,如果成功放回1,否则0

int destroyFromRet(int row); //把row行的数据删除,然后再把数据全部向下移动

int moveDownRet(int row);//移动小于row的数据,并且修改他们的位置

void strat();//开始游戏

void stop();//暂停游戏

void starNewGame();//开始一个新的比赛,清除所有的元素,并且重新生成curGroup和nextGroup。

void keyPressEvent(QKeyEvent * keyEvent);//键盘事件

程序执行的过程:

  1. 建立一个QGraphicsView的对象,添加到Ui中,在建立一个myscene的对象,设置他的大小。
  2. 设置要给按钮,可以调用myscene的start()函数。
  3. Myscene内部的定时器,没过0.5秒进行移动一次curGroup
  4. 如果curGroup发生了碰撞,就撤下移动,并判断是否有放满的行。如果有就删除该行,并且移动该行以上的数据。
  5. 如果失败会提示,并且重新开始

难点:

  1. 坐标,myItem移动之后,无法获取他的坐标.pos()总是返回0,0.想要使用myitem的pos必须设置。
  2. 旋转,如果使用库中的QGraphicsItemGroup,有现成的旋转函数,但是使用的过程之后,无法正常的进行碰撞检测,最后没有使用这个类。旋转函数是自己写的,它是通过移动方块到指定的位置,实现旋转的感觉。
  3. 游戏结束。目前如果程序一直按space键,还是会出现bug。

源码(如果没有看懂可以直接去参考源码,写的很稀碎)

1.MyItem.h和MyItem.cpp

#include <QGraphicsRectItem>class MyItem : public QGraphicsRectItem
{
public:MyItem();MyItem(int x);MyItem(int w,int h);MyItem(int x,int y,int w,int h);};#include "myitem.h"
//使用这个函数构造一个item的类
MyItem::MyItem(int w, int h)
{this->setRect(0,0,18,18);
}//没有使用到
MyItem::MyItem(int x, int y, int w, int h)
{this->setRect(x,y,w,h);}

2. MyGroup.h和MyGroup.cpp

#include "myitem.h"
#include <QRect>
#include <QDebug>
#include <QGraphicsItemGroup>
#include <QGraphicsObject>
#include <QKeyEvent>class MyGroup
{
public :int pos_x;int pos_y;//组的位置
public:MyGroup();MyGroup(int pos_x,int pos_y,int type);int isColliding();void zhuangLeft();void zhuangRigth();void clear();QList<QGraphicsItem * > list;int Type_rotation; //设置当前的状态。int Type_style;void setPos(int x,int y);void moveBy(int x,int y);};#include "mygroup.h"
int type_pos_x [7][4][4] = {//第一种情况
  {{0,20,0,20},{0,20,0,20},{0,20,0,20},{0,20,0,20},},//第二个图形
    {{0,0,0,20},{20,0,-20,-20},{20,20,20,0},{0,20,40,40},},//第三个图形
  {{20,20,20,0},{20,0,-20,-20},{0,0,0,20},{0,20,40,40},},//第四个图形
   {{0,0,20,20},{20,0,0,-20},{0,0,20,20},{20,0,0,-20},},//第5个图形
   {{20,20,0,0},{20,0,0,-20},{20,20,0,0},{20,0,0,-20},},//第6个图形
   {{0,0,0,0},{-40,-20,0,20},{0,0,0,0},{-40,-20,0,20},},//第7个图形
   {{0,-20,0,20},{20,0,0,0},{0,20,0,-20},{-20,0,0,0},},
};int type_pos_y [7][4][4] = {//第一种情况
  {{0,0,20,20},{0,0,20,20},{0,0,20,20},{0,0,20,20},},//第二个图形
    {{0,20,40,40},{0,0,0,20},{20,0,-20,-20},{20,20,20,0},},//第三个图形
  {{0,20,40,40},{20,20,20,0},{20,0,-20,-20},{0,0,0,20},},//第四个图形
   {{0,20,20,40},{0,0,20,20},{0,20,20,40},{0,0,20,20},},//第5个图形
   {{0,20,20,40},{20,20,0,0},{0,20,20,40},{20,20,0,0},},//第6个图形
   {{0,20,40,60},{0,0,0,0},{0,20,40,60},{0,0,0,0},},//第7个图形
   {{0,20,20,20},{0,-20,0,20},{20,0,0,0},{0,20,0,-20},},
};int type_x[7][4] ={{0,0,20,20},{0,0,0,20},{20,20,20,0},{0,0,0,0},{0,0,20,20},{20,20,0,0},{20,0,20,40}};
int type_y[7][4] = {{0,20,0,20},{0,20,40,40},{0,20,40,40},{0,20,40,60},{0,20,20,40},{0,20,20,40},{0,20,20,20}
};MyGroup::MyGroup()
{}MyGroup::MyGroup(int pos_x, int pos_y, int type)
{Type_rotation = 0;Type_style = type;this->setPos(pos_x,pos_y);MyItem * item1 = new MyItem(18,18);MyItem * item2 = new MyItem(18,18);MyItem * item3 = new MyItem(18,18);MyItem * item4 = new MyItem(18,18);item1->setPos(pos_x+type_pos_x[type][Type_rotation][0],pos_y+type_pos_y[type][Type_rotation][0]);item2->setPos(pos_x+type_pos_x[type][Type_rotation][1],pos_y+type_pos_y[type][Type_rotation][1]);item3->setPos(pos_x+type_pos_x[type][Type_rotation][2],pos_y+type_pos_y[type][Type_rotation][2]);item4->setPos(pos_x+type_pos_x[type][Type_rotation][3],pos_y+type_pos_y[type][Type_rotation][3]);list.append(item1);list.append(item2);list.append(item3);list.append(item4);
}int MyGroup::isColliding()
{QGraphicsItem *item;foreach(item, list){if(item->collidingItems(Qt::ContainsItemBoundingRect).count()>0)//collidingItems返回与当前item碰撞的子item列表return 1;//代表至少有一个item发生了碰撞
       }return 0;
}void MyGroup::zhuangLeft()
{Type_rotation++;if(Type_rotation == 4){Type_rotation = 0;}qDebug() << type_pos_x[Type_style][Type_rotation][0] << type_pos_x[Type_style][Type_rotation][0] ;list.at(0)->setPos(pos_x + type_pos_x[Type_style][Type_rotation][0],pos_y + type_pos_y[Type_style][Type_rotation][0]);list.at(1)->setPos(pos_x + type_pos_x[Type_style][Type_rotation][1],pos_y + type_pos_y[Type_style][Type_rotation][1]);list.at(2)->setPos(pos_x + type_pos_x[Type_style][Type_rotation][2],pos_y + type_pos_y[Type_style][Type_rotation][2]);list.at(3)->setPos(pos_x + type_pos_x[Type_style][Type_rotation][3],pos_y + type_pos_y[Type_style][Type_rotation][3]);}void MyGroup::zhuangRigth()
{Type_rotation--;if(Type_rotation == -1){Type_rotation = 3;}qDebug() << type_pos_x[Type_style][Type_rotation][0] << type_pos_x[Type_style][Type_rotation][0] ;list.at(0)->setPos(pos_x + type_pos_x[Type_style][Type_rotation][0],pos_y + type_pos_y[Type_style][Type_rotation][0]);list.at(1)->setPos(pos_x + type_pos_x[Type_style][Type_rotation][1],pos_y + type_pos_y[Type_style][Type_rotation][1]);list.at(2)->setPos(pos_x + type_pos_x[Type_style][Type_rotation][2],pos_y + type_pos_y[Type_style][Type_rotation][2]);list.at(3)->setPos(pos_x + type_pos_x[Type_style][Type_rotation][3],pos_y + type_pos_y[Type_style][Type_rotation][3]);}void MyGroup::clear()
{list.clear();
}void MyGroup::setPos(int x, int y)
{pos_x = x ;pos_y = y ;}void MyGroup::moveBy(int x, int y)
{pos_x = pos_x + x;pos_y = pos_y + y;list.at(0)->moveBy(x,y);list.at(1)->moveBy(x,y);list.at(2)->moveBy(x,y);list.at(3)->moveBy(x,y);
}

3.MyScene.h和MyScene.cpp

#include <QGraphicsScene>
#include "myitem.h"
#include <QDebug>
#include <QList>
#include <QMessageBox>
#include <QTimer>
#include <QVector>
#include <QKeyEvent>
#include <QTime>
#include <QtGlobal>
#include "mygroup.h"
#include <QMessageBox>class MyScene : public QGraphicsScene
{Q_OBJECT
public:QGraphicsLineItem * lineItem1;QGraphicsLineItem * lineItem2;QGraphicsLineItem * lineItem3;QTimer *timer;MyGroup * curGroup;MyGroup * nextGroup;QGraphicsItem * type_ret[20][10];int score;int testEnd;
public:explicit MyScene(QObject *parent = 0);void initScene();int IsColliding(); //return 1 yes return 0 novoid keyPressEvent(QKeyEvent * keyEvent);void addGroup(MyGroup * group);void creatNewGroup();  //产生一个方块组并且放在场景中void setRet(); //方块放置完成记录方块。int testRet(int row); //如果有放置之后要检测这一行是不是已经数据完成了,如果成功放回1,否则0int destroyFromRet(int row); //把row行的数据删除,然后再把数据全部向下移动int moveDownRet(int row);void strat();void stop();void starNewGame();public slots:int moveDownTest(); //return 1 is over;

};#include "myscene.h"
MyScene::MyScene(QObject *parent) :QGraphicsScene(parent)
{initScene();
}//初始化
void MyScene::initScene()
{lineItem1 = new QGraphicsLineItem;lineItem1->setLine(198,-10,198,400);this->addItem(lineItem1);lineItem2 = new QGraphicsLineItem;lineItem2->setLine(401,-10,401,400);this->addItem(lineItem2);lineItem3 = new QGraphicsLineItem;lineItem3->setLine(201,400,399,400);this->addItem(lineItem3);this->setSceneRect(0,0,580,410);qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));int type = qrand();type = type % 7;this->curGroup = new MyGroup(280,0,type);this->addGroup(curGroup);type = qrand();type = type % 7;this->nextGroup = new MyGroup(450,50,type);this->addGroup(nextGroup);timer = new QTimer(this);connect(timer, SIGNAL(timeout()), this, SLOT(moveDownTest()));//设置状态,当前没有一个方块在界面中for(int i = 0; i< 20 ;i ++){for(int j = 0 ;j < 10 ;j ++){type_ret[i][j] = NULL;}}testEnd = 0;
}//碰撞检测
int MyScene::IsColliding()
{QList<QGraphicsItem * > list = this->collidingItems(lineItem1);if(list.size() != 0){qDebug() << "line 1 "<<endl;return 1;}list = this->collidingItems(lineItem2);if(list.size() != 0){//this->group->moveUp();qDebug() << "line 2 "<<endl;return 1;}list = this->collidingItems(lineItem3);if(list.size() != 0){qDebug() << "line 3 "<<endl;//this->group->moveUp();return 1;}if(this->curGroup->isColliding()){return 1;};return 0;
}//键盘事件
void MyScene::keyPressEvent(QKeyEvent *keyEvent)
{if(!timer->isActive()){return ;}if(keyEvent->key() == Qt::Key_Left || keyEvent->key() == Qt::Key_A){curGroup->moveBy(-20,0);if(this->IsColliding()){curGroup->moveBy(20,0);return ;}}else if(keyEvent->key() == Qt::Key_Right || keyEvent->key() == Qt::Key_D){curGroup->moveBy(20,0);if(this->IsColliding()){curGroup->moveBy(-20,0);return ;}}else if(keyEvent->key() == Qt::Key_Down || keyEvent->key() == Qt::Key_S){curGroup->moveBy(0,20);if(this->IsColliding()){curGroup->moveBy(0,-20);return ;}}else if(keyEvent->key() == Qt::Key_Q){curGroup->zhuangLeft();if(this->IsColliding()){curGroup->zhuangRigth();}}if(keyEvent->key() == Qt::Key_Space){this->testEnd ++ ;while(!this->IsColliding()){curGroup->moveBy(0,20);}curGroup->moveBy(0,-20);}if(keyEvent->key() == Qt::Key_P){if(timer->isActive()){timer->stop();}else{timer->start(500);}}
}//把一组图形放到scene中
void MyScene::addGroup(MyGroup *group)
{this->addItem(group->list.at(0));this->addItem(group->list.at(1));this->addItem(group->list.at(2));this->addItem(group->list.at(3));
}void MyScene::creatNewGroup()
{qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));int type = qrand();type = type % 7;curGroup = new MyGroup(280,0,nextGroup->Type_style);this->removeItem(nextGroup->list.at(0));this->removeItem(nextGroup->list.at(1));this->removeItem(nextGroup->list.at(2));this->removeItem(nextGroup->list.at(3));this->nextGroup = new MyGroup(450,50,type);this->addGroup(nextGroup);this->addGroup(curGroup);testEnd = 0;
}void MyScene::setRet()
{//此处为了解决下面移动问题采用一种笨方法int row[4];int count = 0;QGraphicsItem * item ;//qDebug() << curGroup->pos_x  << curGroup->pos_y;foreach (item, curGroup->list) {int i = (item->pos().x() - 200) / 20;int j = item->pos().y() / 20;qDebug() << i << j ;type_ret[j][i] = item;row[count] = j;count ++ ;}//从开始遍历,仅仅遍历row中存在的,也就是刚才存放过的//如果消除的顺序不是cong'shang倒下就会出现下面的数据无法处理for(int i = 0 ; i < 20;i ++ ){if(testRet(i)){destroyFromRet(i);}}}int MyScene::testRet(int row)
{for(int i = 0 ; i < 10 ; i++){if(type_ret[row][i] == NULL)return 0;}return 1;
}int MyScene::destroyFromRet(int row)
{int pos_x = 210;int pos_y = row * 20 + 10;//删除一行的元素for(int i = 0 ; i < 10 ; i++){this->removeItem(type_ret[row][i]);type_ret[row][i] = NULL ;}moveDownRet(row);return 0;
}int MyScene::moveDownRet(int row)
{for(int i = row - 1 ;i >-1 ; i --){for(int j = 0 ; j < 10 ;j ++){if(type_ret[i][j]){type_ret[i][j]->moveBy(0,20);type_ret[i+1][j] = type_ret[i][j];type_ret[i][j] = NULL;}}}return 0;
}void MyScene::strat()
{timer->start(500);
}void MyScene::stop()
{timer->stop();
}void MyScene::starNewGame()
{timer->stop();QGraphicsItem * item ;foreach(item,curGroup->list){this->removeItem(item);}foreach(item,nextGroup->list){this->removeItem(item);}for(int i = 0 ; i < 20; i ++){for(int j = 0 ; j < 10 ; j++){if(type_ret[i][j]){this->removeItem(type_ret[i][j]);type_ret[i][j] = NULL;}}}qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));int type = qrand();type = type % 7;this->curGroup = new MyGroup(280,0,type);this->addGroup(curGroup);qDebug() << "clear" <<endl;type = qrand();type = type % 7;this->nextGroup = new MyGroup(450,50,type);this->addGroup(nextGroup);
}//下落的函数
int MyScene::moveDownTest()
{if(curGroup == NULL){return 0;}curGroup->moveBy(0,20);if(this->IsColliding()){if(testEnd == 0){//比赛结束//QMessageBox::warning(this, tr("game over"),tr("GAME OVER\n" "start new game"),QMessageBox::Ok);qDebug() << "game over";this->starNewGame();return 0;}curGroup->moveBy(0,-20);setRet();curGroup->clear();creatNewGroup();return 0;}testEnd ++;return 1;
}

4.mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "myscene.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);this->setGeometry(0,30,800,420);ui->graphicsView->setGeometry(0,0,610,420);scene = new MyScene ();ui->graphicsView->setScene(scene);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_pushButton_clicked()
{scene->strat();
}void MainWindow::on_pushButton_2_clicked()
{scene->stop();
}

需要在ui中添加两个按钮,和要给GraphicsView

有什么问题可以问我。可以从github上下载完整项目

转载于:https://www.cnblogs.com/qiny1012/p/9029731.html

c++和QT实现俄罗斯方块,使用GraphicsView。相关推荐

  1. linux qt 俄罗斯方块,使用Qt开发俄罗斯方块游戏

    使用Qt开发俄罗斯方块游戏,可能大家都比较感兴趣吧.那么就快看下面的详细讲解吧! 其实在QtCreator中已经有了俄罗斯方块的例子,大家可以在帮助中搜索Tetrix进行查看.其内容如下: 但是对于初 ...

  2. 一款基于Qt的俄罗斯方块游戏

    地址地址:CetTetrix-Setup-Beta-V1.0.2.333.exe-互联网文档类资源-CSDN下载

  3. arm linux 俄罗斯方块,基于ARM的俄罗斯方块游戏的开发教材.doc

    学号: 常 州 大 学 毕业设计(论文) (2012届) 题 目 学 生 学 院 专业班级 校内指导教师 专业技术职务 校外指导老师 专业技术职务 二○ 基于ARM的俄罗斯方块游戏的开发 摘 要:随着 ...

  4. .eep_eep ..已经是三月了

    .eep I seem to start every month in a state of shock that a new month has arrived, time being an eve ...

  5. QT开发(四十)——GraphicsView编程

    QT开发(四十)--GraphicsView编程 一.QGraphicsScene 1.QGraphicsScene QGraphicsScene继承自QObject,是一个管理图元的容器,与QGra ...

  6. 多人联机的俄罗斯方块游戏(C++),游戏规则模仿任天堂Tetris99,基于qt,kcp,protobuf,qslog。

    目录 Tetris 游戏截图 游戏菜单 1v1对战 9人对局 游戏特性细节介绍 攻击机制 Tetris标准特性 Super Rotation System(超级旋转系统) 7 bag system ( ...

  7. linux下qt打印功能如何实现,Qt Graphics-View的打印功能实现

    本文来研究一下Qt Graphics-View的打印功能实现. 在Qt的官方文档中介绍了Graphics-View的打印相关内容. Qt中对打印的支持是有一个独立的printsupport模块来完成的 ...

  8. 小游戏:俄罗斯方块(Qt 5.9.8)

    小游戏:俄罗斯方块 游戏介绍 过程 设计思路 实现过程 1.Block类 2.Tetris类 3.Box类 4.NextBox类 5.MainWindow类 6.main函数 结果 分析 遇到的问题 ...

  9. 分享一个Qt实现的AI版俄罗斯方块

    一直在网上伸手,也回馈一下. 程序以Qt官方提供的Tetrix俄罗斯方块为基础,进行扩展. AI算法为:Pierre Dellacherie. Pierre Dellacherie算法的参考链接:ht ...

  10. Qt版双人俄罗斯方块游戏

    Qt版双人俄罗斯方块游戏 转载请标明出处:牟尼的专栏 http://blog.csdn.net/u012027907     之前写过<VC版双人俄罗斯方块>,将其在Qt下又重写了一遍,核 ...

最新文章

  1. APMServ伪静态设置
  2. 第2周项目2程序的多文件组织
  3. Open-E DSS V7 应用系列之三 Web管理简介
  4. 大湾区|Serverless 线下活动两连发
  5. linux-telnet服务配置
  6. MySQL 5.7.11 重置root密码
  7. 用python画派大星代码_Python多线程处理数据,并打印进度条
  8. 常用数据下载网站汇总
  9. 用腾讯云轻量搭建 TeamSpeak 服务器
  10. 搜狗新闻文本分类竞赛
  11. 修改idea64.exe.vmoptions导致双击打不开idea的解决办法
  12. 运行python文件、电脑突然黑屏_电脑运行中总是突然黑屏怎么办?
  13. 3分钟教你如何在Word里快速制作单斜线和多斜线表头
  14. 什么是等保?等保流程又具体包含哪些内容呢?
  15. java判断麻将听牌,和牌看听:麻将听牌种类大全
  16. Linux离线安装Python第三方库Requests
  17. vs2015c语言内嵌汇编,C#中内嵌资源的读取
  18. 【RAC】如何修改SCAN IP的IP地址、名称、端口等信息
  19. 计算机科学引论英文精编pdf,计算机科学引论英文版.pdf
  20. 网络安全态势感知研究综述、MD5C#实现

热门文章

  1. Dynamic Wallpaper for Mac视频动态壁纸
  2. vuejs 外部嵌套from表单
  3. 安全SaaS调查品牌认知
  4. IIS中发布网站的问题
  5. SQL Server BI Step by Step SSIS 5 --- 通过Email发送查询结果
  6. Andrew Ng(coursera)单变量线性回归(LINEAR REGRESSION WITH ONE VARIABLE)
  7. 精彩的javascript对象和数组混合相加
  8. select设置高度的兼容问题
  9. Makefile中变量赋值方式
  10. 可以势利,不可以小人