基于Qt5图形视图框架的“俄罗斯方块”

Qt5 图形视图框架QGraphicsView

1、图形视图框架包含三大类:场景类(QGraphicsScene),视图类(QGraphicsView),图元类(QGraphicsItem);
2、对于有很多项的场景,使用轻量级的QGraphicsItem类作为数目众多的自定义项的基础最好,仅对数目较少的项使用QGraphicsObject
3、当一个项发生了变换(transformation),该项所有的子对象自动应用 该变换,递归应用到最深层次的子孙对象,
变换有(拖动,移动。。。。。),通过调用QGraphicsItem::setFlag(QGraphicsItem::ItemIngnoreTransformation)可以使子项忽略父项的变换,通常使用的标志还有可移动,选中,获得焦点等
4、通过把项设置为QGraphicsItemGroup的子项,可以将他们分组,创建项的集合。
5、图形视图类使用三种座标系统,但是实际应用中只是关心其中的两种。视图使用物理座标系统,场景使用在构造函数中传入的QRectF定义的逻辑座标系统。Qt自动进行场景座标到视图座标的映射,放置项时使用的是场景的座标。项的中心是在(0,0)点的逻辑座标系统,每个项的(0,0)点实际在该项场景中所在位置的中心(文本项除外,原点在项的左上角)。
6、图形项:QGraphicsItem因为有两个纯虚函数而不能实例化对象,这两个纯虚函数是boundingRect()和paint()
paint()函数必须重新实现来绘制项,boundingRect()函数在图形视图框架中为项提供一个边界矩形,用于冲突监测和保证项仅在QGraphicsView的视口(viewport)中可见时才重绘。如果要创建非矩形形状的自定义图形项,最好同时实现shape()方法,这个方法返回一个精确描述项的轮廓的QpainterPath,对于准确检测冲突和鼠标点击非常有用。
7、如果要自定义一个形状,最简单的是使用标准的QGraphicsItem的子类之一,比如QGraphicsPathItem和QGraphicsPolygonItem,如果有定制行为,可以重新实现保护事件的处理函数,如keyPressEvent()。如果只是想要自己绘制,可以从QGraphicsItem派生,重新实现boundingRect()和paint()和shape()方法。

俄罗斯方块的实现

俄罗斯方块的逻辑

这里写图片描述

小方块的类型

这里写图片描述

效果图

这里写图片描述
这里写图片描述

代码的实现

onePiece.h

#ifndef ONEPIECE_H
#define ONEPIECE_H

/************
 *一块方块的绘制
 *
 *
 ***************/

#include <QGraphicsObject>
#include <QColor>

class onePiece : public QGraphicsObject
{
public:
    onePiece(const QColor &brushColor = Qt::red);
    //为项提供一个外围的边界矩形
    virtual QRectF boundingRect() const;
    //QGraphicsView调用,在本地座标系统中绘制项
    virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
    //重新定义项的形状,默认调用boundingRect获取项的矩形形状轮廓
    virtual QPainterPath shape() const;
private:
    QColor m_brushColor;

};

#endif // ONEPIECE_H

onepiece.c

#include "onepiece.h"
#include <QPainter>
#include "enumHeader.h"

/****
 * 为了避免同一个方块组内小方块发生碰撞,
 * 小方块的大小实际为19.5*19.5,但是小方块加上笔刷的宽度后为20*20
 * 这样看起来是四个小方块连在一起的
 * **/

onePiece::onePiece(const QColor &brushColor)
    :m_brushColor(brushColor)
{
}

QRectF onePiece::boundingRect() const
{
    qreal penWidth = PEN_WIDTH;
    return QRectF(-(PIECE_DIAMETER - penWidth)/2, -(PIECE_DIAMETER - penWidth)/2,
                  PIECE_DIAMETER - penWidth, PIECE_DIAMETER - penWidth);
}

