服务器之家

服务器之家 > 正文

Qt实现Flappy Bird游戏

时间:2021-07-15 15:29     来源/作者:ly305750665

简述

最近浏览网站的时候,忘记在哪里看的这个FlappyBird了,这个小游戏在之前小火了一段时间。今天用QT简单的实现了一把,然后在网上找了一些相关的切图,便进行了制作。难度不是很大,只是通过写这篇博客,能有点启发以及大家共同学习。

效果图

Qt实现Flappy Bird游戏

Qt实现Flappy Bird游戏

Qt实现Flappy Bird游戏

代码

主界面控制

?
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

标签:

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
2021德云社封箱演出完整版 2021年德云社封箱演出在线看
2021德云社封箱演出完整版 2021年德云社封箱演出在线看 2021-03-15
返回顶部