QT学习笔记--翻金币案例

1.主窗体基本设置

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //1.游戏主场景配置
    this->setFixedSize(320, 588);//设置大小
    this->setWindowTitle("翻金币");
    this->setWindowIcon(QIcon("://res//Coin0001.png"));
    //设置退出
    connect(ui->actionquit, &QAction::triggered, [=](){
        this->close();
    });
}

2.设置背景图片(需要重写paintEvent方法)

//2.设置背景图片
    QPainter painter(this);// 指定绘图设备为该主窗口
    QPixmap img;
    img.load("://res//PlayLevelSceneBg.png");
    painter.drawPixmap(0, 0, this->width(), this->height(), img);

3.设置标题(需要重写paintEvent方法)

 //3.加载标题
    img.load("://res//Title.png");
    //缩放图片
    painter.drawPixmap(10, 30, img.width()*0.5, img.height()*0.5, img);

4.创建开始按钮(需要自定义一个按钮类)

用QPixmap加载图片(load方法,返回值为bool类型,可用此判断是否加载成果)

下面这段代码是为了让图片以不规则图形显示

this->setStyleSheet("QPushButton{border:0px;}");

开始按钮创建完成后,需要对其定义事件,当对其进行点击操作后,应令图片向下向上来回弹跳一次。因此定义了两个动画 函数。

QT的动画操作需要利用QPropertyAnimation类

setDuration方法设置动画的间隔

setStartValue设置动画的起始位置

setEndValue设置动画的结束位置。

在zoom1中,结束位置为起始位置+20,意味着图片会向下走20个像素(QT中的(0,0)点在左上角),而zoom2应从(x,y+20)回到(x,y)处。

setEasingCurve设置弹跳曲线,具体用怎样的曲线可查阅帮助文档

这两个方法需要在主场景中定义事件来执行

void MyPushButton::zoom1()
{
    QPropertyAnimation *animation = new QPropertyAnimation(this,"geometry");
    animation->setDuration(200);//设置动画间隔
    animation->setStartValue(QVariant(QRect(this->x(), this->y(), this->width(), this->height())));
    animation->setEndValue(QVariant(QRect(this->x(), this->y()+20, this->width(), this->height())));
    animation->setEasingCurve(QEasingCurve::OutBounce);//设置弹跳曲线
    animation->start();//执行动画
}

void MyPushButton::zoom2()
{
    QPropertyAnimation *animation = new QPropertyAnimation(this,"geometry");
    animation->setDuration(200);//设置动画间隔
    animation->setStartValue(QVariant(QRect(this->x(), this->y()+20, this->width(), this->height())));
    animation->setEndValue(QVariant(QRect(this->x(), this->y(), this->width(), this->height())));
    animation->setEasingCurve(QEasingCurve::OutBounce);//设置弹跳曲线
    animation->start();//执行动画
}

由于不是所有的按钮都需要点击后执行按下的特效,因此该类的构造函数接收了两个图片(常态的图片路径和按下后的图片路径),若后者的路径为空则意味着不需要有按下特效。

若传入了两个路径,则需要在按下按钮后切换成另一个图片,在释放时切换回常态图片,以实现按下按钮的特效

自定义按钮整体代码如下:

#include "mypushbutton.h"
MyPushButton::MyPushButton(QString normal_path, QString press_path)
{
    QPixmap img;
    bool isok = img.load(normal_path);//加载图片
    if(!isok){
        qDebug()<<"加载失败";
    }
    this->setFixedSize(img.width(), img.height());
    this->setIcon(QIcon(img));
    this->setIconSize(QSize(this->width(), this->height()));
    this->setStyleSheet("QPushButton{border:0px;}");
    connect(this, &QPushButton::pressed, [=](){//按下时,若传入了按下的图片,则显示
        if(press_path!=""){
            QPixmap img;
            bool isok = img.load(press_path);
            if(!isok){
                qDebug()<<"加载失败";
            }
            this->setIcon(QIcon(img));
        }
    });
    connect(this, &QPushButton::released, [=](){//松开时应还原为normal图片
        QPixmap img;
        bool isok = img.load(normal_path);
        if(!isok){
            qDebug()<<"加载失败";
        }
        this->setFixedSize(img.width(), img.height());
        this->setIcon(QIcon(img));
    });
}