void onePiece::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    //背景贴图
    painter->drawPixmap(-PIECE_DIAMETER/2,-PIECE_DIAMETER/2,PIECE_DIAMETER,PIECE_DIAMETER,QPixmap(":/piece/Image/piece/box.png"));
    painter->setBrush(m_brushColor);
    //将方块的边界的颜色进行透明化
    QColor penColor = m_brushColor;
    // 将颜色的透明度减小
    penColor.setAlpha(200);
    painter->setPen(penColor);
    //使用当前的笔刷和笔画矩形框
    painter->drawRect(-PIECE_DIAMETER/2, -PIECE_DIAMETER/2, PIECE_DIAMETER, PIECE_DIAMETER);
}

QPainterPath onePiece::shape() const
{
    QPainterPath path;
    //去除笔刷的宽度,这样同一个方块组的方块就不会被检测出碰撞的情况
    path.addRect(-(PIECE_DIAMETER-PEN_WIDTH)/2,-(PIECE_DIAMETER-PEN_WIDTH)/2,PIECE_DIAMETER-PEN_WIDTH,PIECE_DIAMETER-PEN_WIDTH);
    return path;
}

pieceBox.h

#ifndef PIECEBOX_H
#define PIECEBOX_H

/********
 * 方块组
 * 4*4
 *
 *
 * ******/

#include <QGraphicsItemGroup>
#include <QKeyEvent>
#include <QTimer>
#include "enumHeader.h"
#include <QTransform>
#include "onepiece.h"
#include <QGraphicsItem>

class pieceBox :public QObject,public QGraphicsItemGroup
{
    Q_OBJECT
public:
    pieceBox();
    //颜色表
    static QColor colorTable[7];
    //绘制方块组的边框矩形
    virtual QRectF boundingRect() const;
    //是否发生碰撞
    bool isCollding() const;
    //获取当前的方块类型
    BoxType getCurrentBoxType() const;
    //创建方块组
    void createBox(const QPointF &point = QPointF(0,0),
                   BoxType currentBoxType = RandomShape);
    //消除方块组
    void clearBoxGroup(const bool &isClear = false);

protected:
    virtual void keyPressEvent(QKeyEvent * event);

signals:
    void signal_needNewBox();
    void signal_gameOver();
public slots:
    void slot_moveOneStep();
    void slot_startTimer(int timeSec);
    void slot_stopTimer();
private:
    QTimer *m_Timer;
    BoxType m_currentBoxType;
    QTransform m_oldTransform;
    QList<onePiece *> m_pieceBoxList;   //存放新方块组的四个方块
};

#endif // PIECEBOX_H

pieceBox.c

#include "piecebox.h"
#include "enumHeader.h"
#include <QList>
#include <QDebug>

QColor pieceBox::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)};

pieceBox::pieceBox()
{
    m_pieceBoxList.clear();
    //使得方块组支持键盘操作
    setFlags(QGraphicsItem::ItemIsFocusable);
    //保存矩阵的原状态,使得可以还原矩阵
    m_oldTransform = transform();
    m_Timer = new QTimer(this);
    connect(m_Timer,SIGNAL(timeout()),this,SLOT(slot_moveOneStep()));
    m_currentBoxType = RandomShape;
}

//绘制方块组的边框矩形
QRectF pieceBox::boundingRect() const
{
    qreal penWidth = PEN_WIDTH;
    return QRectF(-(PIECE_DIAMETER*2 - penWidth) / 2, -(PIECE_DIAMETER*2 - penWidth) / 2,
                  PIECE_DIAMETER*4-penWidth, PIECE_DIAMETER*4-penWidth);
}

bool pieceBox::isCollding() const
{
    //依次检测方块组中的每个方块的碰撞
    foreach (onePiece *piece, m_pieceBoxList) {
//        qDebug() << "colliding number:" << piece->collidingItems().count();
        //获取与该方块碰撞的方块的个数
        if(piece->collidingItems().count() > 1)
        {
            return true;
        }
    }
    return false;
}

BoxType pieceBox::getCurrentBoxType() const
{
    return m_currentBoxType;
}

