Qt實現(xiàn)Flappy Bird游戲
簡述
最近瀏覽網(wǎng)站的時候,忘記在哪里看的這個FlappyBird了,這個小游戲在之前小火了一段時間。今天用QT簡單的實現(xiàn)了一把,然后在網(wǎng)上找了一些相關(guān)的切圖,便進(jìn)行了制作。難度不是很大,只是通過寫這篇博客,能有點啟發(fā)以及大家共同學(xué)習(xí)。
效果圖
代碼
主界面控制
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); //游戲狀態(tài)檢測,開啟定時器,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() { //檢測小鳥是否與地面和管道發(fā)生碰撞 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 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(); }); }
地面繪制
#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(); }
結(jié)尾
全部代碼,都在上面了,希望對大伙有所點啟發(fā)和幫助,只為記錄,只為分享! 愿所寫能對你有所幫助。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
您可能感興趣的文章
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計-用棧實現(xiàn)表達(dá)式求值的方法詳解
- 01-10使用OpenGL實現(xiàn)3D立體顯示的程序代碼
- 01-10求斐波那契(Fibonacci)數(shù)列通項的七種實現(xiàn)方法
- 01-10C語言 解決不用+、-、&#215;、&#247;數(shù)字運算符做加法
- 01-10使用C++實現(xiàn)全排列算法的方法詳解
- 01-10用C++實現(xiàn)DBSCAN聚類算法
- 01-10深入全排列算法及其實現(xiàn)方法
- 01-10全排列算法的非遞歸實現(xiàn)與遞歸實現(xiàn)的方法(C++)
- 01-10用C語言實現(xiàn)單鏈表的各種操作(一)
- 01-10用C語言實現(xiàn)單鏈表的各種操作(二)


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對數(shù)函數(shù)的表達(dá)式 c語言中對
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機閱讀
- 01-10delphi制作wav文件的方法
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 04-02jquery與jsp,用jquery
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10C#中split用法實例總結(jié)