Qt5 图形视图框架QGraphicsView

1、图形视图框架包含三大类:场景类(QGraphicsScene),视图类(QGraphicsView),图元类(QGraphicsItem); 
2、对于有很多项的场景,使用轻量级的QGraphicsItem类作为数目众多的自定义项的基础最好,仅对数目较少的项使用QGraphicsObject 
3、当一个项发生了变换(transformation),该项所有的子对象自动应用 该变换,递归应用到最深层次的子孙对象, 
变换有(拖动,移动。。。。。),通过调用QGraphicsItem::setFlag(QGraphicsItem::ItemIngnoreTransformation)可以使子项忽略父项的变换,通常使用的标志还有可移动,选中,获得焦点等 
4、通过把项设置为QGraphicsItemGroup的子项,可以将他们分组,创建项的集合。 
5、图形视图类使用三种坐标系统,但是实际应用中只是关心其中的两种。视图使用物理坐标系统,场景使用在构造函数中传入的QRectF定义的逻辑坐标系统。Qt自动进行场景坐标到视图坐标的映射,放置项时使用的是场景的坐标。项的中心是在(0,0)点的逻辑坐标系统,每个项的(0,0)点实际在该项场景中所在位置的中心(文本项除外,原点在项的左上角)。 
6、图形项:QGraphicsItem因为有两个纯虚函数而不能实例化对象,这两个纯虚函数是boundingRect()和paint() 
paint()函数必须重新实现来绘制项,boundingRect()函数在图形视图框架中为项提供一个边界矩形,用于冲突监测和保证项仅在QGraphicsView的视口(viewport)中可见时才重绘。如果要创建非矩形形状的自定义图形项,最好同时实现shape()方法,这个方法返回一个精确描述项的轮廓的QpainterPath,对于准确检测冲突和鼠标点击非常有用。 
7、如果要自定义一个形状,最简单的是使用标准的QGraphicsItem的子类之一,比如QGraphicsPathItem和QGraphicsPolygonItem,如果有定制行为,可以重新实现保护事件的处理函数,如keyPressEvent()。如果只是想要自己绘制,可以从QGraphicsItem派生,重新实现boundingRect()和paint()和shape()方法。

俄罗斯方块的实现

俄罗斯方块的逻辑

小方块的类型

效果图

 

代码的实现

onePiece.h

#ifndef ONEPIECE_H
#define ONEPIECE_H /************
*一块方块的绘制
*
*
***************/ #include <QGraphicsObject>
#include <QColor> class onePiece : public QGraphicsObject
{
public:
onePiece(const QColor &brushColor = Qt::red);
//为项提供一个外围的边界矩形
virtual QRectF boundingRect() const;
//QGraphicsView调用,在本地坐标系统中绘制项
virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
//重新定义项的形状,默认调用boundingRect获取项的矩形形状轮廓
virtual QPainterPath shape() const;
private:
QColor m_brushColor; }; #endif // ONEPIECE_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

onepiece.c

