Qt之FlappyBird游戏开发

Qt之FlappyBird游戏开发Qt 之 FlappyBird 游戏开发 Qt 之 FlappyBird 游戏开发简述效果图代码主界面控制小鸟组件绘制游戏开始按钮管道组件绘制地面绘制结尾简述最近浏览网站的时候 忘记在哪里看的这个 FlappyBird 了 这个小游戏在之前小火了一段时间 今天用 QT 简单的实现了一把 然后在网上找了一些相关的切图 便进行了制作 难度不是很大 只是通过写这篇博客 能有点启发以及大家共同学习 效

Qt之FlappyBird游戏开发

简述

最近浏览网站的时候,忘记在哪里看的这个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("%1").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("%1").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(); }

结尾

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/223191.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午2:39
下一篇 2026年3月17日 下午2:39


相关推荐

  • java drm_DRM系统工作原理

    java drm_DRM系统工作原理一 系统工作原理 DRM 技术是一项加强对音频 视频数字化产品内容版权保护的技术 其基本的工作原理是将音频 视频等文件进行加密编码处理 再建立一个证书授权服务中心 当用户使用这些加密文件时 应用软件会根据其包含在头文件中的有关属性自动链接到相应的站点 证书授权服务中心 获取相应的证书 只有通过授权中心的验证并获得授权 才能使用这些音 视频等文件 从而严密有效的保护了这些数字多媒体产品的版权和使用权限

    2026年3月18日
    2
  • @Param注解的使用和解析「建议收藏」

    @Param注解的使用和解析「建议收藏」作用:用注解来简化xml配置的时候(比如Mybatis的Mapper.xml中的sql参数引入),@Param注解的作用是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中(一般通过#{}的方式,${}会有sql注入的问题)。实例说明:1,使用@Param注解  Mapper接口方法:publicintgetUsersDetail(@Param("u…

    2025年7月23日
    9
  • vue 全局变量

    vue 全局变量1 示例代码 include iostream usingnamespa intfunction inta intb 2 c 0 a b c 仅在函数 function 内有效 returna b c intmain intm n m n 仅在函数 main 内有效 cin gt gt m n function m cout lt iostream

    2026年3月19日
    2
  • 90后清华学霸,又融资35亿

    90后清华学霸,又融资35亿

    2026年3月12日
    1
  • 国外最流行的Bootstrap后台管理模板

    国外最流行的Bootstrap后台管理模板工欲善其事,必先利其器对于从事软件开发的您也一样,有一套熟悉的bootstrap后台ui框架让您的开发速度大幅度提升这是本人经常使用到的一些bootstrap后台框架推荐给大家第一名inspiniabootstrap演示地址http://cn.inspinia.cn效果图http://cn.inspinia.cnhttp://cn.inspinia.cn第二名…

    2022年4月25日
    48
  • 微信开发者工具报错,提示 未找到入口 app.json 文件

    微信开发者工具报错,提示 未找到入口 app.json 文件微信开发者工具报错,提示 未找到入口 app.json 文件

    2022年4月24日
    89

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号