Qt实现Flappy Bird游戏

2020-01-06 20:09:37刘景俊

简述

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

效果图

Qt,FlappyBird,游戏

Qt,FlappyBird,游戏

Qt,FlappyBird,游戏

代码

主界面控制


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);
 }
}