Qt 项目实战 | 俄罗斯方块

马肤
这是懒羊羊

Qt 项目实战 | 俄罗斯方块

  • Qt 项目实战 | 俄罗斯方块
    • 游戏架构
    • 实现游戏逻辑
      • 游戏流程
      • 实现基本游戏功能
        • 设计小方块
        • 设计方块组
        • 添加游戏场景
        • 添加主函数
        • 测试
          • 踩坑点1:rotate 失效
          • 踩坑点2:items 方法报错
          • 踩坑点3:setCodecForTr 失效
          • 踩坑点4:不要在中文路径下运行 Qt 项目
          • 踩坑点5:multiple definition of `qMain(int, char**)'
          • 测试效果
          • 游戏优化
            • 添加满行销毁动画
            • 添加游戏级别设置
            • 添加游戏控制按钮和面板
              • 踩坑点1:error: no matching function for call to 'QGraphicsTextItem::QGraphicsTextItem(int, QGraphicsScene*&)'
              • 踩坑点2:error: no matching function for call to 'QGraphicsScene::items(int, int, int, int, Qt::ItemSelectionMode)'
              • 添加背景音乐和音效
              • 添加程序启动画面
              • 运行效果
              • 资源下载

                官方博客:https://www.yafeilinux.com/

                Qt开源社区:https://www.qter.org/

                参考书:《Qt 及 Qt Quick 开发实战精解》

                Qt 项目实战 | 俄罗斯方块

                开发环境:Qt Creator 4.6.2 Based on Qt 5.9.6

                Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第1张

                游戏架构

                在这个游戏中,有一个区域用来摆放方块,该区域宽为10,高为20,以小正方形为单位,它可以看作是拥有20行10列的一个网格。标准的游戏中一共有7种方块,它们都是由4个小正方形组成的规则图形,依据形状分别用字母I、J、L、O、S、T和Z来命名。

                这里使用图形视图框架来实现整个游戏的设计。小正方形由OneBox来表示,它继承自QGraphicsObject类,之所以继承自这个类,是因为这样就可以使用信号和槽机制,话可以使用属性动画。小正方形就是一个宽和高都为20像素的正方形图形项。游戏中的方块游戏由方块组BoxGroup类来实现,继承自QObject和QGraphicsItemGroup类,这样该类也可以使用信号和槽机制。方块组是一个宽和高都是80像素的图形项组,其中包含了4个小方块,通过设置小方块的位置来实现7种标准的方块图形。它们的形状和位置如下图,在BoxGroup类中实现了方块图形的创建、移动和碰撞检测。

                本项目由三个类构成:

                • OneBox 类:继承自 QGraphicsObject 类。表示小正方形,可以使用信号与槽机制和属性动画。
                • BoxGroup 类:继承自 QObject 类和 QGraphicsItemGroup 类。表示游戏中的方块图形,可以使用信号与槽机制,实现了方块图形的创建、移动和碰撞检测。
                • MyView 类:实现了游戏场景。

                  整个游戏场景宽800像素,高500像素。方块移动区域宽200像素,高400像素,纵向每20个像素被视作一行,共有20行;横行也是每20个像素视作一列,所以共有10列,该区域可以看作一个由20行10列20×20像素的方格组成的网格。方块组在方块移动区域的初始位置为上方正中间,但方块组的最上方一行小正方形在方块移动区域以外,这样可以保证方块组完全出现在移动区域的最上方,方块组每移动一次,就是移动一个方格的位置。场景还设置了下一个要出现方块的提示方块、游戏暂停等控制按钮和游戏分数级别的显示文本。

                  游戏场景示意图:

                  Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第2张

                  实现游戏逻辑

                  当游戏开始后,首先创建一个新的方块组,并将其添加到场景中的方块移动区域上方。然后进行碰撞检测,如果这时已经发生了碰撞,那么游戏结束;如果没有发生碰撞,就可以使用键盘的方向键对其进行旋转变形或者左右移动。当到达指定事件时方块组会自动下移一个方格,这时再次判断是否发生碰撞,如果发生了碰撞,先消除满行的方格,然后出现新的方块组,并继续进行整个流程。其中方程块的移动、旋转、碰撞检测等都在BoxGroup类中进行;游戏的开始、结束、出现新的方程组、消除满行等都在MyView类中进行。

                  游戏流程

                  游戏流程图:

                  Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第3张

                  七种方块图形:

                  Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第4张

                  方块组的左移、右移、下移和旋转都是先进行该操作,然后判断是否发生碰撞,比如发生了碰撞就再进行反向操作。比如,使用方向键左移方块组,那么就先将方块组左移一格,然后进行碰撞检测,看是否与边界线或者其他方块碰撞了,如果发生了碰撞,那么就再移过来,即右移一个。

                  方块组移动和旋转:

                  Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第5张

                  • 碰撞检测:对于方块组的碰撞检测,其实是使用方块组中的4个小方块来进行的,这样就不用再为每个方块图形都设置一个碰撞检测时使用的形状。要进行碰撞检测时,对每一个小方块都使用函数来获取与它们碰撞的图形项的数目,因为现在小方块在方块组中,所以应该只有方块组与它们碰撞了(由于我们对小方块的形状进行了设置,所以挨着的四个小方块相互间不会被检测出发生了碰撞),也就是说与它们碰撞的图形项数目应该不会大于1,如果有哪个小方块发现与它碰撞的图形项的数目大于1,那么说明已经发生了碰撞。

                  • 游戏结束:当一个新的方块组出现时,就立即对齐进行碰撞检测,如果它一出现就与其他方块发生了碰撞,说明游戏已经结束了,这时由方块组发射游戏结束信号。

                  • 消除满行:游戏开始后,每当出现一个新的方块以前,都判断游戏移动区域的每一行是否已经拥有10个小方块。如果有一行已经拥有了10个小方块,说明改行已满,那么就销毁该行的所有小方块,然后让该行上面的所有小方块都下移一格。

                    实现基本游戏功能

                    新建空的 Qt 项目,项目名 myGame。

                    myGame.pro 中新增代码:

                    QT += widgets
                    TARGET = myGame
                    

                    这也是个踩坑点,在这里提前说了。

                    添加资源文件,名称为 myImages,添加图片:

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第6张

                    设计小方块

                    新建 mybox.h,添加 OneBox 类的定义:

                    #ifndef MYBOX_H
                    #define MYBOX_H
                    #include 
                    #include 
                    // 小方块类
                    class OneBox : public QGraphicsObject
                    {
                    private:
                        QColor brushColor;
                    public:
                        OneBox(const QColor& color = Qt::red);
                        QRectF boundingRect() const;
                        void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget);
                        QPainterPath shape() const;
                    };
                    #endif  // MYBOX_H
                    

                    新建 mybox.cpp,添加 OneBox 类的实现代码:

                    #include "mybox.h"
                    #include 
                    OneBox::OneBox(const QColor& color) { brushColor = color; }
                    QRectF OneBox::boundingRect() const
                    {
                        qreal penWidth = 1;
                        return QRectF(-10 - penWidth / 2, -10 - penWidth / 2, 20 + penWidth, 20 + penWidth);
                    }
                    void OneBox::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
                    {
                        // 为小方块使用贴图
                        painter->drawPixmap(-10, -10, 20, 20, QPixmap(":/images/box.gif"));
                        painter->setBrush(brushColor);
                        QColor penColor = brushColor;
                        // 将颜色的透明度降低
                        penColor.setAlpha(20);
                        painter->setPen(penColor);
                        painter->drawRect(-10, -10, 20, 20);
                    }
                    QPainterPath OneBox::shape() const
                    {
                        QPainterPath path;
                        // 形状比边框矩形小 0.5 像素,这样方块组中的小方块才不会发生碰撞
                        path.addRect(-9.5, -9.5, 19, 19);
                        return path;
                    }
                    
                    设计方块组

                    在 mybox.h 中添加头文件:

                    #include 
                    

                    再添加 BoxGroup 类的定义:

                    // 方块组类
                    class BoxGroup : public QObject, public QGraphicsItemGroup
                    {
                        Q_OBJECT
                    private:
                        BoxShape currentShape;
                        QTransform oldTransform;
                        QTimer* timer;
                    protected:
                        void keyPressEvent(QKeyEvent* event);
                    public:
                        enum BoxShape
                        {
                            IShape,
                            JShape,
                            LShape,
                            OShape,
                            SShape,
                            TShape,
                            ZShape,
                            RandomShape
                        };
                        BoxGroup();
                        QRectF boundingRect() const;
                        bool isColliding();
                        void createBox(const QPointF& point = QPointF(0, 0), BoxShape shape = RandomShape);
                        void clearBoxGroup(bool destroyBox = false);
                        BoxShape getCurrentShape() { return currentShape; }
                    signals:
                        void needNewBox();
                        void gameFinished();
                    public slots:
                        void moveOneStep();
                        void startTimer(int interval);
                        void stopTimer();
                    };
                    

                    到 mybox.cpp 中添加头文件:

                    #include 
                    #include 
                    

                    添加 BoxGroup 类的实现代码:

                    // 方块组类
                    void BoxGroup::keyPressEvent(QKeyEvent* event)
                    {
                        switch (event->key())
                        {
                            case Qt::Key_Down:
                                moveBy(0, 20);
                                if (isColliding())
                                {
                                    moveBy(0, -20);
                                    // 将小方块从方块组中移除到场景中
                                    clearBoxGroup();
                                    // 需要显示新的方块
                                    emit needNewBox();
                                }
                                break;
                            case Qt::Key_Left:
                                moveBy(-20, 0);
                                if (isColliding())
                                    moveBy(20, 0);
                                break;
                            case Qt::Key_Right:
                                moveBy(20, 0);
                                if (isColliding())
                                    moveBy(-20, 0);
                                break;
                            case Qt::Key_Up:
                                rotate(90);
                                if (isColliding())
                                    rotate(-90);
                                break;
                            // 空格键实现坠落
                            case Qt::Key_Space:
                                moveBy(0, 20);
                                while (!isColliding())
                                {
                                    moveBy(0, 20);
                                }
                                moveBy(0, -20);
                                clearBoxGroup();
                                emit needNewBox();
                                break;
                        }
                    }
                    BoxGroup::BoxGroup()
                    {
                        setFlags(QGraphicsItem::ItemIsFocusable);
                        // 保存变换矩阵,当 BoxGroup 进行旋转后,可以使用它来进行恢复
                        oldTransform = transform();
                        timer = new QTimer(this);
                        connect(timer, SIGNAL(timeout()), this, SLOT(moveOneStep()));
                        currentShape = RandomShape;
                    }
                    QRectF BoxGroup::boundingRect() const
                    {
                        qreal penWidth = 1;
                        return QRectF(-40 - penWidth / 2, -40 - penWidth / 2, 80 + penWidth, 80 + penWidth);
                    }
                    // 碰撞检测
                    bool BoxGroup::isColliding()
                    {
                        QList itemList = childItems();
                        QGraphicsItem* item;
                        // 使用方块组中的每一个小方块来进行判断
                        foreach (item, itemList)
                        {
                            if (item->collidingItems().count() > 1)
                                return true;
                        }
                        return false;
                    }
                    // 创建方块
                    void BoxGroup::createBox(const QPointF& point, BoxShape shape)
                    {
                        static const QColor colorTable[7] =
                        {
                            QColor(200, 0, 0, 100),
                            QColor(255, 200, 0, 100),
                            QColor(0, 0, 200, 100),
                            QColor(0, 200, 0, 100),
                            QColor(0, 200, 255, 100),
                            QColor(200, 0, 255, 100),
                            QColor(150, 100, 100, 100)
                        };
                        int shapeID = shape;
                        if (shape == RandomShape)
                        {
                            // 产生 0-6 之间的随机数
                            shapeID = qrand() % 7;
                        }
                        QColor color = colorTable[shapeID];
                        QList list;
                        //恢复方块组的变换矩阵
                        setTransform(oldTransform);
                        for (int i = 0; i setPos(-10, -10);
                                list.at(2)->setPos(10, -10);
                                list.at(3)->setPos(30, -10);
                                break;
                            case JShape:
                                currentShape = JShape;
                                list.at(0)->setPos(10, -10);
                                list.at(1)->setPos(10, 10);
                                list.at(2)->setPos(-10, 30);
                                list.at(3)->setPos(10, 30);
                                break;
                            case LShape:
                                currentShape = LShape;
                                list.at(0)->setPos(-10, -10);
                                list.at(1)->setPos(-10, 10);
                                list.at(2)->setPos(-10, 30);
                                list.at(3)->setPos(10, 30);
                                break;
                            case OShape:
                                currentShape = OShape;
                                list.at(0)->setPos(-10, -10);
                                list.at(1)->setPos(10, -10);
                                list.at(2)->setPos(-10, 10);
                                list.at(3)->setPos(10, 10);
                                break;
                            case SShape:
                                currentShape = SShape;
                                list.at(0)->setPos(10, -10);
                                list.at(1)->setPos(30, -10);
                                list.at(2)->setPos(-10, 10);
                                list.at(3)->setPos(10, 10);
                                break;
                            case TShape:
                                currentShape = TShape;
                                list.at(0)->setPos(-10, -10);
                                list.at(1)->setPos(10, -10);
                                list.at(2)->setPos(30, -10);
                                list.at(3)->setPos(10, 10);
                                break;
                            case ZShape:
                                currentShape = ZShape;
                                list.at(0)->setPos(-10, -10);
                                list.at(1)->setPos(10, -10);
                                list.at(2)->setPos(10, 10);
                                list.at(3)->setPos(30, 10);
                                break;
                            default: break;
                        }
                        // 设置位置
                        setPos(point);
                        // 如果开始就发生碰撞,说明已经结束游戏
                        if (isColliding())
                        {
                            stopTimer();
                            emit gameFinished();
                        }
                    }
                    // 删除方块组中的所有小方块
                    void BoxGroup::clearBoxGroup(bool destroyBox)
                    {
                        QList itemList = childItems();
                        QGraphicsItem* item;
                        foreach (item, itemList)
                        {
                            removeFromGroup(item);
                            if (destroyBox)
                            {
                                OneBox* box = (OneBox*)item;
                                box->deleteLater();
                            }
                        }
                    }
                    // 向下移动一步
                    void BoxGroup::moveOneStep()
                    {
                        moveBy(0, 20);
                        if (isColliding())
                        {
                            moveBy(0, -20);
                            // 将小方块从方块组中移除到场景中
                            clearBoxGroup();
                            emit needNewBox();
                        }
                    }
                    // 开启定时器
                    void BoxGroup::startTimer(int interval) { timer->start(interval); }
                    // 停止定时器
                    void BoxGroup::stopTimer() { timer->stop(); }
                    
                    添加游戏场景

                    新建一个 C++ 类,类名为 MyView,基类为 GraphicsView,继承自 QWidget:

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第7张

                    更改 myview.h:

                    #ifndef MYVIEW_H
                    #define MYVIEW_H
                    #include 
                    #include 
                    class BoxGroup;
                    class MyView : public GraphicsView
                    {
                    private:
                        BoxGroup* boxGroup;
                        BoxGroup* nextBoxGroup;
                        QGraphicsLineItem* topLine;
                        QGraphicsLineItem* bottomLine;
                        QGraphicsLineItem* leftLine;
                        QGraphicsLineItem* rightLine;
                        qreal gameSpeed;
                        QList rows;
                        void initView();
                        void initGame();
                        void updateScore(const int fullRowNum = 0);
                    public:
                        explicit MyView(QWidget* parent = 0);
                    public slots:
                        void startGame();
                        void clearFullRows();
                        void moveBox();
                        void gameOver();
                    };
                    #endif  // MYVIEW_H
                    

                    更改 myview.cpp:

                    #include "myview.h"
                    #include 
                    #include "mybox.h"
                    // 游戏的初始速度
                    static const qreal INITSPEED = 500;
                    // 初始化游戏界面
                    void MyView::initView()
                    {
                        // 使用抗锯齿渲染
                        setRenderHint(QPainter::Antialiasing);
                        // 设置缓存背景,这样可以加快渲染速度
                        setCacheMode(CacheBackground);
                        setWindowTitle(tr("MyBox方块游戏"));
                        setWindowIcon(QIcon(":/images/icon.png"));
                        setMinimumSize(810, 510);
                        setMaximumSize(810, 510);
                        // 设置场景
                        QGraphicsScene* scene = new QGraphicsScene;
                        scene->setSceneRect(5, 5, 800, 500);
                        scene->setBackgroundBrush(QPixmap(":/images/background.png"));
                        setScene(scene);
                        // 方块可移动区域的四条边界线
                        topLine = scene->addLine(197, 47, 403, 47);
                        bottomLine = scene->addLine(197, 453, 403, 453);
                        leftLine = scene->addLine(197, 47, 197, 453);
                        rightLine = scene->addLine(403, 47, 403, 453);
                        // 当前方块组和提示方块组
                        boxGroup = new BoxGroup;
                        connect(boxGroup, SIGNAL(needNewBox()), this, SLOT(clearFullRows()));
                        connect(boxGroup, SIGNAL(gameFinished()), this, SLOT(gameOver()));
                        scene->addItem(boxGroup);
                        nextBoxGroup = new BoxGroup;
                        scene->addItem(nextBoxGroup);
                        startGame();
                    }
                    // 初始化游戏
                    void MyView::initGame()
                    {
                        boxGroup->createBox(QPointF(300, 70));
                        boxGroup->setFocus();
                        boxGroup->startTimer(INITSPEED);
                        gameSpeed = INITSPEED;
                        nextBoxGroup->createBox(QPointF(500, 70));
                    }
                    // 更新分数
                    void MyView::updateScore(const int fullRowNum) {}
                    MyView::MyView(QWidget* parent) : QGraphicsView(parent) { initView(); }
                    // 开始游戏
                    void MyView::startGame() { initGame(); }
                    // 清空满行
                    void MyView::clearFullRows()
                    {
                        // 获取比一行方格较大的矩形中包含的所有小方块
                        for (int y = 429; y > 50; y -= 20)
                        {
                            QList list = scene()->items(199, y, 202, 22, Qt::ContainsItemShape);
                            // 如果该行已满
                            if (list.count() == 10)
                            {
                                foreach (QGraphicsItem* item, list)
                                {
                                    OneBox* box = (OneBox*)item;
                                    box->deleteLater();
                                }
                                // 保存满行的位置
                                rows  0)
                        {
                            // 如果有满行,下移满行上面的各行再出现新的方块组
                            moveBox();
                        }
                        else  // 如果没有满行,则直接出现新的方块组
                        {
                            boxGroup->createBox(QPointF(300, 70), nextBoxGroup->getCurrentShape());
                            // 清空并销毁提示方块组中的所有小方块
                            nextBoxGroup->clearBoxGroup(true);
                            nextBoxGroup->createBox(QPointF(500, 70));
                        }
                    }
                    // 下移满行上面的所有小方块
                    void MyView::moveBox()
                    {
                        // 从位置最靠上的满行开始
                        for (int i = rows.count(); i > 0; i--)
                        {
                            int row = rows.at(i - 1);
                            foreach (QGraphicsItem* item, scene()->items(199, 49, 202, row - 47, Qt::ContainsItemShape))
                            {
                                item->moveBy(0, 20);
                            }
                        }
                        // 更新分数
                        updateScore(rows.count());
                        // 将满行列表清空为 0
                        rows.clear();
                        // 等所有行下移以后再出现新的方块组
                        boxGroup->createBox(QPointF(300, 70), nextBoxGroup->getCurrentShape());
                        nextBoxGroup->clearBoxGroup(true);
                        nextBoxGroup->createBox(QPointF(500, 70));
                    }
                    // 游戏结束
                    void MyView::gameOver() {}
                    
                    添加主函数

                    新建 main.cpp,添加代码:

                    #include 
                    #include 
                    #include 
                    #include "myview.h"
                    int main(int argc, char* argv[])
                    {
                        QApplication app(argc, argv);
                        QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
                        // 设置随机数的初始值
                        qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
                        MyView view;
                        view.show();
                        return app.exec();
                    }
                    

                    测试

                    运行程序。

                    果不其然的报错了。

                    主要是一些 Qt4 和 Qt5 的差别带来的问题。

                    踩坑点1:rotate 失效

                    函数 void BoxGroup::keyPressEvent(QKeyEvent* event) 原代码:

                    void BoxGroup::keyPressEvent(QKeyEvent *event)
                    {
                        switch (event->key())
                        {
                        case Qt::Key_Down :
                            moveBy(0, 20);
                            if (isColliding()) {
                                moveBy(0, -20);
                                // 将小方块从方块组中移除到场景中
                                clearBoxGroup();
                                // 需要显示新的方块
                                emit needNewBox();
                            }
                            break;
                        case Qt::Key_Left :
                            moveBy(-20, 0);
                            if (isColliding())
                                moveBy(20, 0);
                            break;
                        case Qt::Key_Right :
                            moveBy(20, 0);
                            if (isColliding())
                                moveBy(-20, 0);
                            break;
                        case Qt::Key_Up :
                            rotate(90);
                            if(isColliding())
                                rotate(-90);
                            break;
                        // 空格键实现坠落
                        case Qt::Key_Space :
                            moveBy(0, 20);
                            while (!isColliding()) {
                                moveBy(0, 20);
                            }
                            moveBy(0, -20);
                            clearBoxGroup();
                            emit needNewBox();
                            break;
                        }
                    }
                    

                    其中的 rotate 函数失效。

                    在 Qt5 中,QGraphicsItem::rotate 已经不再使用,而是使用 setRotation。

                    修改为:

                    void BoxGroup::keyPressEvent(QKeyEvent* event)
                    {
                        qreal oldRotate;
                        switch (event->key())
                        {
                            // 下移
                            case Qt::Key_Down:
                                moveBy(0, 20);
                                if (isColliding())
                                {
                                    moveBy(0, -20);
                                    // 将小方块从方块组中移除到场景中
                                    clearBoxGroup();
                                    // 需要显示新的方块
                                    emit needNewBox();
                                }
                                break;
                            // 左移
                            case Qt::Key_Left:
                                moveBy(-20, 0);
                                if (isColliding())
                                    moveBy(20, 0);
                                break;
                            // 右移
                            case Qt::Key_Right:
                                moveBy(20, 0);
                                if (isColliding())
                                    moveBy(-20, 0);
                                break;
                            // 旋转
                            case Qt::Key_Up:
                                // 在 Qt5 中,QGraphicsItem::rotate 已经不再使用,而是使用 setRotation
                                /* old code */
                                //    rotate(90);
                                //   if (isColliding())
                                //       rotate(-90);
                                //    break;
                                /* old code */
                                oldRotate = rotation();
                                if (oldRotate >= 360)
                                {
                                    oldRotate = 0;
                                }
                                setRotation(oldRotate + 90);
                                if (isColliding())
                                {
                                    setRotation(oldRotate - 90);
                                }
                                break;
                            // 空格键实现坠落
                            case Qt::Key_Space:
                                moveBy(0, 20);
                                while (!isColliding())
                                {
                                    moveBy(0, 20);
                                }
                                moveBy(0, -20);
                                clearBoxGroup();
                                emit needNewBox();
                                break;
                        }
                    }
                    

                    参考博客:Qt及Qt Quick开发实战精解项目二俄罗斯方块 rotate失效方法报错

                    踩坑点2:items 方法报错

                    在 void MyView::clearFullRows() 函数里有这样一行代码:

                    QList list = scene()->items(199, y, 202, 22, Qt::ContainsItemShape);
                    

                    报错信息:

                    myview.cpp:75:47: error: no matching member function for call to 'items'
                    qgraphicsscene.h:158:28: note: candidate function not viable: requires at most 4 arguments, but 5 were provided
                    qgraphicsscene.h:159:28: note: candidate function not viable: requires at most 4 arguments, but 5 were provided
                    qgraphicsscene.h:160:28: note: candidate function not viable: requires at most 4 arguments, but 5 were provided
                    qgraphicsscene.h:161:28: note: candidate function not viable: requires at most 4 arguments, but 5 were provided
                    qgraphicsscene.h:175:35: note: candidate function not viable: requires at least 6 arguments, but 5 were provided
                    qgraphicsscene.h:156:28: note: candidate function not viable: allows at most single argument 'order', but 5 arguments were provided
                    

                    大概意思是参数不匹配。

                    修改为:

                    QList list = scene()->items(199, y, 202, 22, Qt::ContainsItemShape, Qt::AscendingOrder);
                    

                    新增的一项 Qt::AscendingOrder 的意思是对 QList 的内容正序排序。

                    参考博客:Qt及Qt Quick开发实战精解项目二俄罗斯方块 items方法报错

                    踩坑点3:setCodecForTr 失效

                    在 main.cpp 中有这样一行代码:

                    QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
                    

                    这行代码主要解决 Qt 中文乱码的问题。

                    但是在 Qt5 中 setCodecForTr 函数已经失效了,我们改成:

                    // 解决 Qt 中文乱码问题
                    QTextCodec* codec = QTextCodec::codecForName("UTF-8");
                    QTextCodec::setCodecForLocale(codec);
                    QTextCodec::setCodecForCStrings(codec);
                    QTextCodec::setCodecForTr(codec);
                    

                    这个视个人电脑使用的编码决定。

                    踩坑点4:不要在中文路径下运行 Qt 项目

                    就是这样,喵~

                    踩坑点5:multiple definition of `qMain(int, char**)’

                    报错信息:

                    error: multiple definition of `qMain(int, char**)'
                    

                    这是在 pro 文件中出的问题,频繁的添加以及移除文件,导致 HEADERS 以及 SOURCES 中会重复添加。

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第8张

                    这里 main.cpp 重复了,删掉一个即可。

                    测试效果

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第9张

                    游戏优化

                    添加满行销毁动画

                    在 myview.cpp 中添加头文件:

                    #include 
                    #include 
                    #include 
                    

                    修改 clearFullRows() 函数:

                    void MyView::clearFullRows()
                    {
                        // 获取比一行方格较大的矩形中包含的所有小方块
                        for (int y = 429; y > 50; y -= 20)
                        {
                            // QList list = scene()->items(199, y, 202, 22, Qt::ContainsItemShape);
                            QList list = scene()->items(199, y, 202, 22, Qt::ContainsItemShape, Qt::AscendingOrder);
                            // 如果该行已满
                            if (list.count() == 10)
                            {
                                foreach (QGraphicsItem* item, list)
                                {
                                    OneBox* box = (OneBox*)item;
                                    // box->deleteLater();
                                    QGraphicsBlurEffect* blurEffect = new QGraphicsBlurEffect;
                                    box->setGraphicsEffect(blurEffect);
                                    QPropertyAnimation* animation = new QPropertyAnimation(box, "scale");
                                    animation->setEasingCurve(QEasingCurve::OutBounce);
                                    animation->setDuration(250);
                                    animation->setStartValue(4);
                                    animation->setEndValue(0.25);
                                    animation->start(QAbstractAnimation::DeleteWhenStopped);
                                    connect(animation, SIGNAL(finished()), box, SLOT(deleteLater()));
                                }
                                // 保存满行的位置
                                rows  0)
                        {
                            // moveBox();
                            QTimer::singleShot(400, this, SLOT(moveBox()));
                        }
                        else  // 如果没有满行,则直接出现新的方块组
                        {
                            boxGroup->createBox(QPointF(300, 70), nextBoxGroup->getCurrentShape());
                            // 清空并销毁提示方块组中的所有小方块
                            nextBoxGroup->clearBoxGroup(true);
                            nextBoxGroup->createBox(QPointF(500, 70));
                        }
                    }
                    

                    为小方块设置模糊效果,为小方块添加先放大再缩小的属性动画。

                    使用了只执行一次的定时器,其目的是等待所有小方块都销毁后再移动满行上面的小方块。

                    添加游戏级别设置

                    在 myview.h 的 private 中添加两个变量:

                    QGraphicsTextItem* gameScoreText;
                    QGraphicsTextItem* gameLevelText;
                    

                    在myview.cpp 的 initView() 函数中调用 startGame() 槽前添加代码:

                    // 得分文本
                    gameScoreText = new QGraphicsTextItem(0, scene);
                    gameScoreText->setFont(QFont("Times", 20, QFont::Bold));
                    gameScoreText->setPos(650, 350);
                    // 级别文本
                    gameLevelText = new QGraphicsTextItem(0, scene);
                    gameLevelText->setFont(QFont("Times", 30, QFont::Bold));
                    gameLevelText->setPos(20, 150);
                    

                    注意,上面是书中的代码,是错的,修改为下面代码:

                    // 得分文本
                    gameScoreText = new QGraphicsTextItem();
                    gameScoreText->setFont(QFont("Times", 20, QFont::Bold));
                    gameScoreText->setPos(650, 350);
                    // 级别文本
                    gameLevelText = new QGraphicsTextItem();
                    gameLevelText->setFont(QFont("Times", 30, QFont::Bold));
                    gameLevelText->setPos(20, 150);
                    scene->addItem(gameLevelText);
                    scene->addItem(gameScoreText);
                    

                    再到initGame() 中添加代码:

                    scene()->setBackgroundBrush(QPixmap(":/images/background01.png"));
                    gameScoreText->setHtml(tr("0"));
                    gameLevelText->setHtml(tr("第

                    幕"));

                    最后到 updateScore() 函数中添加代码:

                    // 更新分数
                    void MyView::updateScore(const int fullRowNum)
                    {
                        int score = fullRowNum * 100;
                        int currentScore = gameScoreText->toPlainText().toInt();
                        currentScore += score;
                        // 显示当前分数
                        gameScoreText->setHtml(tr("%1").arg(currentScore));
                        // 判断级别
                        if (currentScore setHtml(tr("第

                    幕")); scene()->setBackgroundBrush(QPixmap(":/images/background02.png")); gameSpeed = 300; boxGroup->stopTimer(); boxGroup->startTimer(gameSpeed); } else { // 添加下一个级别的设置 } }

                    测试:

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第10张

                    添加游戏控制按钮和面板

                    在 myview.h 添加私有槽:

                    void restartGame();
                    void finishGame();
                    void pauseGame();
                    void returnGame();
                    

                    在 myview.h 添加私有变量:

                    QGraphicsWidget *maskWidget; // 遮罩面板
                    // 各种按钮
                    QGraphicsWidget *startButton;
                    QGraphicsWidget *finishButton;
                    QGraphicsWidget *restartButton;
                    QGraphicsWidget *pauseButton;
                    QGraphicsWidget *optionButton;
                    QGraphicsWidget *returnButton;
                    QGraphicsWidget *helpButton;
                    QGraphicsWidget *exitButton;
                    QGraphicsWidget *showMenuButton;
                    // 各种文本
                    QGraphicsTextItem *gameWelcomeText;
                    QGraphicsTextItem *gamePausedText;
                    QGraphicsTextItem *gameOverText;
                    

                    在 myview.cpp 添加头文件:

                    #include 
                    #include 
                    #include 
                    #include 
                    #include 
                    

                    在 initGame() 函数中,删除代码:

                    startGame();
                    

                    添加代码:

                    /*****************下面是2-4中添加的代码,部分代码在书中省略了*************/
                    // 设置初始为隐藏状态
                    topLine->hide();
                    bottomLine->hide();
                    leftLine->hide();
                    rightLine->hide();
                    gameScoreText->hide();
                    gameLevelText->hide();
                    // 黑色遮罩
                    QWidget *mask = new QWidget;
                    mask->setAutoFillBackground(true);
                    mask->setPalette(QPalette(QColor(0, 0, 0, 80)));
                    mask->resize(900, 600);
                    maskWidget = scene->addWidget(mask);
                    maskWidget->setPos(-50, -50);
                    // 设置其Z值为1,这样可以处于Z值为0的图形项上面
                    maskWidget->setZValue(1);
                    // 选项面板
                    QWidget *option = new QWidget;
                    QPushButton *optionCloseButton = new QPushButton(tr("关   闭"), option);
                    QPalette palette;
                    palette.setColor(QPalette::ButtonText, Qt::black);
                    optionCloseButton->setPalette(palette);
                    optionCloseButton->move(120, 300);
                    connect(optionCloseButton, SIGNAL(clicked()), option, SLOT(hide()));
                    option->setAutoFillBackground(true);
                    option->setPalette(QPalette(QColor(0, 0, 0, 180)));
                    option->resize(300, 400);
                    QGraphicsWidget *optionWidget = scene->addWidget(option);
                    optionWidget->setPos(250, 50);
                    optionWidget->setZValue(3);
                    optionWidget->hide();
                    // 帮助面板
                    QWidget *help = new QWidget;
                    QPushButton *helpCloseButton = new QPushButton(tr("关   闭"), help);
                    helpCloseButton->setPalette(palette);
                    helpCloseButton->move(120, 300);
                    connect(helpCloseButton, SIGNAL(clicked()), help, SLOT(hide()));
                    help->setAutoFillBackground(true);
                    help->setPalette(QPalette(QColor(0, 0, 0, 180)));
                    help->resize(300, 400);
                    QGraphicsWidget *helpWidget = scene->addWidget(help);
                    helpWidget->setPos(250, 50);
                    helpWidget->setZValue(3);
                    helpWidget->hide();
                    QLabel *helpLabel = new QLabel(help);
                    helpLabel->setText(tr("

                    yafeilinux作品" "
                    www.yafeilinux.com

                    ")); helpLabel->setAlignment(Qt::AlignCenter); helpLabel->move(30, 150); // 游戏欢迎文本 gameWelcomeText = new QGraphicsTextItem(0, scene); gameWelcomeText->setHtml(tr("MyBox方块游戏")); gameWelcomeText->setFont(QFont("Times", 30, QFont::Bold)); gameWelcomeText->setPos(250, 100); gameWelcomeText->setZValue(2); // 游戏暂停文本 gamePausedText = new QGraphicsTextItem(0, scene); gamePausedText->setHtml(tr("游戏暂停中!")); gamePausedText->setFont(QFont("Times", 30, QFont::Bold)); gamePausedText->setPos(300, 100); gamePausedText->setZValue(2); gamePausedText->hide(); // 游戏结束文本 gameOverText = new QGraphicsTextItem(0, scene); gameOverText->setHtml(tr("游戏结束!")); gameOverText->setFont(QFont("Times", 30, QFont::Bold)); gameOverText->setPos(320, 100); gameOverText->setZValue(2); gameOverText->hide(); // 游戏中使用的按钮 QPushButton *button1 = new QPushButton(tr("开 始")); QPushButton *button2 = new QPushButton(tr("选 项")); QPushButton *button3 = new QPushButton(tr("帮 助")); QPushButton *button4 = new QPushButton(tr("退 出")); QPushButton *button5 = new QPushButton(tr("重新开始")); QPushButton *button6 = new QPushButton(tr("暂 停")); QPushButton *button7 = new QPushButton(tr("主 菜 单")); QPushButton *button8 = new QPushButton(tr("返回游戏")); QPushButton *button9 = new QPushButton(tr("结束游戏")); connect(button1, SIGNAL(clicked()), this, SLOT(startGame())); connect(button2, SIGNAL(clicked()), option, SLOT(show())); connect(button3, SIGNAL(clicked()), help, SLOT(show())); connect(button4, SIGNAL(clicked()), qApp, SLOT(quit())); connect(button5, SIGNAL(clicked()), this, SLOT(restartGame())); connect(button6, SIGNAL(clicked()), this, SLOT(pauseGame())); connect(button7, SIGNAL(clicked()), this, SLOT(finishGame())); connect(button8, SIGNAL(clicked()), this, SLOT(returnGame())); connect(button9, SIGNAL(clicked()), this, SLOT(finishGame())); startButton = scene->addWidget(button1); optionButton = scene->addWidget(button2); helpButton = scene->addWidget(button3); exitButton = scene->addWidget(button4); restartButton = scene->addWidget(button5); pauseButton = scene->addWidget(button6); showMenuButton = scene->addWidget(button7); returnButton = scene->addWidget(button8); finishButton = scene->addWidget(button9); startButton->setPos(370, 200); optionButton->setPos(370, 250); helpButton->setPos(370, 300); exitButton->setPos(370, 350); restartButton->setPos(600, 150); pauseButton->setPos(600, 200); showMenuButton->setPos(600, 250); returnButton->setPos(370, 200); finishButton->setPos(370, 250); startButton->setZValue(2); optionButton->setZValue(2); helpButton->setZValue(2); exitButton->setZValue(2); restartButton->setZValue(2); returnButton->setZValue(2); finishButton->setZValue(2); restartButton->hide(); finishButton->hide(); pauseButton->hide(); showMenuButton->hide(); returnButton->hide(); /*****************上面是2-4中添加的代码,部分代码在书中省略了*************/

                    在 startGame() 中调用 initGame() 函数前添加代码:

                    gameWelcomeText->hide();
                    startButton->hide();
                    optionButton->hide();
                    helpButton->hide();
                    exitButton->hide();
                    maskWidget->hide();
                    

                    在 initGame() 函数的最后添加代码:

                    restartButton->show();
                    pauseButton->show();
                    showMenuButton->show();
                    gameScoreText->show();
                    gameLevelText->show();
                    topLine->show();
                    bottomLine->show();
                    leftLine->show();
                    rightLine->show();
                    // 可能以前返回主菜单时隐藏了boxGroup
                    boxGroup->show();
                    

                    修改 gameOver() 槽:

                    // 游戏结束
                    void MyView::gameOver()
                    {
                        pauseButton->hide();
                        showMenuButton->hide();
                        maskWidget->show();
                        gameOverText->show();
                        restartButton->setPos(370, 200);
                        finishButton->show();
                    }
                    

                    添加其他槽:

                    // 重新开始游戏
                    void MyView::restartGame()
                    {
                        maskWidget->hide();
                        gameOverText->hide();
                        finishButton->hide();
                        restartButton->setPos(600, 150);
                        // 销毁提示方块组和当前方块移动区域中的所有小方块
                        nextBoxGroup->clearBoxGroup(true);
                        boxGroup->clearBoxGroup();
                        boxGroup->hide();
                        foreach (QGraphicsItem* item, scene()->items(199, 49, 202, 402, Qt::ContainsItemShape, Qt::AscendingOrder))
                        {
                            // 先从场景中移除小方块,因为使用deleteLater()是在返回主事件循环后才销毁
                            // 小方块的,为了在出现新的方块组时不发生碰撞,所以需要先从场景中移除小方块
                            scene()->removeItem(item);
                            OneBox* box = (OneBox*)item;
                            box->deleteLater();
                        }
                        initGame();
                    }
                    // 结束当前游戏
                    void MyView::finishGame()
                    {
                        gameOverText->hide();
                        finishButton->hide();
                        restartButton->setPos(600, 150);
                        restartButton->hide();
                        pauseButton->hide();
                        showMenuButton->hide();
                        gameScoreText->hide();
                        gameLevelText->hide();
                        topLine->hide();
                        bottomLine->hide();
                        leftLine->hide();
                        rightLine->hide();
                        nextBoxGroup->clearBoxGroup(true);
                        boxGroup->clearBoxGroup();
                        boxGroup->hide();
                        foreach (QGraphicsItem* item, scene()->items(199, 49, 202, 402, Qt::ContainsItemShape))
                        {
                            OneBox* box = (OneBox*)item;
                            box->deleteLater();
                        }
                        // 可能是在进行游戏时按下“主菜单”按钮
                        maskWidget->show();
                        gameWelcomeText->show();
                        startButton->show();
                        optionButton->show();
                        helpButton->show();
                        exitButton->show();
                        scene()->setBackgroundBrush(QPixmap(":/images/background.png"));
                    }
                    // 暂停游戏
                    void MyView::pauseGame()
                    {
                        boxGroup->stopTimer();
                        restartButton->hide();
                        pauseButton->hide();
                        showMenuButton->hide();
                        maskWidget->show();
                        gamePausedText->show();
                        returnButton->show();
                    }
                    // 返回游戏,处于暂停状态时
                    void MyView::returnGame()
                    {
                        returnButton->hide();
                        gamePausedText->hide();
                        maskWidget->hide();
                        restartButton->show();
                        pauseButton->show();
                        showMenuButton->show();
                        boxGroup->startTimer(gameSpeed);
                    }
                    
                    踩坑点1:error: no matching function for call to ‘QGraphicsTextItem::QGraphicsTextItem(int, QGraphicsScene*&)’

                    报错信息:

                    error: no matching function for call to 'QGraphicsTextItem::QGraphicsTextItem(int, QGraphicsScene*&)'
                         gameWelcomeText = new QGraphicsTextItem(0, scene);
                    
                      ^
                    

                    将下面代码:

                    // 游戏欢迎文本
                    gameWelcomeText = new QGraphicsTextItem(0, scene);
                    gameWelcomeText->setHtml(tr("MyBox方块游戏"));
                    gameWelcomeText->setFont(QFont("Times", 30, QFont::Bold));
                    gameWelcomeText->setPos(250, 100);
                    gameWelcomeText->setZValue(2);
                    // 游戏暂停文本
                    gamePausedText = new QGraphicsTextItem(0, scene);
                    gamePausedText->setHtml(tr("游戏暂停中!"));
                    gamePausedText->setFont(QFont("Times", 30, QFont::Bold));
                    gamePausedText->setPos(300, 100);
                    gamePausedText->setZValue(2);
                    gamePausedText->hide();
                    // 游戏结束文本
                    gameOverText = new QGraphicsTextItem(0, scene);
                    gameOverText->setHtml(tr("游戏结束!"));
                    gameOverText->setFont(QFont("Times", 30, QFont::Bold));
                    gameOverText->setPos(320, 100);
                    gameOverText->setZValue(2);
                    gameOverText->hide();
                    

                    修改为:

                    // 游戏欢迎文本
                    gameWelcomeText = new QGraphicsTextItem();
                    gameWelcomeText->setHtml(tr("MyBox方块游戏"));
                    gameWelcomeText->setFont(QFont("Times", 30, QFont::Bold));
                    gameWelcomeText->setPos(250, 100);
                    gameWelcomeText->setZValue(2);
                    // 游戏暂停文本
                    gamePausedText = new QGraphicsTextItem();
                    gamePausedText->setHtml(tr("游戏暂停中!"));
                    gamePausedText->setFont(QFont("Times", 30, QFont::Bold));
                    gamePausedText->setPos(300, 100);
                    gamePausedText->setZValue(2);
                    gamePausedText->hide();
                    // 游戏结束文本
                    gameOverText = new QGraphicsTextItem();
                    gameOverText->setHtml(tr("游戏结束!"));
                    gameOverText->setFont(QFont("Times", 30, QFont::Bold));
                    gameOverText->setPos(320, 100);
                    gameOverText->setZValue(2);
                    gameOverText->hide();
                    scene->addItem(gameWelcomeText);
                    scene->addItem(gamePausedText);
                    scene->addItem(gameOverText);
                    

                    为了进行游戏时总是当前方块组获得焦点,我们要重写视图的键盘按下事件处理函数。

                    myview.h 新增代码:

                    protected:
                        void keyPressEvent(QKeyEvent* event);
                    

                    然后到 myview.cpp 添加定义:

                    // 如果正在进行游戏,当键盘按下时总是方块组获得焦点
                    void MyView::keyPressEvent(QKeyEvent* event)
                    {
                        if (pauseButton->isVisible())
                            boxGroup->setFocus();
                        else
                            boxGroup->clearFocus();
                        QGraphicsView::keyPressEvent(event);
                    }
                    
                    踩坑点2:error: no matching function for call to ‘QGraphicsScene::items(int, int, int, int, Qt::ItemSelectionMode)’

                    报错信息:

                    error: no matching function for call to 'QGraphicsScene::items(int, int, int, int, Qt::ItemSelectionMode)'
                         foreach (QGraphicsItem* item, scene()->items(199, 49, 202, 402, Qt::ContainsItemShape))
                    

                    原因与之前的踩坑点2:items 方法报错相同。

                    错误代码:

                    foreach (QGraphicsItem *item, scene()->items(199, 49, 202, 402, Qt::ContainsItemShape))
                    {
                    	OneBox *box = (OneBox *)item;
                    	box->deleteLater();
                    }
                    

                    修改为:

                    foreach (QGraphicsItem *item, scene()->items(199, 49, 202, 402, Qt::ContainsItemShape, Qt::AscendingOrder))
                    {
                    	OneBox *box = (OneBox *)item;
                    	box->deleteLater();
                    }
                    

                    添加背景音乐和音效

                    在 myGame.pro 添加代码:

                    QT += phonon
                    

                    报错:

                    Project ERROR: Unknown module(s) in QT: phonon
                    

                    因为 Qt5 不支持 phonon,所以此部分省略。

                    安装 Qt 4.8.6:Qt 4.8.6 的下载与安装

                    注:实测发现,不用安装 Qt Creator 3.3.0 也能在原来的 Qt Creator 上编写项目,只需要改一下构建。

                    在 myview.h 添加头文件:

                    #include 
                    

                    添加槽声明:

                    void aboutToFinish();
                    

                    添加私有对象定义:

                    // 音乐部件
                    Phonon::MediaObject *backgroundMusic;
                    Phonon::MediaObject *clearRowSound;
                    

                    在 myview.cpp 添加代码:

                    // 声音文件路径
                    static const QString SOUNDPATH = "../myGame/sounds/";
                    

                    然后到 initView() 函数最后添加代码:

                    // 设置声音
                    backgroundMusic = new Phonon::MediaObject(this);
                    clearRowSound = new Phonon::MediaObject(this);
                    Phonon::AudioOutput *audio1 = new Phonon::AudioOutput(Phonon::MusicCategory, this);
                    Phonon::AudioOutput *audio2 = new Phonon::AudioOutput(Phonon::MusicCategory, this);
                    Phonon::createPath(backgroundMusic, audio1);
                    Phonon::createPath(clearRowSound, audio2);
                    // 设置音量控制部件,它们显示在选项面板上
                    Phonon::VolumeSlider *volume1 = new Phonon::VolumeSlider(audio1, option);
                    Phonon::VolumeSlider *volume2 = new Phonon::VolumeSlider(audio2, option);
                    QLabel *volumeLabel1 = new QLabel(tr("音乐:"), option);
                    QLabel *volumeLabel2 = new QLabel(tr("音效:"), option);
                    volume1->move(100, 100);
                    volume2->move(100, 200);
                    volumeLabel1->move(60, 105);
                    volumeLabel2->move(60, 205);
                    connect(backgroundMusic, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
                    // 因为播放完毕后会进入暂停状态,再调用play()将无法进行播放,需要在播放完毕后使其进入停止状态
                    connect(clearRowSound, SIGNAL(finished()), clearRowSound, SLOT(stop()));
                    backgroundMusic->setCurrentSource(Phonon::MediaSource(SOUNDPATH + "background.mp3"));
                    clearRowSound->setCurrentSource(Phonon::MediaSource(SOUNDPATH + "clearRow.mp3"));
                    backgroundMusic->play();
                    

                    在 initGame() 函数的最后添加代码:

                    backgroundMusic->setCurrentSource(Phonon::MediaSource(SOUNDPATH + "background01.mp3"));
                    backgroundMusic->play();
                    

                    在 finishGame() 函数的最后添加代码:

                    backgroundMusic->setCurrentSource(Phonon::MediaSource(SOUNDPATH + "background.mp3"));
                    backgroundMusic->play();
                    

                    修改 updateScore() 函数:

                    // 更新分数
                    void MyView::updateScore(const int fullRowNum)
                    {
                        int score = fullRowNum * 100;
                        int currentScore = gameScoreText->toPlainText().toInt();
                        currentScore += score;
                        // 显示当前分数
                        gameScoreText->setHtml(tr("%1").arg(currentScore));
                        // 判断级别
                        if (currentScore setHtml(tr("第

                    幕")); scene()->setBackgroundBrush(QPixmap(":/images/background02.png")); gameSpeed = 300; boxGroup->stopTimer(); boxGroup->startTimer(gameSpeed); if (QFileInfo(backgroundMusic->currentSource().fileName()).baseName() != "background02") { backgroundMusic->setCurrentSource(Phonon::MediaSource(SOUNDPATH + "background02.mp3")); backgroundMusic->play(); } } else { // 添加下一个级别的设置 } }

                    添加 aboutToFinish() 槽定义:

                    // 背景音乐将要播放完毕时继续重新播放
                    void MyView::aboutToFinish()
                    {
                        backgroundMusic->enqueue(backgroundMusic->currentSource());
                    }
                    

                    添加程序启动画面

                    在 main.cpp 中添加头文件:

                    #include 
                    

                    在主函数创建 view 对象前添加代码:

                    QPixmap pix(":/images/logo.png");
                    QSplashScreen splash(pix);
                    splash.resize(pix.size());
                    splash.show();
                    app.processEvents();
                    

                    在调用 show() 函数后添加代码:

                    splash.finish(&view);
                    

                    运行效果

                    运行程序,主界面出现前会在屏幕的中心出现启动画面:

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第11张

                    开始界面:

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第12张

                    点击“帮助”:

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第13张

                    点击选项:

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第14张

                    游戏界面:

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第15张

                    暂停:

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第16张

                    游戏结束:

                    Qt 项目实战 | 俄罗斯方块,在这里插入图片描述,词库加载错误:未能找到文件“C:\Users\Administrator\Desktop\火车头9.8破解版\Configuration\Dict_Stopwords.txt”。,操作,电脑,没有,第17张

                    资源下载

                    GitHub:UestcXiye/Tetris

                    CSDN:Qt 项目:俄罗斯方块.zip


文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

发表评论

快捷回复:表情:
评论列表 (暂无评论,0人围观)

还没有评论,来说两句吧...

目录[+]

取消
微信二维码
微信二维码
支付宝二维码