首页 > 编程 > C > 正文

Qt实现Flappy Bird游戏

2020-01-26 13:35:36
字体:
来源:转载
供稿:网友

简述

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

效果图

代码

主界面控制

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

小鸟组件绘制

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

游戏开始按钮

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

管道组件绘制

#define PIPE_WIDTH 60GraphicsPipeitem::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(); });}

地面绘制

#define ROAD_ITEM_HEIGHT 38GraphicsRoadItem::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();}

结尾

全部代码,都在上面了,希望对大伙有所点启发和帮助,只为记录,只为分享! 愿所写能对你有所帮助。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选