#include "onepiece.h"
#include <QPainter>
#include "enumHeader.h" /****
* 为了避免同一个方块组内小方块发生碰撞,
* 小方块的大小实际为19.5*19.5,但是小方块加上笔刷的宽度后为20*20
* 这样看起来是四个小方块连在一起的
* **/ onePiece::onePiece(const QColor &brushColor)
:m_brushColor(brushColor)
{
} QRectF onePiece::boundingRect() const
{
qreal penWidth = PEN_WIDTH;
return QRectF(-(PIECE_DIAMETER - penWidth)/2, -(PIECE_DIAMETER - penWidth)/2,
PIECE_DIAMETER - penWidth, PIECE_DIAMETER - penWidth);
} void onePiece::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
//背景贴图
painter->drawPixmap(-PIECE_DIAMETER/2,-PIECE_DIAMETER/2,PIECE_DIAMETER,PIECE_DIAMETER,QPixmap(":/piece/Image/piece/box.png"));
painter->setBrush(m_brushColor);
//将方块的边界的颜色进行透明化
QColor penColor = m_brushColor;
// 将颜色的透明度减小
penColor.setAlpha(200);
painter->setPen(penColor);
//使用当前的笔刷和笔画矩形框
painter->drawRect(-PIECE_DIAMETER/2, -PIECE_DIAMETER/2, PIECE_DIAMETER, PIECE_DIAMETER);
} QPainterPath onePiece::shape() const
{
QPainterPath path;
//去除笔刷的宽度,这样同一个方块组的方块就不会被检测出碰撞的情况
path.addRect(-(PIECE_DIAMETER-PEN_WIDTH)/2,-(PIECE_DIAMETER-PEN_WIDTH)/2,PIECE_DIAMETER-PEN_WIDTH,PIECE_DIAMETER-PEN_WIDTH);
return path;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

pieceBox.h

#ifndef PIECEBOX_H
#define PIECEBOX_H /********
* 方块组
* 4*4
*
*
* ******/ #include <QGraphicsItemGroup>
#include <QKeyEvent>
#include <QTimer>
#include "enumHeader.h"
#include <QTransform>
#include "onepiece.h"
#include <QGraphicsItem> class pieceBox :public QObject,public QGraphicsItemGroup
{
Q_OBJECT
public:
pieceBox();
//颜色表
static QColor colorTable[7];
//绘制方块组的边框矩形
virtual QRectF boundingRect() const;
//是否发生碰撞
bool isCollding() const;
//获取当前的方块类型
BoxType getCurrentBoxType() const;
//创建方块组
void createBox(const QPointF &point = QPointF(0,0),
BoxType currentBoxType = RandomShape);
//消除方块组
void clearBoxGroup(const bool &isClear = false); protected:
virtual void keyPressEvent(QKeyEvent * event); signals:
void signal_needNewBox();
void signal_gameOver();
public slots:
void slot_moveOneStep();
void slot_startTimer(int timeSec);
void slot_stopTimer();
private:
QTimer *m_Timer;
BoxType m_currentBoxType;
QTransform m_oldTransform;
QList<onePiece *> m_pieceBoxList; //存放新方块组的四个方块
}; #endif // PIECEBOX_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

pieceBox.c

#include "piecebox.h"
#include "enumHeader.h"
#include <QList>
#include <QDebug> QColor pieceBox::colorTable[7] = {QColor(200,0,0,100),QColor(255,200,0,100),
QColor(0,0,200,100),QColor(0,200,0,100),
QColor(0,200,255,100),QColor(200,0,255,100),
QColor(150,100,100,100)}; pieceBox::pieceBox()
{
m_pieceBoxList.clear();
//使得方块组支持键盘操作
setFlags(QGraphicsItem::ItemIsFocusable);
//保存矩阵的原状态,使得可以还原矩阵
m_oldTransform = transform();
m_Timer = new QTimer(this);
connect(m_Timer,SIGNAL(timeout()),this,SLOT(slot_moveOneStep()));
m_currentBoxType = RandomShape;
} //绘制方块组的边框矩形
QRectF pieceBox::boundingRect() const
{
qreal penWidth = PEN_WIDTH;
return QRectF(-(PIECE_DIAMETER*2 - penWidth) / 2, -(PIECE_DIAMETER*2 - penWidth) / 2,
PIECE_DIAMETER*4-penWidth, PIECE_DIAMETER*4-penWidth);
} bool pieceBox::isCollding() const
{
//依次检测方块组中的每个方块的碰撞
foreach (onePiece *piece, m_pieceBoxList) {
// qDebug() << "colliding number:" << piece->collidingItems().count();
//获取与该方块碰撞的方块的个数
if(piece->collidingItems().count() > 1)
{
return true;
}
}
return false;
} BoxType pieceBox::getCurrentBoxType() const
{
return m_currentBoxType;
} void pieceBox::createBox(const QPointF &point, BoxType currentBoxType)
{
int boxType = currentBoxType;
if(boxType == RandomShape)
{
boxType = qrand() % 7;
}
//设置该方块组的颜色
QColor boxColor = colorTable[boxType];
//准备四个小方块 //恢复方块组的变换矩阵,因为之前的方块组的变换会导致变换矩阵的位置发生变换,
//防止新的方块组因为旧的方块组变换异常
setTransform(m_oldTransform);
setRotation(0);
resetTransform(); m_pieceBoxList.clear();
for(int i = 0;i < 4;i++)
{
onePiece *piece = new onePiece(boxColor);
m_pieceBoxList.append(piece);
//将小方块添加到方块组中
addToGroup(piece);
}
//设置方块组的形状
switch (boxType) {
case IShape:
m_currentBoxType = IShape;
m_pieceBoxList.at(0)->setPos(-30,-10);
m_pieceBoxList.at(1)->setPos(-10,-10);
m_pieceBoxList.at(2)->setPos(10,-10);
m_pieceBoxList.at(3)->setPos(30,-10);
break;
case JShape:
m_currentBoxType = JShape;
m_pieceBoxList.at(0)->setPos(10,-10);
m_pieceBoxList.at(1)->setPos(10,10);
m_pieceBoxList.at(2)->setPos(10,30);
m_pieceBoxList.at(3)->setPos(-10,30);
break;
case LShape:
m_currentBoxType = LShape;
m_pieceBoxList.at(0)->setPos(-10,-10);
m_pieceBoxList.at(1)->setPos(-10,10);
m_pieceBoxList.at(2)->setPos(10,30);
m_pieceBoxList.at(3)->setPos(-10,30);
break;
case OShape:
m_currentBoxType = OShape;
m_pieceBoxList.at(0)->setPos(-10,-10);
m_pieceBoxList.at(1)->setPos(10,-10);
m_pieceBoxList.at(2)->setPos(-10,10);
m_pieceBoxList.at(3)->setPos(10,10);
break;
case SShape:
m_currentBoxType = SShape;
m_pieceBoxList.at(0)->setPos(30,-10);
m_pieceBoxList.at(1)->setPos(10,-10);
m_pieceBoxList.at(2)->setPos(10,10);
m_pieceBoxList.at(3)->setPos(-10,10);
break;
case TShape:
m_currentBoxType = TShape;
m_pieceBoxList.at(0)->setPos(-10,-10);
m_pieceBoxList.at(1)->setPos(10,-10);
m_pieceBoxList.at(2)->setPos(30,-10);
m_pieceBoxList.at(3)->setPos(10,10);
break;
case Zshape:
m_currentBoxType = Zshape;
m_pieceBoxList.at(0)->setPos(-10,-10);
m_pieceBoxList.at(1)->setPos(10,-10);
m_pieceBoxList.at(2)->setPos(10,10);
m_pieceBoxList.at(3)->setPos(30,10);
break;
default:
break;
}
//设置方块组的位置
setPos(point);
//检测是否发生碰撞,发生碰撞,游戏结束
if(isCollding())
{
slot_stopTimer();
emit signal_gameOver();
}
} //删除方块组中的小方块到情景中
void pieceBox::clearBoxGroup(const bool &isClear)
{
QList<QGraphicsItem *> itemList = childItems();
foreach (QGraphicsItem *piece, itemList) {
removeFromGroup(piece);
// qDebug() << "clear box group" << isClear;
if(isClear)
{
//销毁小方块
((onePiece *)piece)->deleteLater();
}
}
m_pieceBoxList.clear();
} void pieceBox::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_Down:
moveBy(0,20);
//检测是否碰撞
if(isCollding())
{
moveBy(0,-20);
clearBoxGroup();
//需要新的方块
emit signal_needNewBox();
}
break;
case Qt::Key_Left:
moveBy(-20,0);
if(isCollding())
{
moveBy(20,0);
} break;
case Qt::Key_Right:
moveBy(20,0);
if(isCollding())
{
moveBy(-20,0);
}
break;
case Qt::Key_Up:
setRotation(rotation()+90);
if(isCollding())
{
setRotation(rotation()-90);
}
break;
case Qt::Key_Space: //快速下落
moveBy(0,20);
while (!isCollding()) {
moveBy(0,20);
}
moveBy(0,-20);
clearBoxGroup();
//需要新的方块
emit signal_needNewBox();
break;
default:
break;
}
} void pieceBox::slot_moveOneStep()
{
moveBy(0,20);
// qDebug() << "move one step";
if(isCollding())
{
moveBy(0,-20);
// 将小方块从方块组中移除到场景中
clearBoxGroup();
//需要新的方块
emit signal_needNewBox();
}
} void pieceBox::slot_startTimer(int timeSec)
{
m_Timer->start(timeSec);
} void pieceBox::slot_stopTimer()
{
m_Timer->stop();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229

**界面类**panel.h

#ifndef PANEL_H
#define PANEL_H #include <QWidget>
#include <QPalette>
#include <QPixmap>
#include <QGraphicsScene>
#include <QGraphicsView>
#include "piecebox.h"
#include "onepiece.h"
#include <QGraphicsLineItem>
#include <QMediaPlayer> namespace Ui {
class Panel;
} class Panel : public QWidget
{
Q_OBJECT public:
explicit Panel(QWidget *parent = 0);
~Panel();
void setbackground(const int &Lv);
void initControlWidget();
void initGraphicsViewWidget(); /**游戏控制项***/
void startGame();
void pauseGame();
void restartGame();
void stopGame(); void updateScore(const int fullRows = 0); private slots:
void on_pbt_startGame_clicked(); void on_pbt_pauseGame_clicked(); void on_pbt_restart_clicked(); void on_pbt_stopGame_clicked(); void slot_clearFullRows(); void slot_gameOver(); void slot_moveBox();
private:
Ui::Panel *ui;
QPalette m_Palette;
QPixmap m_pixmap;
int m_currentLv;
int m_currentLVSpeed;
bool m_isPauseGame;
bool m_isGameOver;
QGraphicsScene *m_scene;
//四条边界线
QGraphicsLineItem *m_topLine;
QGraphicsLineItem *m_leftLine;
QGraphicsLineItem *m_buttomLine;
QGraphicsLineItem *m_rightLine; pieceBox *m_currentBox;
pieceBox *m_nextBox; QList<int> m_rowList;
QMediaPlayer *m_mediaPlayer;
}; #endif // PANEL_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