void pieceBox::createBox(const QPointF &point, BoxType currentBoxType)
{
    int boxType = currentBoxType;
    if(boxType == RandomShape)
    {
        boxType = qrand() % 7;
    }
    //设置该方块组的颜色
    QColor boxColor = colorTable[boxType];
    //准备四个小方块

    //恢复方块组的变换矩阵,因为之前的方块组的变换会导致变换矩阵的位置发生变换,
    //防止新的方块组因为旧的方块组变换异常
    setTransform(m_oldTransform);
    setRotation(0);
    resetTransform();

    m_pieceBoxList.clear();
    for(int i = 0;i < 4;i++)
    {
        onePiece *piece = new onePiece(boxColor);
        m_pieceBoxList.append(piece);
        //将小方块添加到方块组中
        addToGroup(piece);
    }
    //设置方块组的形状
    switch (boxType) {
    case IShape:
        m_currentBoxType = IShape;
        m_pieceBoxList.at(0)->setPos(-30,-10);
        m_pieceBoxList.at(1)->setPos(-10,-10);
        m_pieceBoxList.at(2)->setPos(10,-10);
        m_pieceBoxList.at(3)->setPos(30,-10);
        break;
    case JShape:
        m_currentBoxType = JShape;
        m_pieceBoxList.at(0)->setPos(10,-10);
        m_pieceBoxList.at(1)->setPos(10,10);
        m_pieceBoxList.at(2)->setPos(10,30);
        m_pieceBoxList.at(3)->setPos(-10,30);
        break;
    case LShape:
        m_currentBoxType = LShape;
        m_pieceBoxList.at(0)->setPos(-10,-10);
        m_pieceBoxList.at(1)->setPos(-10,10);
        m_pieceBoxList.at(2)->setPos(10,30);
        m_pieceBoxList.at(3)->setPos(-10,30);
        break;
    case OShape:
        m_currentBoxType = OShape;
         m_pieceBoxList.at(0)->setPos(-10,-10);
         m_pieceBoxList.at(1)->setPos(10,-10);
         m_pieceBoxList.at(2)->setPos(-10,10);
         m_pieceBoxList.at(3)->setPos(10,10);
        break;
    case SShape:
        m_currentBoxType = SShape;
         m_pieceBoxList.at(0)->setPos(30,-10);
         m_pieceBoxList.at(1)->setPos(10,-10);
         m_pieceBoxList.at(2)->setPos(10,10);
         m_pieceBoxList.at(3)->setPos(-10,10);
        break;
    case TShape:
        m_currentBoxType = TShape;
         m_pieceBoxList.at(0)->setPos(-10,-10);
         m_pieceBoxList.at(1)->setPos(10,-10);
         m_pieceBoxList.at(2)->setPos(30,-10);
         m_pieceBoxList.at(3)->setPos(10,10);
        break;
    case Zshape:
        m_currentBoxType = Zshape;
         m_pieceBoxList.at(0)->setPos(-10,-10);
         m_pieceBoxList.at(1)->setPos(10,-10);
         m_pieceBoxList.at(2)->setPos(10,10);
         m_pieceBoxList.at(3)->setPos(30,10);
        break;
    default:
        break;
    }
    //设置方块组的位置
    setPos(point);
    //检测是否发生碰撞,发生碰撞,游戏结束
    if(isCollding())
    {
        slot_stopTimer();
        emit signal_gameOver();
    }
}

//删除方块组中的小方块到情景中
void pieceBox::clearBoxGroup(const bool &isClear)
{
    QList<QGraphicsItem *> itemList = childItems();
    foreach (QGraphicsItem *piece, itemList) {
        removeFromGroup(piece);
//        qDebug() << "clear box group" << isClear;
        if(isClear)
        {
            //销毁小方块
           ((onePiece *)piece)->deleteLater();
        }
    }
    m_pieceBoxList.clear();
}