void MyPushButton::zoom1()
{
    QPropertyAnimation *animation = new QPropertyAnimation(this,"geometry");
    animation->setDuration(200);//设置动画间隔
    animation->setStartValue(QVariant(QRect(this->x(), this->y(), this->width(), this->height())));
    animation->setEndValue(QVariant(QRect(this->x(), this->y()+20, this->width(), this->height())));
    animation->setEasingCurve(QEasingCurve::OutBounce);//设置弹跳曲线
    animation->start();//执行动画
}

void MyPushButton::zoom2()
{
    QPropertyAnimation *animation = new QPropertyAnimation(this,"geometry");
    animation->setDuration(200);//设置动画间隔
    animation->setStartValue(QVariant(QRect(this->x(), this->y()+20, this->width(), this->height())));
    animation->setEndValue(QVariant(QRect(this->x(), this->y(), this->width(), this->height())));
    animation->setEasingCurve(QEasingCurve::OutBounce);//设置弹跳曲线
    animation->start();//执行动画
}

void MyPushButton::setPos(int x, int y)
{
    this->move(QPoint(x, y));
}

在主场景中,需要自定义事件来执行动画,点击之后应该停留一段时间,然后跳转到关卡选择场景。

停留方法,QTimer::singleShot(延迟时间,延迟的对象,延迟结束后执行什么操作)

对于延迟后的操作可以用lambda表达式来定义。

此处延迟0.5秒后令当前窗体用hide()方法隐藏,令自定义的choosescene场景显示

​

    connect(start, &QPushButton::clicked, [=](){
        start->zoom1();
        start->zoom2();

        //点击之后,停留0.5秒后自身隐藏,scene显示
        //QTimer::singleShot(延迟多久,谁延迟,时间结束后执行什么操作可用lambda表达式表示)
        QTimer::singleShot(500, this, [=](){//即0.5秒后让this隐藏,另一个场景scene显示
            this->hide();
            choosescene->show();
        });
    });

[点击并拖拽以移动]
​

5.关卡选择场景设置

主要设置大小、窗体图标、窗体标题、菜单栏、返回按钮。

需要在菜单栏中添加退出事件。

在返回按钮中令其能够返回到主场景

#include "chooselevelscence.h"

ChooseLevelScence::ChooseLevelScence(QWidget *parent)
{
    //设置大小
    this->setFixedSize(320, 588);
    //设置图标
    this->setWindowIcon(QIcon("://res//Coin0001.png"));
    //设置标题
    this->setWindowTitle("选择关卡");

    //设置菜单栏
    QMenuBar * bar = new QMenuBar(this);
    this->setMenuBar(bar);
    QMenu * startMenu = bar->addMenu("开始");
    QAction * quitAction = startMenu->addAction("退出");
    connect(quitAction, &QAction::triggered, [=](){//点击退出后关闭
        this->close();
    });

    //在该场景中添加返回按钮
    //返回按钮不需要弹跳
    MyPushButton * back = new MyPushButton("://res//BackButton.png","://res//BackButtonSelected.png");
    back->setParent(this);
    back->setPos(this->width()-back->width()-20, this->height()-back->height()-20);
    connect(back, &QPushButton::clicked, [=](){
        //点击返回按钮后返回主场景
        this->hide();
    });
}

ChooseLevelScence::~ChooseLevelScence()
{

}

void ChooseLevelScence::paintEvent(QPaintEvent *ev)
{
    QPainter painter(this);
    painter.drawPixmap(0, 0, this->width(), this->height(), QPixmap("://res//PlayLevelSceneBg.png"));

    //显示标题,显示在中间
    QPixmap *title = new QPixmap("://res//Title.png");
    painter.drawPixmap(this->width()*0.5-title->width()*0.5, 30, title->width(), title->height(), *title);//绘制标题
}


