简述
最近浏览网站的时候,忘记在哪里看的这个FlappyBird了,这个小游戏在之前小火了一段时间。今天用QT简单的实现了一把,然后在网上找了一些相关的切图,便进行了制作。难度不是很大,只是通过写这篇博客,能有点启发以及大家共同学习。
效果图
代码
主界面控制
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
|
MainWindow::MainWindow(QWidget *parent)
: BasicWindow(parent)
, m_startGame( false )
{
ui.setupUi( this );
setAttribute(Qt::WA_TranslucentBackground);
initControl();
}
void MainWindow::initControl()
{
loadStyleSheet( "MainWindow" );
m_scene = new MainGraphicsScene( this , rect());
QGraphicsView* view = new QGraphicsView(m_scene, this );
view->setScene(m_scene);
view->setStyleSheet( "border:none; background:transparent;" );
view->setCacheMode(QGraphicsView::CacheBackground);
startWelcome();
}
void MainWindow::startWelcome()
{
//道路
GraphicsRoadItem *roadItem = new GraphicsRoadItem(m_scene);
//小鸟
m_bird = new FlappyBird(m_scene);
//管道
GraphicsPipeitem *pipeItem = new GraphicsPipeitem(m_scene);
//游戏状态检测,开启定时器,50ms检测一次
m_checkGameStatus = new QTimer( this );
connect(m_checkGameStatus, SIGNAL(timeout()), this , SLOT(onCheckGameStatus()));
//flappybird字母
static const int nLetters = 10;
static struct {
char const *pix;
qreal initX, initY;
qreal destX, destY;
} letterData[nLetters] = {
{ "F" , -1000, -1000, 150, 100 },
{ "L" , -800, -1000, 200, 100 },
{ "A" , -600, -1000, 250, 100 },
{ "P" , -400, -1000, 300, 100 },
{ "P" , 1000, 2000, 350, 100 },
{ "Y" , 800, 2000, 400, 100 },
{ "B" , 600, 2000, 260, 160 },
{ "I" , 400, 2000, 310, 160 },
{ "R" , 200, 2000, 360, 160 },
{ "D" , 0, 2000, 410, 160 } };
QSequentialAnimationGroup * lettersGroupMoving = new QSequentialAnimationGroup( this );
m_lettersGroupFading = new QParallelAnimationGroup( this );
for ( int i = 0; i < nLetters; ++i) {
QString& htmlText = QString( "<span style=\"font-family:'Berlin Sans FB';font-size:48px;font-weight:600;color:#194819;\">%1</span>" ).arg(letterData[i].pix);
QGraphicsTextItem *letter = new QGraphicsTextItem();
letter->setHtml(htmlText);
letter->setPos(letterData[i].initX, letterData[i].initY);
QPropertyAnimation *moveAnim = new QPropertyAnimation(letter, "pos" , lettersGroupMoving);
moveAnim->setEndValue(QPointF(letterData[i].destX, letterData[i].destY));
moveAnim->setDuration(200);
moveAnim->setEasingCurve(QEasingCurve::OutElastic);
lettersGroupMoving->addPause(50);
QPropertyAnimation *fadeAnim = new QPropertyAnimation(letter, "opacity" , m_lettersGroupFading);
fadeAnim->setDuration(1000);
fadeAnim->setEndValue(0);
fadeAnim->setEasingCurve(QEasingCurve::OutQuad);
m_scene->addItem(letter);
}
lettersGroupMoving->start(QAbstractAnimation::DeleteWhenStopped);
//游戏开始按钮
QPixmap&& pix = QPixmap( ":/FlappyBird/Resources/texture/startButton.png" ).scaled(QSize(160, 48), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
GraphicsButtonItem* btnItem = new GraphicsButtonItem(pix, m_scene);
btnItem->setPos(QPointF(220, 340));
QPropertyAnimation *fadeAnim = new QPropertyAnimation(btnItem, "opacity" , m_lettersGroupFading);
fadeAnim->setDuration(600);
fadeAnim->setEndValue(0);
fadeAnim->setEasingCurve(QEasingCurve::OutQuad);
connect(btnItem, SIGNAL(clicked()), this , SLOT(onStartBtnClicked()));
connect(fadeAnim, &QPropertyAnimation::finished, [ this ](){
m_startGame = true ;
m_checkGameStatus->start(50);
m_bird->flyLandfallAnimation();
});
}
void MainWindow::onCheckGameStatus()
{
//检测小鸟是否与地面和管道发生碰撞
if (m_bird->checkIsCollided())
{
GameOver();
}
}
void MainWindow::GameOver()
{
static const int nLetters = 8;
static struct {
char const *pix;
qreal initX, initY;
qreal destX, destY;
} letterData[nLetters] = {
{ "G" , -1000, -1000, 150, 100 },
{ "A" , -800, -1000, 200, 100 },
{ "M" , -600, -1000, 250, 100 },
{ "E" , -400, -1000, 300, 100 },
{ "O" , 600, 2000, 260, 160 },
{ "V" , 400, 2000, 310, 160 },
{ "E" , 200, 2000, 360, 160 },
{ "R" , 0, 2000, 410, 160 } };
QParallelAnimationGroup * lettersGroupMoving = new QParallelAnimationGroup( this );
for ( int i = 0; i < nLetters; ++i) {
QString& htmlText = QString( "<span style=\"font-family:'Berlin Sans FB';font-size:48px;font-weight:600;color:#194819;\">%1</span>" ).arg(letterData[i].pix);
QGraphicsTextItem *letter = new QGraphicsTextItem();
letter->setHtml(htmlText);
letter->setPos(letterData[i].initX, letterData[i].initY);
QPropertyAnimation *moveAnim = new QPropertyAnimation(letter, "pos" , lettersGroupMoving);
moveAnim->setEndValue(QPointF(letterData[i].destX, letterData[i].destY));
moveAnim->setDuration(200);
moveAnim->setEasingCurve(QEasingCurve::OutElastic);
m_scene->addItem(letter);
}
lettersGroupMoving->start(QAbstractAnimation::DeleteWhenStopped);
m_scene->removeItem(m_bird);
}
void MainWindow::onStartBtnClicked()
{
m_lettersGroupFading->start(QAbstractAnimation::DeleteWhenStopped);
}
void MainWindow::keyPressEvent(QKeyEvent *event)
{
if (m_startGame)
{
m_bird->keyPressEvent(event);
}
}
|
小鸟组件绘制
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
|
FlappyBird::FlappyBird(QGraphicsScene *scene): m_curflyStatus(0)
, m_IsLandFall( true )
, m_IsRaise( true )
{
scene->addItem( this );
m_scene = scene;
m_birdRefreashTime = new QTimer( this );
connect(m_birdRefreashTime, SIGNAL(timeout()), this , SLOT(onRefreashBird()));
m_birdRefreashTime->start(12);
m_flyAnimation = new QPropertyAnimation( this , "pos" );
}
void FlappyBird::onRefreashBird()
{
update();
}
QRectF FlappyBird::boundingRect() const
{
return QRectF(60, FLY_BIRD_SIZE * 5 , FLY_BIRD_SIZE, FLY_BIRD_SIZE);
}
void FlappyBird::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
painter->save();
if (m_curflyStatus < 10)
{
m_curflyStatus++;
painter->drawImage(boundingRect(), QImage( ":/FlappyBird/Resources/texture/bird1.png" ));
}
else if (m_curflyStatus < 20)
{
m_curflyStatus++;
painter->drawImage(boundingRect(), QImage( ":/FlappyBird/Resources/texture/bird2.png" ));
}
else if ( m_curflyStatus < 30)
{
m_curflyStatus++;
painter->drawImage(boundingRect(), QImage( ":/FlappyBird/Resources/texture/bird3.png" ));
}
else
{
m_curflyStatus = 0;
}
painter->restore();
}
void FlappyBird::flyRaiseAnimation()
{
if (m_IsRaise)
{
m_IsLandFall = false ;
m_IsRaise = false ;
m_flyAnimation->stop();
if (pos().y() > -180)
{
m_flyAnimation->setDuration(300);
m_flyAnimation->setEndValue(QPoint(pos().x(), pos().y() - FLY_BIRD_SIZE));
}
else
{
m_flyAnimation->setDuration(300);
m_flyAnimation->setEndValue(pos());
}
m_flyAnimation->setEasingCurve(QEasingCurve::OutQuad);
m_flyAnimation->start();
connect(m_flyAnimation, SIGNAL(finished()), this , SLOT(onFlyRaiseAnimationFinished()));
}
}
void FlappyBird::onFlyRaiseAnimationFinished()
{
m_flyAnimation->disconnect(SIGNAL(finished()));
m_IsRaise = true ;
m_IsLandFall = true ;
flyLandfallAnimation();
}
void FlappyBird::flyLandfallAnimation()
{
if (m_birdRefreashTime->isActive())
{
m_birdRefreashTime->stop();
}
if (m_IsLandFall)
{
m_flyAnimation->stop();
int fallHeight = m_scene->height() - pos().y();
int time = 1000 * fallHeight / m_scene->height();
m_flyAnimation->setDuration( time );
m_flyAnimation->setEndValue(QPoint(pos().x(), pos().y() + fallHeight));
m_flyAnimation->setEasingCurve(QEasingCurve::InQuad);
m_flyAnimation->start();
m_IsLandFall = false ;
}
}
bool FlappyBird::checkIsCollided()
{
if (!collidingItems().isEmpty())
return true ;
else
return false ;
}
void FlappyBird::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Space)
{
flyRaiseAnimation();
}
}
|
游戏开始按钮
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
|
GraphicsButtonItem::GraphicsButtonItem( const QPixmap &pixmap, QGraphicsScene *scene) : pix(pixmap)
{
scene->addItem( this );
setCursor(QCursor(Qt::PointingHandCursor));
}
void GraphicsButtonItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
emit clicked();
}
__super::mousePressEvent(event);
}
QSizeF GraphicsButtonItem::size() const
{
return pix.size();
}
QRectF GraphicsButtonItem::boundingRect() const
{
return QRectF(QPointF(0, 0), pix.size());
}
void GraphicsButtonItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
painter->drawPixmap(0, 0, pix);
}
|
管道组件绘制
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
|
#define PIPE_WIDTH 60
GraphicsPipeitem::GraphicsPipeitem(QGraphicsScene *scene)
{
m_scene = scene;
m_scene->addItem( this );
createPipeHeight();
startMove();
}
void GraphicsPipeitem::createPipeHeight()
{
m_upPipeHeight = qrand() % 100 + 80;
m_downPipeHeight = m_scene->height() - m_upPipeHeight - 178;
}
QRectF GraphicsPipeitem::boundingRect() const
{
return QRectF(m_scene->width(), 0, PIPE_WIDTH, m_scene->height());
}
QPainterPath GraphicsPipeitem::shape() const
{
QPainterPath path;
path.addRect(QRectF(m_scene->width(), 0, PIPE_WIDTH, m_upPipeHeight));
path.addRect(QRectF(m_scene->width(), m_upPipeHeight + 140, PIPE_WIDTH, m_downPipeHeight));
return path;
}
void GraphicsPipeitem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->save();
painter->drawImage(QRectF(m_scene->width(), 0, PIPE_WIDTH, m_upPipeHeight), QImage( ":/FlappyBird/Resources/texture/tubeup.png" ).scaled(PIPE_WIDTH, m_upPipeHeight));
painter->drawImage(QRectF(m_scene->width(), m_upPipeHeight + 140, PIPE_WIDTH, m_downPipeHeight), QImage( ":/FlappyBird/Resources/texture/tubedown.png" ).scaled(PIPE_WIDTH, m_downPipeHeight));
painter->restore();
}
void GraphicsPipeitem::startMove()
{
QPropertyAnimation* moveAnimation = new QPropertyAnimation( this , "pos" );
moveAnimation->setLoopCount(-1);
moveAnimation->setDuration(3000);
moveAnimation->setStartValue(QPoint(0, pos().y()));
moveAnimation->setEndValue(QPoint(-1 * m_scene->width() - PIPE_WIDTH, pos().y()));
moveAnimation->start();
connect(moveAnimation, &QPropertyAnimation::currentLoopChanged, [ this ]( int loopCount){
createPipeHeight();
});
}
|
地面绘制
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
|
#define ROAD_ITEM_HEIGHT 38
GraphicsRoadItem::GraphicsRoadItem(QGraphicsScene *scene) :m_scene(scene)
{
scene->addItem( this );
startMove();
}
QRectF GraphicsRoadItem::boundingRect() const
{
return QRectF(0, m_scene->height() - ROAD_ITEM_HEIGHT, m_scene->width() * 2, ROAD_ITEM_HEIGHT);
}
void GraphicsRoadItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
painter->drawImage(QRectF(0, m_scene->height() - ROAD_ITEM_HEIGHT, m_scene->width(), ROAD_ITEM_HEIGHT), QImage( ":/FlappyBird/Resources/texture/road.png" ));
painter->drawImage(QRectF(m_scene->width(), m_scene->height() - ROAD_ITEM_HEIGHT, m_scene->width(), ROAD_ITEM_HEIGHT), QImage( ":/FlappyBird/Resources/texture/road.png" ));
}
void GraphicsRoadItem::startMove()
{
QPropertyAnimation* moveAnimation = new QPropertyAnimation( this , "pos" );
moveAnimation->setLoopCount(-1);
moveAnimation->setDuration(6000);
moveAnimation->setStartValue(QPoint(0, pos().y()));
moveAnimation->setEndValue(QPoint(0 - m_scene->width(), pos().y()));
moveAnimation->setEasingCurve(QEasingCurve::Linear);
moveAnimation->start();
}
|
结尾
全部代码,都在上面了,希望对大伙有所点启发和帮助,只为记录,只为分享! 愿所写能对你有所帮助。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/ly305750665/article/details/79006378