void pieceBox::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_Down:
        moveBy(0,20);
        //检测是否碰撞
        if(isCollding())
        {
           moveBy(0,-20);
           clearBoxGroup();
           //需要新的方块
           emit signal_needNewBox();
        }
        break;
    case Qt::Key_Left:
        moveBy(-20,0);
        if(isCollding())
        {
            moveBy(20,0);
        }

        break;
    case Qt::Key_Right:
        moveBy(20,0);
        if(isCollding())
        {
            moveBy(-20,0);
        }
        break;
    case Qt::Key_Up:
        setRotation(rotation()+90);
        if(isCollding())
        {
            setRotation(rotation()-90);
        }
        break;
    case Qt::Key_Space: //快速下落
        moveBy(0,20);
        while (!isCollding()) {
            moveBy(0,20);
        }
        moveBy(0,-20);
        clearBoxGroup();
        //需要新的方块
        emit signal_needNewBox();
        break;
    default:
        break;
    }
}

void pieceBox::slot_moveOneStep()
{
    moveBy(0,20);
//    qDebug() << "move one step";
    if(isCollding())
    {
        moveBy(0,-20);
        // 将小方块从方块组中移除到场景中
        clearBoxGroup();
        //需要新的方块
        emit signal_needNewBox();
    }
}

void pieceBox::slot_startTimer(int timeSec)
{
    m_Timer->start(timeSec);
}

void pieceBox::slot_stopTimer()
{
    m_Timer->stop();
}

**界面类**panel.h

#ifndef PANEL_H
#define PANEL_H

#include <QWidget>
#include <QPalette>
#include <QPixmap>
#include <QGraphicsScene>
#include <QGraphicsView>
#include "piecebox.h"
#include "onepiece.h"
#include <QGraphicsLineItem>
#include <QMediaPlayer>

namespace Ui {
class Panel;
}

class Panel : public QWidget
{
    Q_OBJECT

public:
    explicit Panel(QWidget *parent = 0);
    ~Panel();
    void setbackground(const int &Lv);
    void initControlWidget();
    void initGraphicsViewWidget();

    /**游戏控制项***/
    void startGame();
    void pauseGame();
    void restartGame();
    void stopGame();

    void updateScore(const int fullRows = 0);

private slots:
    void on_pbt_startGame_clicked();

    void on_pbt_pauseGame_clicked();

    void on_pbt_restart_clicked();

    void on_pbt_stopGame_clicked();

    void slot_clearFullRows();

    void slot_gameOver();

    void slot_moveBox();
private:
    Ui::Panel *ui;
    QPalette m_Palette;
    QPixmap m_pixmap;
    int m_currentLv;
    int m_currentLVSpeed;
    bool m_isPauseGame;
    bool m_isGameOver;
    QGraphicsScene *m_scene;
    //四条边界线
    QGraphicsLineItem *m_topLine;
    QGraphicsLineItem *m_leftLine;
    QGraphicsLineItem *m_buttomLine;
    QGraphicsLineItem *m_rightLine;

    pieceBox *m_currentBox;
    pieceBox *m_nextBox;

    QList<int> m_rowList;
    QMediaPlayer *m_mediaPlayer;
};

#endif // PANEL_H

panel.c

#include "panel.h"
#include "ui_panel.h"
#include "enumHeader.h"
#include <QDebug>
#include <QGraphicsBlurEffect>
#include <QPropertyAnimation>
#include <QMessageBox>
#include <QMediaContent>

Panel::Panel(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Panel)
{
    ui->setupUi(this);
    m_isPauseGame = false;
    m_isGameOver = false;

    m_mediaPlayer = new QMediaPlayer;
    m_mediaPlayer->setMedia(QUrl::fromLocalFile(QString("clearRow.mp3")));
    m_mediaPlayer->setVolume(100);
    //设置背景
    setbackground(LV0);
    initControlWidget();

    initGraphicsViewWidget();
}

Panel::~Panel()
{
    delete ui;
}