6.主界面与选择关卡界面的切换

可通过发送接受自定义的信号来实现。

首先需要在chooselevelscence类中定义信号

signals:
    void chooseBackbutton();

然后当其界面中的back按钮被点击后,延迟0.5秒后隐藏这个场景并发送这个信号。

    connect(back, &QPushButton::pressed, [=](){//按下返回,切换场景
        //点击返回按钮后返回主场景
        QTimer::singleShot(500, this, [=](){//为了看到按下特效,需要在按下后0.5秒后隐藏
            this->hide();
            //发出出切换场景的信号
            emit this->chooseBackbutton();
        });
    });

之后需要在mainwindows中接受信号并显示窗体

    connect(choosescene, &ChooseLevelScence::chooseBackbutton, this, [=](){//当choosescene发出信号后,主窗体显示
        choosescene->hide();
        this->show();
    });

7.创建选择关卡的按钮

在chooselevelscence类中用一层for循环来创建关卡按钮

i%4令有4列(0,1,2,3)

i/4令有20/4=5行

25、130是初试位置,70是按钮之间的间距

由于按钮类的setText显示文字不是很好,因此采用QLabel来显示关卡数,但如此就会对按钮造成遮挡,当需要监听按钮的点击事件时就无法获取信号。

因此需要设置鼠标穿透

对label调用setAttribute方法,传参:Qt::WA_TransparentForMouseEvents

    //创建选择关卡的按钮
    for(int i=0;i<20;i++){
        MyPushButton *button = new MyPushButton("://res//LevelIcon.png");
        button->setParent(this);
        button->setPos(25+i%4*70, 130+i/4*70);//最终有4列,每列有20/4=5个按钮

        QLabel *label = new QLabel(this);
        label->setFixedSize(button->width(), button->height());
        label->move(25+i%4*70, 130+i/4*70);
        label->setText(QString::number(i+1));
        label->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);//设置标签水平居中且垂直居中
        //此时由于label将button遮掩,因此需要设置鼠标穿透
        label->setAttribute(Qt::WA_TransparentForMouseEvents);
        //需要监听每个按钮的点击事件
        connect(button, &QPushButton::clicked, [=](){
            qDebug()<<"您选择的是第"<<i+1<<"关";
        });
    }

8.创建关卡场景

点击关卡按钮后需要跳转到对应的关卡场景,定义类PlayScene

先对其进行基本设置:大小、窗体图标、标题,菜单栏的添加,退出设置

背景绘制

返回按钮添加(点击该按钮后应返回chooselevelscence场景,因此需要在该类中自定义信号,由chooselevelscence类接受信号),因此在chooselevelscence实现的选择关卡部分应为:

    //创建选择关卡的按钮
    for(int i=0;i<20;i++){
        MyPushButton *button = new MyPushButton("://res//LevelIcon.png");
        button->setParent(this);
        button->setPos(25+i%4*70, 130+i/4*70);//最终有4列,每列有20/4=5个按钮

        QLabel *label = new QLabel(this);
        label->setFixedSize(button->width(), button->height());
        label->move(25+i%4*70, 130+i/4*70);
        label->setText(QString::number(i+1));
        label->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);//设置标签水平居中且垂直居中
        //此时由于label将button遮掩,因此需要设置鼠标穿透
        label->setAttribute(Qt::WA_TransparentForMouseEvents);
        //需要监听每个按钮的点击事件
        connect(button, &QPushButton::clicked, [=](){
            //进入到关卡场景中
            PlayScene * playscene = new PlayScene(this, i+1);
            this->hide();//将当前的隐藏掉
            playscene->show();//显示关卡
            //场景切换
            connect(playscene, &PlayScene::chooseBack, [=](){//此时返回
                this->show();
                delete playscene;
            });
        });
    }

在PlayScene的构造函数需要接收一个id属性来看是在第几个场景中

#include "playscene.h"