panel.c

#include "panel.h"
#include "ui_panel.h"
#include "enumHeader.h"
#include <QDebug>
#include <QGraphicsBlurEffect>
#include <QPropertyAnimation>
#include <QMessageBox>
#include <QMediaContent> Panel::Panel(QWidget *parent) :
QWidget(parent),
ui(new Ui::Panel)
{
ui->setupUi(this);
m_isPauseGame = false;
m_isGameOver = false; m_mediaPlayer = new QMediaPlayer;
m_mediaPlayer->setMedia(QUrl::fromLocalFile(QString("clearRow.mp3")));
m_mediaPlayer->setVolume(100);
//设置背景
setbackground(LV0);
initControlWidget(); initGraphicsViewWidget();
} Panel::~Panel()
{
delete ui;
} void Panel::setbackground(const int &Lv)
{
setAutoFillBackground(true);
switch (Lv) {
case LV0:
m_currentLv = LV0;
m_currentLVSpeed = LV0_SPEED;
ui->label_gameLevel->setText("俄罗斯方块");
m_pixmap.load(":/background/Image/background/background.png");
break;
case LV1:
m_currentLv = LV1;
m_currentLVSpeed = LV1_SPEED;
ui->label_gameLevel->setText("第一关");
m_pixmap.load(":/background/Image/background/background01.png");
break;
case LV2:
m_currentLv = LV2;
m_currentLVSpeed = LV2_SPEED;
ui->label_gameLevel->setText("第二关");
m_pixmap.load(":/background/Image/background/background02.png");
break;
case LV3:
m_currentLv = LV3;
m_currentLVSpeed = LV3_SPEED;
ui->label_gameLevel->setText("第三关");
m_pixmap.load(":/background/Image/background/background03.png");
break;
case LV4:
m_currentLv = LV4;
m_currentLVSpeed = LV4_SPEED;
ui->label_gameLevel->setText("第四关");
m_pixmap.load(":/background/Image/background/background04.png");
break;
case LV5:
m_currentLv = LV5;
m_currentLVSpeed = LV5_SPEED;
ui->label_gameLevel->setText("第五关");
m_pixmap.load(":/background/Image/background/background05.png");
break;
default:
break;
}
m_Palette.setBrush(QPalette::Window, QBrush(m_pixmap.scaled(size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
setPalette(m_Palette);
} void Panel::initControlWidget()
{
switch (m_currentLv) {
case LV0:
ui->pbt_startGame->setEnabled(true);
ui->pbt_pauseGame->setEnabled(false);
ui->pbt_restart->setEnabled(false);
ui->pbt_stopGame->setEnabled(false);
break;
case LV1:
case LV2:
case LV3:
case LV4:
case LV5:
ui->pbt_startGame->setEnabled(false);
ui->pbt_pauseGame->setEnabled(true);
ui->pbt_restart->setEnabled(true);
ui->pbt_stopGame->setEnabled(true);
break;
default:
break;
}
} void Panel::initGraphicsViewWidget()
{
//使用抗锯齿渲染
ui->GraphicsView->setRenderHint(QPainter::Antialiasing);
//设置缓冲背景,加速渲染
ui->GraphicsView->setCacheMode(QGraphicsView::CacheBackground); m_scene = new QGraphicsScene(this);
m_scene->setSceneRect(30,30,310,410);
ui->GraphicsView->setScene(m_scene); //方块可移动的四条线
//向外扩展3像素,这样可以使方块组到达边界的时候再移动就会发生碰撞
m_topLine = m_scene->addLine(32,32,238,32);
m_leftLine = m_scene->addLine(32,32,32,438);
m_buttomLine = m_scene->addLine(32,438,238,438);
m_rightLine = m_scene->addLine(238,32,238,438); m_topLine->setPen(QPen(QColor(255,255,255)));
m_leftLine->setPen(QPen(QColor(255,255,255)));
m_buttomLine->setPen(QPen(QColor(255,255,255)));
m_rightLine->setPen(QPen(QColor(255,255,255))); m_currentBox = new pieceBox;
m_nextBox = new pieceBox;
connect(m_currentBox,SIGNAL(signal_needNewBox()),this,SLOT(slot_clearFullRows()));
connect(m_currentBox,SIGNAL(signal_gameOver()),this,SLOT(slot_gameOver()));
m_scene->addItem(m_currentBox);
m_scene->addItem(m_nextBox);
} void Panel::startGame()
{
m_currentBox->createBox(QPointF(135,55));
m_nextBox->createBox(QPointF(290,55));
//将键盘焦点给当前的方块组
m_currentBox->setFocus();
m_currentBox->slot_startTimer(m_currentLVSpeed);
} void Panel::updateScore(const int fullRows)
{
int score = ui->LCDNum_Score->value() + fullRows*ROWSCORE; ui->LCDNum_Score->display(score);
if(score < 1000) //第一关
{ }else if(score < 2000) //第二关
{
setbackground(LV2);
initControlWidget();
m_currentBox->slot_stopTimer();
m_currentBox->slot_startTimer(m_currentLVSpeed);
}else if(score < 4000) //第三关
{
setbackground(LV3);
initControlWidget();
m_currentBox->slot_stopTimer();
m_currentBox->slot_startTimer(m_currentLVSpeed);
}else if(score < 8000) //第四关
{
setbackground(LV4);
initControlWidget();
m_currentBox->slot_stopTimer();
m_currentBox->slot_startTimer(m_currentLVSpeed);
}else if(score < 16000) //第五关
{
setbackground(LV5);
initControlWidget();
m_currentBox->slot_stopTimer();
m_currentBox->slot_startTimer(m_currentLVSpeed);
}else //从第一关重新开始
{
setbackground(LV1);
initControlWidget();
m_currentBox->slot_stopTimer();
m_currentBox->slot_startTimer(m_currentLVSpeed);
}
} /**
* 开始游戏
* @brief Panel::on_pbt_startGame_clicked
*/ void Panel::on_pbt_startGame_clicked()
{
m_isGameOver = false;
if(m_isPauseGame)
{
ui->pbt_startGame->setEnabled(false);
m_isPauseGame = false;
m_currentBox->slot_startTimer(m_currentLVSpeed);
return;
}
//默认等级为LV1
setbackground(LV1);
initControlWidget(); startGame();
} /**
* 暂停游戏
* @brief Panel::on_pbt_pauseGame_clicked
*/
void Panel::on_pbt_pauseGame_clicked()
{
if(m_isPauseGame)
{
return;
}
m_isPauseGame = true;
m_currentBox->slot_stopTimer();
ui->pbt_startGame->setEnabled(true);
QMessageBox::information(this,"提示","暂停游戏!",QMessageBox::Yes);
} /**
* 重新开始游戏
* @brief Panel::on_pbt_restart_clicked
*/
void Panel::on_pbt_restart_clicked()
{ m_currentBox->slot_stopTimer();
m_currentBox->clearBoxGroup();
m_nextBox->clearBoxGroup(true);
//先将当前的小正方形组移出游戏框,防止下面的清除item将该方块组清除了
m_currentBox->setPos(290,55);
ui->LCDNum_Score->display(0); //清空视图中所有的小方块
foreach (QGraphicsItem *item, m_scene->items(34, 34, 204, 404, Qt::ContainsItemShape,Qt::AscendingOrder)) {
// 先从场景中移除小方块,因为使用deleteLater()是在返回主事件循环后才销毁
// 小方块的,为了在出现新的方块组时不发生碰撞,所以需要先从场景中移除小方块
m_scene->removeItem(item);
onePiece *piece = (onePiece*) item;
piece->deleteLater();
}
m_isPauseGame = false;
on_pbt_startGame_clicked();
} /**
* 停止游戏
* @brief Panel::on_pbt_stopGame_clicked
*/
void Panel::on_pbt_stopGame_clicked()
{
m_currentBox->slot_stopTimer();
slot_gameOver();
} /**清除满行的小方块
* @brief Panel::slot_clearFullRows
*/
void Panel::slot_clearFullRows()
{
m_rowList.clear();
//获取比一行方格多行的所有小方块,不包含最高的一行
for(int i = 414;i > 35; i-=20)
{
//返回可视区域(202*22)内所有的完全可视的item
QList<QGraphicsItem *> itemList = m_scene->items(34,i,204,22,Qt::ContainsItemShape,Qt::AscendingOrder);
// qDebug() << "可是区域内的item数:" << itemList.count();
//已满
if(itemList.count() == 10)
{
//遍历列表删除小方块
foreach (QGraphicsItem *item, itemList) {
onePiece *piece = (onePiece *)item; //模糊效果,先放大再缩小
QGraphicsBlurEffect *blurEffect = new QGraphicsBlurEffect;
piece->setGraphicsEffect(blurEffect);
QPropertyAnimation *animation = new QPropertyAnimation(piece,"scale");
animation->setDuration(250);
animation->setEasingCurve(QEasingCurve::OutBounce);
animation->setStartValue(4);
animation->setEndValue(0.25);
animation->start(QAbstractAnimation::DeleteWhenStopped);
connect(animation,SIGNAL(finished()),piece,SLOT(deleteLater()));
}
m_mediaPlayer->play();
//记录满行的行地址
m_rowList.append(i);
}
}
// qDebug() << "满行的行数:" << m_rowList.size();
//存在满行,删除后将上面的方块下移
if(!m_rowList.isEmpty())
{
//等待所有的小正方形都销毁后再将上方的小正方形向下移动
QTimer::singleShot(300,this,SLOT(slot_moveBox()));
}else //直接创建新的方块组
{
m_currentBox->createBox(QPointF(135,55), m_nextBox->getCurrentBoxType());
// 清空并销毁提示方块组中的所有小方块
m_nextBox->clearBoxGroup(true);
if(!m_isGameOver)
{
m_nextBox->createBox(QPointF(290,55));
}
}
} void Panel::slot_gameOver()
{
// qDebug() << "game over";
m_isGameOver = true;
QMessageBox::information(this,"提示",QString("您的游戏得分为%1!").arg(ui->LCDNum_Score->value()),QMessageBox::Yes);
ui->LCDNum_Score->display(0);
m_currentBox->clearFocus(); setbackground(LV0);
initControlWidget();
m_isPauseGame = false;
//初始化界面
m_currentBox->clearBoxGroup(true);
m_nextBox->clearBoxGroup(true);
//先将当前的小正方形组移出游戏框,防止下面的清除item将该方块组清除了
m_currentBox->setPos(290,55);
//清空视图中所有的小方块
foreach (QGraphicsItem *item, m_scene->items(34, 34, 204, 404, Qt::ContainsItemShape,Qt::AscendingOrder)) {
// 先从场景中移除小方块,因为使用deleteLater()是在返回主事件循环后才销毁
// 小方块的,为了在出现新的方块组时不发生碰撞,所以需要先从场景中移除小方块
m_scene->removeItem(item);
onePiece *piece = (onePiece*) item;
piece->deleteLater();
}
} /**清空满行的小方块后向下移动上面的小方块
* @brief Panel::slot_moveBox
*/
void Panel::slot_moveBox()
{
// 从位置最靠上的满行开始
for (int i = m_rowList.count(); i > 0; i--)
{
foreach (QGraphicsItem *item, m_scene->items(34, 34, 206, m_rowList.at(i-1) - 32, Qt::ContainsItemShape,Qt::AscendingOrder)) {
item->moveBy(0, 20);
}
}
// 更新分数
updateScore(m_rowList.count());
// 将满行列表清空为0
m_rowList.clear(); // 等所有行下移以后再出现新的方块组
m_currentBox->createBox(QPointF(135,55), m_nextBox->getCurrentBoxType());
// 清空并销毁提示方块组中的所有小方块
m_nextBox->clearBoxGroup(true);
m_nextBox->createBox(QPointF(290,55)); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362

http://blog.csdn.net/sxpsxp12/article/details/50607224

最新文章

  1. 【C#】ConcurrentBag&lt;T&gt; 方法
  2. django常见小问题收集(转)
  3. 【转】vim格式化C代码
  4. 【iCore3 双核心板】例程十九:USBD_MSC实验——虚拟U盘
  5. 使用Putty连接VirtualBox的Ubuntu
  6. 在struts2中整合ajax时出现Template /template/ajax/head.ftl not found错误时的处理方法
  7. 2012 PHP热门资料64个+经典源码50个——下载目录 :
  8. 基于FPGA的中值滤波算法实现
  9. linux dns子域授权 split分离解析 缓存dns服务器
  10. 完全关闭Hyper-v的方法
  11. Map集合中,关于取值和遍历的相关操作
  12. &lt;自动化测试方案_8&gt;第八章、手机端UI自动化测试
  13. Oracle 插入时间时 报错:ORA-01861: 文字与格式字符串不匹配 的解决办法
  14. 硬盘安装Linux(ubuntu,centos)
  15. centos6.5 yum安装postgresql9.3
  16. gulp的安装以及使用详解,除了详细还是详细
  17. mysql查询当前系统时间
  18. iOS进阶指南试读之UI篇
  19. redash docker 运行
  20. JAVA URI URL 区别

热门文章

  1. SpringBoot项目优化和Jvm调优(楼主亲测,真实有效)
  2. iOS 使用贝塞尔曲线绘制路径
  3. Azure Messaging-ServiceBus Messaging
  4. JSON排序
  5. 10g RAC 采用service达到taf
  6. 如何更好的利用redis
  7. javascript 次序li
  8. redis在windows10上跑起来
  9. Boost智能指针-基础知识
  10. 注释为基础的SpringMVC