void Panel::setbackground(const int &Lv)
{
    setAutoFillBackground(true);
    switch (Lv) {
    case LV0:
        m_currentLv = LV0;
        m_currentLVSpeed = LV0_SPEED;
        ui->label_gameLevel->setText("俄罗斯方块");
        m_pixmap.load(":/background/Image/background/background.png");
        break;
    case LV1:
        m_currentLv = LV1;
        m_currentLVSpeed = LV1_SPEED;
        ui->label_gameLevel->setText("第一关");
        m_pixmap.load(":/background/Image/background/background01.png");
        break;
    case LV2:
        m_currentLv = LV2;
        m_currentLVSpeed = LV2_SPEED;
        ui->label_gameLevel->setText("第二关");
        m_pixmap.load(":/background/Image/background/background02.png");
        break;
    case LV3:
        m_currentLv = LV3;
        m_currentLVSpeed = LV3_SPEED;
        ui->label_gameLevel->setText("第三关");
        m_pixmap.load(":/background/Image/background/background03.png");
        break;
    case LV4:
        m_currentLv = LV4;
        m_currentLVSpeed = LV4_SPEED;
        ui->label_gameLevel->setText("第四关");
        m_pixmap.load(":/background/Image/background/background04.png");
        break;
    case LV5:
        m_currentLv = LV5;
        m_currentLVSpeed = LV5_SPEED;
        ui->label_gameLevel->setText("第五关");
        m_pixmap.load(":/background/Image/background/background05.png");
        break;
    default:
        break;
    }
    m_Palette.setBrush(QPalette::Window, QBrush(m_pixmap.scaled(size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
    setPalette(m_Palette);
}

void Panel::initControlWidget()
{
    switch (m_currentLv) {
    case LV0:
        ui->pbt_startGame->setEnabled(true);
        ui->pbt_pauseGame->setEnabled(false);
        ui->pbt_restart->setEnabled(false);
        ui->pbt_stopGame->setEnabled(false);
        break;
    case LV1:
    case LV2:
    case LV3:
    case LV4:
    case LV5:
        ui->pbt_startGame->setEnabled(false);
        ui->pbt_pauseGame->setEnabled(true);
        ui->pbt_restart->setEnabled(true);
        ui->pbt_stopGame->setEnabled(true);
        break;
    default:
        break;
    }
}

void Panel::initGraphicsViewWidget()
{
    //使用抗锯齿渲染
    ui->GraphicsView->setRenderHint(QPainter::Antialiasing);
    //设置缓冲背景,加速渲染
    ui->GraphicsView->setCacheMode(QGraphicsView::CacheBackground);

    m_scene = new QGraphicsScene(this);
    m_scene->setSceneRect(30,30,310,410);
    ui->GraphicsView->setScene(m_scene);

    //方块可移动的四条线
    //向外扩展3像素,这样可以使方块组到达边界的时候再移动就会发生碰撞
    m_topLine = m_scene->addLine(32,32,238,32);
    m_leftLine = m_scene->addLine(32,32,32,438);
    m_buttomLine = m_scene->addLine(32,438,238,438);
    m_rightLine = m_scene->addLine(238,32,238,438);

    m_topLine->setPen(QPen(QColor(255,255,255)));
    m_leftLine->setPen(QPen(QColor(255,255,255)));
    m_buttomLine->setPen(QPen(QColor(255,255,255)));
    m_rightLine->setPen(QPen(QColor(255,255,255)));

    m_currentBox = new pieceBox;
    m_nextBox = new pieceBox;
    connect(m_currentBox,SIGNAL(signal_needNewBox()),this,SLOT(slot_clearFullRows()));
    connect(m_currentBox,SIGNAL(signal_gameOver()),this,SLOT(slot_gameOver()));
    m_scene->addItem(m_currentBox);
    m_scene->addItem(m_nextBox);
}

void Panel::startGame()
{
    m_currentBox->createBox(QPointF(135,55));
    m_nextBox->createBox(QPointF(290,55));
    //将键盘焦点给当前的方块组
    m_currentBox->setFocus();
    m_currentBox->slot_startTimer(m_currentLVSpeed);
}

void Panel::updateScore(const int fullRows)
{
    int score = ui->LCDNum_Score->value() + fullRows*ROWSCORE;

    ui->LCDNum_Score->display(score);
    if(score < 1000)         //第一关
    {

    }else if(score < 2000)  //第二关
    {
        setbackground(LV2);
        initControlWidget();
        m_currentBox->slot_stopTimer();
        m_currentBox->slot_startTimer(m_currentLVSpeed);
    }else if(score < 4000)  //第三关
    {
        setbackground(LV3);
        initControlWidget();
        m_currentBox->slot_stopTimer();
        m_currentBox->slot_startTimer(m_currentLVSpeed);
    }else if(score < 8000) //第四关
    {
        setbackground(LV4);
        initControlWidget();
        m_currentBox->slot_stopTimer();
        m_currentBox->slot_startTimer(m_currentLVSpeed);
    }else if(score < 16000)  //第五关
    {
        setbackground(LV5);
        initControlWidget();
        m_currentBox->slot_stopTimer();
        m_currentBox->slot_startTimer(m_currentLVSpeed);
    }else   //从第一关重新开始
    {
        setbackground(LV1);
        initControlWidget();
        m_currentBox->slot_stopTimer();
        m_currentBox->slot_startTimer(m_currentLVSpeed);
    }
}

/**
 *  开始游戏
 * @brief Panel::on_pbt_startGame_clicked
 */

void Panel::on_pbt_startGame_clicked()
{
    m_isGameOver = false;
    if(m_isPauseGame)
    {
        ui->pbt_startGame->setEnabled(false);
        m_isPauseGame = false;
        m_currentBox->slot_startTimer(m_currentLVSpeed);
        return;
    }
    //默认等级为LV1
    setbackground(LV1);
    initControlWidget();

    startGame();
}

/**
 *  暂停游戏
 * @brief Panel::on_pbt_pauseGame_clicked
 */
void Panel::on_pbt_pauseGame_clicked()
{
    if(m_isPauseGame)
    {
        return;
    }
    m_isPauseGame = true;
    m_currentBox->slot_stopTimer();
    ui->pbt_startGame->setEnabled(true);
    QMessageBox::information(this,"提示","暂停游戏!",QMessageBox::Yes);
}

/**
 * 重新开始游戏
 * @brief Panel::on_pbt_restart_clicked
 */
void Panel::on_pbt_restart_clicked()
{

    m_currentBox->slot_stopTimer();
    m_currentBox->clearBoxGroup();
    m_nextBox->clearBoxGroup(true);
    //先将当前的小正方形组移出游戏框,防止下面的清除item将该方块组清除了
    m_currentBox->setPos(290,55);
    ui->LCDNum_Score->display(0);

    //清空视图中所有的小方块
    foreach (QGraphicsItem *item, m_scene->items(34, 34, 204, 404, Qt::ContainsItemShape,Qt::AscendingOrder)) {
        // 先从场景中移除小方块,因为使用deleteLater()是在返回主事件循环后才销毁
        // 小方块的,为了在出现新的方块组时不发生碰撞,所以需要先从场景中移除小方块
        m_scene->removeItem(item);
        onePiece *piece = (onePiece*) item;
        piece->deleteLater();
    }
    m_isPauseGame = false;
    on_pbt_startGame_clicked();
}

/**
 *  停止游戏
 * @brief Panel::on_pbt_stopGame_clicked
 */
void Panel::on_pbt_stopGame_clicked()
{
    m_currentBox->slot_stopTimer();
    slot_gameOver();
}

/**清除满行的小方块
 * @brief Panel::slot_clearFullRows
 */
void Panel::slot_clearFullRows()
{
    m_rowList.clear();
    //获取比一行方格多行的所有小方块,不包含最高的一行
    for(int i = 414;i > 35; i-=20)
    {
        //返回可视区域(202*22)内所有的完全可视的item
        QList<QGraphicsItem *> itemList = m_scene->items(34,i,204,22,Qt::ContainsItemShape,Qt::AscendingOrder);
//        qDebug() << "可是区域内的item数:" << itemList.count();
        //已满
        if(itemList.count() == 10)
        {
            //遍历列表删除小方块
            foreach (QGraphicsItem *item, itemList) {
                onePiece *piece = (onePiece *)item;

                //模糊效果,先放大再缩小
                QGraphicsBlurEffect *blurEffect = new QGraphicsBlurEffect;
                piece->setGraphicsEffect(blurEffect);
                QPropertyAnimation *animation = new QPropertyAnimation(piece,"scale");
                animation->setDuration(250);
                animation->setEasingCurve(QEasingCurve::OutBounce);
                animation->setStartValue(4);
                animation->setEndValue(0.25);
                animation->start(QAbstractAnimation::DeleteWhenStopped);
                connect(animation,SIGNAL(finished()),piece,SLOT(deleteLater()));
            }
            m_mediaPlayer->play();
            //记录满行的行地址
            m_rowList.append(i);
        }
    }
//    qDebug() << "满行的行数:" << m_rowList.size();
    //存在满行,删除后将上面的方块下移
    if(!m_rowList.isEmpty())
    {
        //等待所有的小正方形都销毁后再将上方的小正方形向下移动
       QTimer::singleShot(300,this,SLOT(slot_moveBox()));
    }else   //直接创建新的方块组
    {
        m_currentBox->createBox(QPointF(135,55), m_nextBox->getCurrentBoxType());
        // 清空并销毁提示方块组中的所有小方块
        m_nextBox->clearBoxGroup(true);
        if(!m_isGameOver)
        {
            m_nextBox->createBox(QPointF(290,55));
        }
    }
}

void Panel::slot_gameOver()
{
//    qDebug() << "game over";
    m_isGameOver = true;
    QMessageBox::information(this,"提示",QString("您的游戏得分为%1!").arg(ui->LCDNum_Score->value()),QMessageBox::Yes);
    ui->LCDNum_Score->display(0);
    m_currentBox->clearFocus();

    setbackground(LV0);
    initControlWidget();
    m_isPauseGame = false;
    //初始化界面
    m_currentBox->clearBoxGroup(true);
    m_nextBox->clearBoxGroup(true);
    //先将当前的小正方形组移出游戏框,防止下面的清除item将该方块组清除了
    m_currentBox->setPos(290,55);
    //清空视图中所有的小方块
    foreach (QGraphicsItem *item, m_scene->items(34, 34, 204, 404, Qt::ContainsItemShape,Qt::AscendingOrder)) {
        // 先从场景中移除小方块,因为使用deleteLater()是在返回主事件循环后才销毁
        // 小方块的,为了在出现新的方块组时不发生碰撞,所以需要先从场景中移除小方块
        m_scene->removeItem(item);
        onePiece *piece = (onePiece*) item;
        piece->deleteLater();
    }
}

/**清空满行的小方块后向下移动上面的小方块
 * @brief Panel::slot_moveBox
 */
void Panel::slot_moveBox()
{
    // 从位置最靠上的满行开始
    for (int i = m_rowList.count(); i > 0; i--)
    {
        foreach (QGraphicsItem *item, m_scene->items(34, 34, 206, m_rowList.at(i-1) - 32, Qt::ContainsItemShape,Qt::AscendingOrder)) {
            item->moveBy(0, 20);
        }
    }
    // 更新分数
    updateScore(m_rowList.count());
    // 将满行列表清空为0
    m_rowList.clear();

    // 等所有行下移以后再出现新的方块组
    m_currentBox->createBox(QPointF(135,55), m_nextBox->getCurrentBoxType());
    // 清空并销毁提示方块组中的所有小方块
    m_nextBox->clearBoxGroup(true);
    m_nextBox->createBox(QPointF(290,55));

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章