Qt实现Flappy Bird游戏

简述

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

}

结尾

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

以上是 Qt实现Flappy Bird游戏 的全部内容, 来源链接: utcz.com/z/328731.html

回到顶部