PlayScene::PlayScene(QWidget *parent, int id) : QMainWindow(parent), id(id)
{
    //基本设置
    this->setFixedSize(320, 588);//设置大小
    this->setWindowIcon(QIcon("://res//Coin0001.png"));//设置窗体图标
    this->setWindowTitle("游戏场景");

    //添加开始菜单栏
    QMenuBar * bar = new QMenuBar(this);
    this->setMenuBar(bar);
    QMenu * start = bar->addMenu("开始");
    QAction * quit = start->addAction("退出");
    connect(quit, &QAction::triggered, [=](){
        this->close();
    });

    //添加返回按钮
    MyPushButton * button = new MyPushButton("://res//BackButton.png", "://res//BackButtonSelected.png");
    button->setParent(this);
    button->setPos(this->width()-button->width()-20, this->height()-button->height()-20);
    //点击返回之后需要返回到场景选择界面
    connect(button, &QPushButton::clicked, [=](){
        QTimer::singleShot(500, this, [=](){//延迟一下再发送
            emit this->chooseBack();//发送信号,令场景选择界面接受
        });
    });
}

void PlayScene::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);//绘制当前关卡场景
    //绘制背景
    painter.drawPixmap(0, 0, this->width(), this->height(), QPixmap("://res//OtherSceneBg.png"));

    //绘制标题
    QPixmap pix;
    pix.load("://res//Title.png");
    painter.drawPixmap(10, 30, pix.width()*0.5, pix.height()*0.5, pix);
}

void PlayScene::setId(int id)
{
    this->id = id;
}

int PlayScene::getId()
{
    return this->id;
}

9.在游戏场景中显示关卡号

在PlayScene类中实现

使用label显示文字“Level 关卡号”

可调用setGeometry(x, y, width, height)来设置标签位置和大小

通过QFont来定义字体

setPointSize设置字体大小

QLabel通过setFont方法设置字体

    //显示关卡号
    QLabel * label = new QLabel(this);
    QString str = QString("Level ") + QString::number(this->id);
    label->setGeometry(20, this->height()-70, 150, 50);//设置标签大小
    label->setText(str);
    QFont font("华文新魏");
    font.setPointSize(24);
    label->setFont(font);//设置字体

10.金币类的封装

用按钮类来表示金币图片

传入的path是金币或银币图片的路径

#include "mycoin.h"

MyCoin::MyCoin(QWidget *parent) : QPushButton(parent)
{

}

MyCoin::MyCoin(QString path)
{
    QPixmap pix;
    bool isok = pix.load(path);
    if(!isok){
        qDebug()<<path<<" "<<"加载失败";
    }
    //此时说明加载成果
    this->setFixedSize(pix.width(), pix.height());//设置按钮固定大小
    this->setStyleSheet("QPushButton{border:0px;}");//设置风格样式
    this->setIcon(QIcon(pix));
    this->setIconSize(QSize(pix.width(), pix.height()));//设置图标的大小
}

11.设置每个关卡的默认显示

需要根据配置文件中定义好的关卡矩阵来对金币或银币进行显示

配置文件代码:

在该文件中可以通过mData[id][i][j]来访问关卡名为id的矩阵中第i行,第j列的元素值

值为1代表这个位置初始为金币

值为0代表这个位置初始为银币

一共20个关卡。

#ifndef DATACONFIG_H
#define DATACONFIG_H

#include <QObject>
#include <QMap>
#include <QVector>

class dataConfig : public QObject
{
    Q_OBJECT
public:
    explicit dataConfig(QObject *parent = 0);

public:

    QMap<int, QVector< QVector<int> > >mData;



signals:

public slots:
};

#endif // DATACONFIG_H
#include "dataconfig.h"
#include <QDebug>
dataConfig::dataConfig(QObject *parent) : QObject(parent)
{

     int array1[4][4] = {{1, 1, 1, 1},
                        {1, 1, 0, 1},
                        {1, 0, 0, 0},
                        {1, 1, 0, 1} } ;

     QVector< QVector<int>> v;
     for(int i = 0 ; i < 4;i++)
     {
         QVector<int>v1;
         for(int j = 0 ; j < 4;j++)
         {

            v1.push_back(array1[i][j]);
         }
         v.push_back(v1);
     }

     mData.insert(1,v);


     int array2[4][4] = { {1, 0, 1, 1},
                          {0, 0, 1, 1},
                          {1, 1, 0, 0},
                          {1, 1, 0, 1}} ;

     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array2[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(2,v);



     int array3[4][4] = {  {0, 0, 0, 0},
                           {0, 1, 1, 0},
                           {0, 1, 1, 0},
                           {0, 0, 0, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array3[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(3,v);


     int array4[4][4] = {   {0, 1, 1, 1},
                            {1, 0, 0, 1},
                            {1, 0, 1, 1},
                            {1, 1, 1, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array4[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(4,v);


     int array5[4][4] = {  {1, 0, 0, 1},
                           {0, 0, 0, 0},
                           {0, 0, 0, 0},
                           {1, 0, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array5[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(5,v);


     int array6[4][4] = {   {1, 0, 0, 1},
                            {0, 1, 1, 0},
                            {0, 1, 1, 0},
                            {1, 0, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array6[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(6,v);


     int array7[4][4] = {   {0, 1, 1, 1},
                            {1, 0, 1, 1},
                            {1, 1, 0, 1},
                            {1, 1, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array7[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(7,v);

     int array8[4][4] = {  {0, 1, 0, 1},
                           {1, 0, 0, 0},
                           {0, 0, 0, 1},
                           {1, 0, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array8[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(8,v);

     int array9[4][4] = {   {1, 0, 1, 0},
                            {1, 0, 1, 0},
                            {0, 0, 1, 0},
                            {1, 0, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array9[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(9,v);



     int array10[4][4] = {  {1, 0, 1, 1},
                            {1, 1, 0, 0},
                            {0, 0, 1, 1},
                            {1, 1, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array10[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(10,v);


     int array11[4][4] = {  {0, 1, 1, 0},
                            {1, 0, 0, 1},
                            {1, 0, 0, 1},
                            {0, 1, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array11[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(11,v);

     int array12[4][4] = {  {0, 1, 1, 0},
                            {0, 0, 0, 0},
                            {1, 1, 1, 1},
                            {0, 0, 0, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array12[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(12,v);


     int array13[4][4] = {    {0, 1, 1, 0},
                              {0, 0, 0, 0},
                              {0, 0, 0, 0},
                              {0, 1, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array13[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(13,v);

     int array14[4][4] = {    {1, 0, 1, 1},
                              {0, 1, 0, 1},
                              {1, 0, 1, 0},
                              {1, 1, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array14[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(14,v);


     int array15[4][4] = {   {0, 1, 0, 1},
                             {1, 0, 0, 0},
                             {1, 0, 0, 0},
                             {0, 1, 0, 1}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array15[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(15,v);


     int array16[4][4] = {   {0, 1, 1, 0},
                             {1, 1, 1, 1},
                             {1, 1, 1, 1},
                             {0, 1, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array16[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(16,v);

     int array17[4][4] = {  {0, 1, 1, 1},
                            {0, 1, 0, 0},
                            {0, 0, 1, 0},
                            {1, 1, 1, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array17[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(17,v);


     int array18[4][4] = { {0, 0, 0, 1},
                           {0, 0, 1, 0},
                           {0, 1, 0, 0},
                           {1, 0, 0, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array18[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(18,v);

     int array19[4][4] = {   {0, 1, 0, 0},
                             {0, 1, 1, 0},
                             {0, 0, 1, 1},
                             {0, 0, 0, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array19[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(19,v);

     int array20[4][4] = {  {0, 0, 0, 0},
                            {0, 0, 0, 0},
                            {0, 0, 0, 0},
                            {0, 0, 0, 0}} ;
     v.clear();
     for(int i = 0 ; i < 4;i++)
     {
          QVector<int>v1;
          for(int j = 0 ; j < 4;j++)
          {
             v1.push_back(array20[i][j]);
          }
          v.push_back(v1);
     }

     mData.insert(20,v);


     //测试数据
//    for( QMap<int, QVector< QVector<int> > >::iterator it = mData.begin();it != mData.end();it++ )
//    {
//         for(QVector< QVector<int> >::iterator it2 = (*it).begin(); it2!= (*it).end();it2++)
//         {
//            for(QVector<int>::iterator it3 = (*it2).begin(); it3 != (*it2).end(); it3++ )
//            {
//                qDebug() << *it3 ;
//            }
//         }
//         qDebug() << endl;
//    }


}

关卡默认显示的代码:

在playscene类的构造函数中,通过getId方法获取场景的id,然后根据id到配置类中寻找对应的矩阵,根据矩阵各个元素值创建金币或银币,完成当前关卡场景初始化

//创建金币的背景图
    //需要根据场景ID与配置文件对应的矩阵创建金币或银币
    dataConfig fig;//创建配置类
    QVector<QVector<int>> arr = fig.mData[this->getId()];//根据传入的id获取相应的矩阵
    for(int i=0;i<arr.size();i++){
        for(int j=0;j<arr[i].size();j++){
            //用QLabel创建金币背景
            QLabel *lab = new QLabel(this);
            lab->setPixmap(QPixmap("://res//BoardNode(1).png"));
            lab->setFixedSize(50, 50);
            lab->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
            lab->move(57+i*50, 200+j*50);
            //创建金币
            //如果矩阵当前位置的值为1创建金币,0创建银币
            MyCoin *coin=nullptr;
            if(arr[i][j]==1){
                coin = new MyCoin("://res//Coin0001.png");
            }
            else{
                coin = new MyCoin("://res//Coin0008.png");
            }
            coin->setParent(this);
            coin->move(59+i*50, 204+j*50);
        }
    }

12.金币反转的特效

在金币类中定义函数changeFlag,当点击钱币时会调用该方法,判断当前金币的flag,将其flag反转,并开启一个定时器,每30秒发送一次信号

void MyCoin::changeFlag()
{
    //正面翻反面
    if(this->flag==1)
    {
        //开始翻正面的计时器
        time1->start(30);
        flag = 0;//改变flag
    }
    else{//反面翻正面
        time2->start(30);
        flag = 1;
    }
}

发送的信号会被金币内置的timer1或2接受,这两个定时器分别是用于正面反转和反面反转的定时器,当正面反转时,之前的time1每隔30s发送信号,然后会开始读路径,当读完之后停止定时器并将min值重置。

这里的min=1,max=8,因为从正->反的动画图片一共8张,每次发送信号时会读取一次新的图片,当min=8时,已经反转结束。

最后还需要监听一下钱币的点击事件,当点击时,调用changeFlag方法启动对应定时器发送信号实现反转动画

connect(time1, &QTimer::timeout, [=](){
        QPixmap img;
        QString path = QString("://res//Coin000%1").arg(min++);
        img.load(path);
        this->setIcon(QIcon(img));
        this->setFixedSize(img.width(), img.height());
        this->setStyleSheet("QPushButton{border:0px;}");
        this->setIconSize(QSize(img.width(), img.height()));
        if(min > max){//正翻反面结束
            min = 1;
            time1->stop();//停止定时器
        }
    });

    connect(time2, &QTimer::timeout, [=](){
        QPixmap img;
        QString path = QString("://res//Coin000%1").arg(max--);
        img.load(path);
        this->setIcon(QIcon(img));
        this->setFixedSize(img.width(), img.height());
        this->setStyleSheet("QPushButton{border:0px;}");
        this->setIconSize(QSize(img.width(), img.height()));
        if(max < min){//反面翻正面结束
            max = 8;
            time2->stop();//停止定时器
        }
    });

    connect(this, &QPushButton::clicked, [=](){//当coin被点击时将其反转
        this->changeFlag();
    });

13.游戏胜利的判断

在PlayScene中定义isSucceed函数判断游戏是否胜利,点击某个金币后,调用该函数,遍历每个金币查看其flag,若全为true则胜利,否则为false。该函数在反转金币后调用。

bool PlayScene::isSucceed()
{
    for(int i=0;i<gameArr.size();i++){
        for(int j=0;j<gameArr[i].size();j++){
            if(gameArr[i][j]==0){
                this->isok=false;
                return false;
            }
        }
    }
    this->isok=true;
    return true;
}
connect(coin, &QPushButton::clicked, [=](){//当coin被点击时将其反转
                coin->changeFlag();//调用后coin的flag已经改变了
                //点击之后,还应将矩阵中的值修改
                this->gameArr[i][j] = coin->getFlag();
                //延时反转周围
                QTimer::singleShot(300, this, [=](){
                    if(j>0){//反转上边
                        coin_arr[i][j-1]->changeFlag();
                        this->gameArr[i][j-1] = coin_arr[i][j-1]->getFlag();
                    }
                    if(j<gameArr.size()-1){//反转下边
                        coin_arr[i][j+1]->changeFlag();
                        this->gameArr[i][j+1] = coin_arr[i][j+1]->getFlag();
                    }
                    if(i>0){//反转左边
                        coin_arr[i-1][j]->changeFlag();
                        this->gameArr[i-1][j] = coin_arr[i-1][j]->getFlag();
                    }

                    if(i<gameArr[0].size()-1){//反转右边
                        coin_arr[i+1][j]->changeFlag();
                        this->gameArr[i+1][j] = coin_arr[i+1][j]->getFlag();
                    }
                    if(isSucceed()){//成功
                        cout<<"succeed"<<endl;
                        //胜利后设置金币为不可点击状态
                        QTimer::singleShot(1000, this, [=](){
                            this->setEnabled(false);
                        });
                        //应该掉落succeed字样
                    }
                });
            });

14.设置胜利图片

需要实现定义好胜利后的图片,将其置于窗口之外的地方。

//提前设置胜利图片
    QLabel * succeed_pic = new QLabel(this);
    QPixmap img;
    img.load("://res//LevelCompletedDialogBg.png");
    succeed_pic->setPixmap(img);
    succeed_pic->setGeometry(this->width()/2 - img.width()/2, -img.height(), img.width(), img.height());

当胜利时,定义好执行动画,将其从窗口外的位置运行到目标位置处即可。

1秒后,应只让金币无法使用,因此需要遍历金币按钮,setEnabled为false

if(isSucceed()){//成功
    cout<<"succeed"<<endl;
    //胜利后设置金币为不可点击状态
    QPropertyAnimation *animation = new QPropertyAnimation(succeed_pic,"geometry");
    animation->setDuration(1000);//设置动画间隔
    animation->setStartValue(QVariant(QRect(succeed_pic->x(), succeed_pic->y(), succeed_pic->width(), succeed_pic->height())));
    animation->setEndValue(QVariant(QRect(succeed_pic->x(), succeed_pic->y()+200, succeed_pic->width(), succeed_pic->height())));
    animation->setEasingCurve(QEasingCurve::OutBounce);//设置弹跳曲线
    animation->start();//执行动画
    QTimer::singleShot(1000, this, [=](){
        for(int i=0;i<coin_arr.size();i++){
            for(int j=0;j<coin_arr[i].size();j++){
                coin_arr[i][j]->setEnabled(false);//设置所有金币不能使用
            }
        }//不能设置this为Enabled,因为back按钮应该是可以继续使用的,只有金币按钮无法使用
    });
}

15.设置音效

#include<QSound>

该头文件默认没有,需要在.pro文件中的开头进行添加multimedia

QT       += core gui multimedia

QSound创建时传入wav文件路径以及父亲,然后调用play方法开始执行音效

QSound *sound = new QSound("://res//LevelWinSound.wav");
                        sound->setParent(this);
//                        sound->setLoops(2);//设置循环次数,值为-1则无限循环
                        sound->play();//播放音效

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值