Qt案例:翻金币

项目描述

点击硬币,实现其周围硬币的翻转,最后使页面中全显示为金币

1.添加资源文件

1.将所需要的资源文件夹(图片,音频等)复制到项目文件夹中

2.在QT中右击项目,选择添加新文件

3.选择Qt ->选择Qt Resource File ->点击choose按钮

4.给资源文件取命名:如res

5.点击“下一步”,点击完成

6.以资源管理器的方式,打开资源管理器

7.点击“添加前缀”,修改前缀名称如 /

8.点击添加文件,在弹出的文件对话框中,选择刚刚添加的文件夹

9.选择想要添加的资源

10.添加完成后,记得构建,否则可能会出错

11.当能在资源文件中看到刚刚添加的图片,即成功

2.主场景配置

在ui文件

1.移除状态栏

2.添加菜单栏(开始)和菜单项(退出)

在.cpp文件中
设置窗口

1.设置窗口固定大小

2.设置窗口标题

3.设置窗口图标

设置背景图片

1.重写paintEvent事件

在.h文件中声明paintEvent事件

在.cpp文件中重写事件

2.重写绘图事件

声明画家类,并指定其画布

声明QPixmap

加载QPixmap背景图片

画家调用drawPixmap()绘制背景图片

加载QPixmap图标图片

利用scaled()实现图片的放缩

绘制图标图片

退出实现

在点击菜单栏(开始)中的菜单项(退出)后,窗口关闭,这里使用了信号槽机制

1.信号源:ui->actionquit

2.发送的信号:&QAction::triggered

3.利用lambda表达式,实现窗口关闭

4.this.close();

3.创建开始按钮

效果实现:点击开始按钮后,将会看到按钮出现一个弹跳的效果

创建MyPushButton类

选择 继承QWidget类

文件创建成功后,修改其父类为QPushbutton

声明成员变量:

QString nomalImgPath;//保存用户传入的默认图片显示路径 QString pressImgPath;//保存用户按下后显示的图片路径

修改MyPushButton的构造函数的参数列表

参数1:正常显示的图片路径

参数2:按下按钮后显示的图片路径

实现构造函数

1.加载正常显示的图片

2.设置图片的大小,不规则图片的样式

3.设置按钮的图标

开始按钮的实现

在mainscene.cpp中使用自定义的mypushbutton控件

实例化MyPushButton类的开始按钮

构造函数的参数为 开始图标的文件路径

移动开始按钮的位置

将点击按钮做连接,qDebug输出测试语句

开始按钮的跳跃效果实现

在mypushbutton.h 文件中添加

void zoom1();//向下跳

void zoom2();//向上跳

函数声明

函数的实现

1.创建动态对象:QPropertyAnimation

2.设置动画时间间隔

3.设置动态对象的起始位置和结束位置

4.设置弹跳曲线

animal->setEasingCurve(QEasingCurve::OutBounce);

5.执行动画

在开始按钮的connect函数的lambda表达式中分别调用

zoom1()和zoom2()函数

上述部分代码: 

#ifndef MAINSCENE_H
#define MAINSCENE_H
​
#include <QMainWindow>
#include "chooselevelscene.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainScene;
}
QT_END_NAMESPACE
​
class MainScene : public QMainWindow
{
    Q_OBJECT
​
public:
    MainScene(QWidget *parent = nullptr);
    ~MainScene();
​
    //重写paintEvent事件,绘制背景图片
    void paintEvent(QPaintEvent *);
​
    chooseLevelScene * chooseScene=NULL;
​
private:
    Ui::MainScene *ui;
};
#endif // MAINSCENE_H
​
#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H
​
#include <QPushButton>
​
class MyPushButton : public QPushButton
{
    Q_OBJECT
public:
    //防止隐式转换
    //explicit MyPushButton(QWidget *parent = nullptr);
    //构造函数,参数1:正常显示的图片,参数2:按下后显示的图片
    MyPushButton(QString normalImg,QString pressImg="");
    //成员属性:保存用户传入的图片路径
    QString normalImgPath;
    QString pressImgPath;
​
    //弹跳特效
    void zoom1();//向下跳
    void zoom2();//向上跳
​
    //重写按钮的按下和释放事件
    void mousePressEvent(QMouseEvent *e);
​
    void mouseReleaseEvent(QMouseEvent *e);
​
signals:
};
​
#endif // MYPUSHBUTTON_H

 

#include "mainscene.h"
#include "ui_mainscene.h"
#include <QPainter>
#include "mypushbutton.h"
#include <QDebug>
#include <QTimer>
#include <QSound>
MainScene::MainScene(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainScene)
{
    ui->setupUi(this);
​
    //设置翻金币主场景
​
    //设置页面固定大小
    setFixedSize(360,588);//原设置为320.588
​
    //设置图标
    setWindowIcon(QIcon(":/res/Coin0001.png"));
​
    //设置标题
    setWindowTitle("主页面");
​
    //退出按钮的实现  triggered:触发
    connect(ui->actionexit,&QAction::triggered,[=](){
        this->close();
    });
​
    //准备开始按钮的音效
    QSound * startSound=new QSound(":/res/TapButtonSound.wav",this);
​
    //开始按钮
    MyPushButton *startBtn = new MyPushButton(":/res/MenuSceneStartButton.png");
    startBtn->setParent(this);
    startBtn->move(this->width()*0.5-startBtn->width()*0.5,this->height()*0.7);
​
    //实例化选择关卡场景
    chooseScene = new chooseLevelScene;
​
    //监听选择关卡的返回按钮的信号
    connect(chooseScene,&chooseLevelScene::chooseSceneBack,[=](){
        chooseScene->hide();
        this->show();//重新显示主场景
    });
​
    connect(startBtn,&MyPushButton::clicked,[=](){
       // this->setGeometry(chooseScene->geometry());
       // qDebug()<<"点击了开始按钮";
        //播放开始音效
        startSound->play();
​
        //做弹起特效
        startBtn->zoom1();
        startBtn->zoom2();
​
        //延时进入下一界面
        QTimer::singleShot(300,this,[=](){
            //设置chooseScene场景的位置
         //   chooseScene->setGeometry(this->geometry());
​
            //隐藏主界面
            this->hide();
​
            //进入到选择关卡场景中
            chooseScene->show();
​
        });
​
    });
​
}
//重写paintEvent事件
void MainScene::paintEvent(QPaintEvent *)
{
    //创建画家类,指定绘图设备
    QPainter painter(this);
    //创建QPixmap对象
    QPixmap pix;
    //加载图片
    pix.load(":/res/PlayLevelSceneBg.png");
    //绘制背景图片  参数3,4:使图片适应窗口大小
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
​
    //加载标题图片
    pix.load(":/res/Title.png");
    //缩放图片:原尺寸*放缩倍数
    pix=pix.scaled(pix.width()*0.5,pix.height()*0.5);
    //绘制标题
    painter.drawPixmap(10,30,pix);
}
​
MainScene::~MainScene()
{
     delete ui;
}
​
#include "mypushbutton.h"
#include <QDebug>
#include <QPropertyAnimation>
// MyPushButton::MyPushButton(QWidget *parent)
//     : QPushButton{parent}
// {}
​
//声明带默认参数,则实现不带参数,否则将报错
//开始按钮和返回按钮
MyPushButton::MyPushButton(QString normalImg,QString pressImg)
{
    this->normalImgPath=normalImg;
    this->pressImgPath=pressImg;
​
    QPixmap pix;
    bool ret= pix.load(normalImg);
    if(!ret)
    {
        qDebug()<<"图片加载失败";
        return;
    }
​
    //设置按钮固定的大小(根据所要显示的图片确定大小)
    this->setFixedSize(pix.width(),pix.height());
​
    //设置不规则图片样式
    this->setStyleSheet("QPushButton{border:0px;}");
​
    //设置图标(按钮上显示的图片)
    this->setIcon(pix);
​
    //设置图标大小
    this->setIconSize(QSize(pix.width(),pix.height()));
​
​
}
​
//弹跳特效
//down
void MyPushButton::zoom1()
{
    //创建动态对象
    QPropertyAnimation * animation=new QPropertyAnimation(this,"geometry");
    //设置动画时间间隔
    animation->setDuration(50);
​
    //起始位置
    animation->setStartValue(QRect(this->x(),this->y(),this->width(),this->height()));
​
    //结束位置
    animation->setEndValue(QRect(this->x(),this->y()+7,this->width(),this->height()));
​
    //设置弹跳曲线
    animation->setEasingCurve(QEasingCurve::OutBounce);
​
    //执行动画
    animation->start();
​
}
//up
void MyPushButton::zoom2()
{
    //创建动态对象
    QPropertyAnimation * animation=new QPropertyAnimation(this,"geometry");
    //设置动画时间间隔
    animation->setDuration(50);
​
    //起始位置
    animation->setStartValue(QRect(this->x(),this->y()-7,this->width(),this->height()));
​
    //结束位置
    animation->setEndValue(QRect(this->x(),this->y(),this->width(),this->height()));
​
    //设置弹跳曲线
    animation->setEasingCurve(QEasingCurve::OutBounce);
​
    //执行动画
    animation->start();
}
​
//重写按钮的按下和释放事件
void MyPushButton::mousePressEvent(QMouseEvent *e)
{
    //传入的图片不为空,说明需要有按下状态时切换图片
    if(this->pressImgPath!="")
    {
        QPixmap pix;
        bool ret= pix.load(this->pressImgPath);
        if(!ret)
        {
            qDebug()<<"图片加载失败";
            return;
        }
​
        //设置按钮固定的大小(根据所要显示的图片确定大小)
        this->setFixedSize(pix.width(),pix.height());
​
        //设置不规则图片样式
        this->setStyleSheet("QPushButton{border:0px;}");
​
        //设置图标(按钮上显示的图片)
        this->setIcon(pix);
​
        //设置图标大小
        this->setIconSize(QSize(pix.width(),pix.height()));
​
    }
    //让父类执行其他的内容
    return QPushButton::mousePressEvent(e);
​
}
​
​
void MyPushButton::mouseReleaseEvent(QMouseEvent *e)
{
    //传入的图片不为空,说明需要有按下状态时,切换为初始图片
    if(this->normalImgPath!="")
    {
        QPixmap pix;
        bool ret= pix.load(this->normalImgPath);
        if(!ret)
        {
            qDebug()<<"图片加载失败";
            return;
        }
​
        //设置按钮固定的大小(根据所要显示的图片确定大小)
        this->setFixedSize(pix.width(),pix.height());
​
        //设置不规则图片样式
        this->setStyleSheet("QPushButton{border:0px;}");
​
        //设置图标(按钮上显示的图片)
        this->setIcon(pix);
​
        //设置图标大小
        this->setIconSize(QSize(pix.width(),pix.height()));
​
    }
    //让父类执行其他的内容
    return QPushButton::mouseReleaseEvent(e);
}
​

4.创建关卡场景

1.添加新文件

2.在mainscene.h中声明选择关卡场景

3.实例化选关场景,并通过开始按钮进入该场景

4.延时进入选择关卡场景

5.当前窗口的隐藏

6.选择关卡场景调用show()函数

基本配置

窗口配置

1.设置窗口固定大小

2.设置窗口标题

3.设置窗口图标

设置背景图片

1.重写paintEvent事件

2.重写绘图事件

画家调用drawPixmap()绘制背景图片

绘制图标图片

返回按钮的图片切换

描述:不同于开始按钮的动画实现点击效果,在返回按钮中是通过重写鼠标按下和释放事件时,切换不同的图片达到点击的效果

重写鼠标点击和释放事件

mypushbutton.h文件中声明

mypushbutton.cpp文件中实现

1.判断传入的图片是否为空,不为空则需要切换图片

2.设置图片的固定大小

3.设置不规则图片样式

4.设置图标,及大小

5.让父类执行其他操作 return QPushButton::mousePressEvent(ev);

返回按钮的功能实现

1.在选择关卡的头文件中,自定义一个信号

2.主场景监听该信号

3.当用户点击了返回按钮后,emit发送该信号

4.当主场景收到该信号后,隐藏选择关卡场景,显示主场景

选择关卡的按钮创建
自定义的按钮

1.利用循环创建出一个4*5,共20个的自定义按钮

2.设定按钮的图标

3.为按钮设置父类,this

4.在循环中,移动每个按钮,使其到合适的位置上

关卡文字标签

因为关卡的图标是不规则图形,所以直接利用按钮设置文字来指明关卡数,并没有很好的效果,所以另外利用循环创建label来显示文字

1.new一个label对象,并指明其父类

2.设置其宽高分别为选择按钮的宽高

3.设置文字,即关卡数

4.将其移动到对应的按钮位置上

5.将文字设置为水平和垂直居中

鼠标穿透效果

若此时运行,直接点击选择关卡按钮,将不会出现任何效果。

因为在按钮的上方还有一次我们用来显示关卡数的label标签

我们可以通过设置标签穿透,来实现对按钮的点击事件

label->setAttribute(Qt::WA_TransparentForMouseEvents);

进入游戏界面

创建相应的cpp和h文件,并对游戏界面实现基本的初始化,如固定其大小,设置window标题和图标,设置背景图片(重写绘图事件)

在选择关卡界面,监听每个按钮的点击事件

在lambda表达式中,依次,隐藏当前界面;创建翻金币创建,在参数列表中,指定其初始化的关卡;show游戏场景

上述部分代码:

#ifndef CHOOSELEVELSCENE_H
#define CHOOSELEVELSCENE_H
#include <QPaintEvent>
#include <QMainWindow>
#include "playscene.h"
class chooseLevelScene : public QMainWindow
{
    Q_OBJECT
public:
    explicit chooseLevelScene(QWidget *parent = nullptr);
​
    //重写绘图事件
    void paintEvent(QPaintEvent *);
​
    //游戏场景对象指针
    PlayScene *play=NULL;
​
signals:
    //自定义信号,告诉主场景点击了返回
    void chooseSceneBack();
};
​
#endif // CHOOSELEVELSCENE_H
​
#include "chooselevelscene.h"
#include <QMenuBar>
#include <QPainter>
#include "mypushbutton.h"
#include <QDebug>
#include <QTimer>
#include <QLabel>
#include <QSound>
chooseLevelScene::chooseLevelScene(QWidget *parent)
    : QMainWindow{parent}
{
    //配置选择关卡场景
    this->setFixedSize(360,588);
​
    //设置图标
    this->setWindowIcon(QPixmap(":/res/Coin0001.png"));
    //设置标题
    this->setWindowTitle("选择关卡");
​
    //创建开始菜单栏
    QMenuBar *bar=menuBar();
    setMenuBar(bar);
​
    //创建开始菜单
    QMenu * startMenu=bar->addMenu("开始");
​
    //创建退出菜单项
    QAction *exitAction=startMenu->addAction("退出");
​
    //点击退出,关闭窗口
    connect(exitAction,&QAction::triggered,[=](){
        this->close();
    });
​
    //选择关卡音效
    QSound *chooseSound=new QSound(":/res/TapButtonSound.wav",this);
    //返回按钮音效
    QSound *backSound=new QSound(":/res/BackButtonSound.wav",this);
    //返回按钮
    MyPushButton * backBtn=new MyPushButton(":/res/BackButton.png",":/res/BackButtonSelected.png");
    backBtn->setParent(this);
    backBtn->move(this->width()-backBtn->width(),this->height()-backBtn->height());
​
    //点击返回
    connect(backBtn,&MyPushButton::clicked,[=](){
        //qDebug()<<"点击了返回按钮";
        //主场景监听chooseLevelScene的返回按钮
        //发送自定义信号
        //延时返回,即延时发送信号
        //播放返回按钮音效
        backSound->play();
        QTimer::singleShot(300,this,[=](){
            emit this->chooseSceneBack();
        });
​
    });
​
    //创建选择关卡的按钮
    //利用一个循环写出矩阵
    for(int i=0;i<20;i++)
    {
        MyPushButton * menuBtn = new MyPushButton(":/res/LevelIcon.png");
        menuBtn->setParent(this);
        menuBtn->move(50+i%4*70,130+i/4*70);
​
​
​
        //监听每个按钮的点击事件
        connect(menuBtn,&MyPushButton::clicked,[=](){
            //播放选择关卡音效
            chooseSound->play();
            QString str = QString("您选择的是第%1关").arg(i+1);
            qDebug()<<str;
​
​
            //进入到游戏场景
            this->hide();
            play=new PlayScene(i+1);
​
            //设置游戏场景初始位置
            //play->setGeometry(this->geometry());
            play->show();
​
            //监听游戏界面返回事件
            connect(play,&PlayScene::chooseSceneBack,[=](){
            //    this->setGeometry(play->geometry());
                this->show();
                delete play;
                play=NULL;
            });
​
        });
​
        //对于不规则按钮上显示文字,效果不理想
        QLabel * lable=new QLabel(this);
        lable->setFixedSize(menuBtn->width(),menuBtn->height());
        lable->setText(QString::number(i+1));
        lable->move(50+i%4*70,130+i/4*70);
        //设置lable的文字对齐方式,水平居中和垂直居中
        lable->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
​
        //设置让鼠标进行穿透,使鼠标的点击穿透lable标签,直达menuBtn按钮
        //51号属性
        lable->setAttribute(Qt::WA_TransparentForMouseEvents);
​
​
    }
​
}
​
//重写绘图事件
void chooseLevelScene::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    QPixmap pix;
    pix.load(":/res/OtherSceneBg.png");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
​
    //标题
    pix.load(":/res/Title.png");
    painter.drawPixmap(0.5*(this->width()-pix.width()),30,pix.width(),pix.height(),pix);
​
}
​
​
 

5.游戏界面

游戏场景返回按钮

1.在.h文件中声明一个点击按钮返回的信号

2.在.cpp文件中,关联用户点击返回按钮和发送信号

3.在选择关卡场景中,监听游戏界面返回的信号

4.隐藏游戏界面,显示选择关卡界面

显示关卡标签

1.在游戏界面的构造函数中,创建一个label对象

  1. QString str2 =QString("Level:%1").arg(this->levelIndex)

  2. 为标签指定其字体的大小的类型

  3. label设置文字

  4. 通过label->setGeometry来指定标签的大小和位置

创建金币背景图片

利用循环放置一个4*4的金币背景图片

创建金币类

mycoin类继承于QPushButton类

1.重写构造函数,通过参数列表传入不同的路径,来确定其为金币还是银币

2.设置金币类的图标(即传进的资源路径,注意金币类继承于按钮)

3.设置金币类的样式,大小

4.设置金币类图标的大小,即金币图片的大小

关卡数据载入

1.添加配置文件到翻金币项目中,dataconfig.h和dayaconfig.cpp文件

2.将配置文件设置为资源文件

3.在playscene.h中声明二维数组,维护每个关卡的具体数据。

int gameArray[ 4 ] [ 4 ];

4.在palyscene.cpp中初始化每个关卡的二维数组

5.在配置文件中,1代表金币,2代表银币

6.在金币类中添加金币属性

金币的x坐标

金币的y坐标

一个bool类型的flag ,用来标识金币的正反面,正面为true

7.注意关卡数据的载入和金币背景的绘制都在一个双重循环中实现,即i表示金币的x坐标,j表示金币的y坐标

flag=this->gameArray[i] [j];

金币翻转特效

1.在mycoin.h头文件中声明属性和行为

 //改变标志的方法
    void changeFlag();
    QTimer * timer1;//正面翻反面的计时器
    QTimer * timer2;//反面翻正面的定时器
    int min=1;
    int max=8;
    
 //执行动画标志
    bool isAnimation=false;
​

2.实现方法

1).改变标志的方法

判断硬币此时是正还是反(金或银),

打开相应的计时器,执行动画标志置为true,正反标志取反

2).监听正反面翻转的信号,并且翻转金币

利用计时器,若金币还未从1到8,或8到1翻转完毕,则将一直不会受到计时器的timeout信号,当金币翻转的整个过程实现完毕,执行动画的标志设置为false,关闭计时器,此时停止翻转

3).将点击金币按钮和调用changeFlag()方法建立连接

解决快速点击的bug

重写按下和释放事件

若金币类正在执行动画,则按下不起作用

其余事件交予父类处理

翻转周围金币

创建一个金币的二维数组

MyCoin *coinBtn[4] [4];

1.当点击金币时,实现该金币的翻转,并将关卡的二维数组取反

2.依次实现该金币上下左右金币的翻转

3.周围的金币要比中间的金币滞后实现翻转,利用计时器

判断胜利

1.游戏场景中添加胜利的标志

2.每次点击金币后,遍历判断金币类二维数组中的每个正反标志,若出现一个标志为false,则没有胜利

3.在mycoin类中添加胜利的标志

4.若游戏胜利,则将每个金币的标志设为true

5.在重写的按下事件中,添加,如果金币的胜利标志为true则禁止按下(按下没有响应)

胜利图片特效

1.将胜利图片放置在在游戏窗口的上方,可以想象为x轴的负半轴

2.当游戏判断为胜利时,利用动画,修改胜利图片的位置

添加音频资源

1.在.pro配置文件中添加多媒体的库

2.初始化开始的音效,当用户点击开始按钮时播放音效

3.选择关卡场景中,点击关卡按钮,播放音效

4.选择关卡场景中,点击返回按钮,播放音效

5.翻金币场景中,点击金币按钮、以及胜利,播放音效

上述部分代码:

#ifndef PLAYSCENE_H
#define PLAYSCENE_H
#include "mycoin.h"
#include <QMainWindow>
​
class PlayScene : public QMainWindow
{
    Q_OBJECT
public:
    //explicit PlayScene(QWidget *parent = nullptr);
​
    PlayScene(int levelNnum);
​
    //记录所选的关卡
    int levelIndex;
​
    //重写绘图事件
    void paintEvent(QPaintEvent *);
​
    int gameArray[4][4];//二维数组 维护每一个关卡的具体内容
    Mycoin * coinBtn[4][4];
    //是否胜利的标志
    bool isWin;
signals:
    void chooseSceneBack();
};
​
#endif // PLAYSCENE_H
​
#include "playscene.h"
#include <QMenuBar>
#include<QPainter>
#include <QPixmap>
#include "mypushbutton.h"
#include <QTimer>
#include <QLabel>
#include <QDebug>
#include "mycoin.h"
#include "dataconfig.h"
#include <QPropertyAnimation>
#include <QSound>
// PlayScene::PlayScene(QWidget *parent)
//     : QMainWindow{parent}
// {}
​
​
PlayScene::PlayScene(int levelNum)
{
    this->levelIndex=levelNum;
​
    //初始化游戏场景
    this->setFixedSize(360,588);
    this->setWindowIcon(QPixmap(":/res/Coin0001.png"));
    this->setWindowTitle("翻金币场景");
​
    //创建开始菜单栏
    QMenuBar *bar=menuBar();
    setMenuBar(bar);
​
    //创建开始菜单
    QMenu * startMenu=bar->addMenu("开始");
​
    //创建退出菜单项
    QAction *exitAction=startMenu->addAction("退出");
​
    //点击退出,关闭窗口
    connect(exitAction,&QAction::triggered,[=](){
        this->close();
    });
​
    //添加音效资源
     QSound * backSound=new QSound(":/res/BackButtonSound.wav",this);
     QSound * filpSound=new QSound(":/res/ConFlipSound.wav",this);
      QSound * winSound=new QSound(":/res/LevelWinSound.wav",this);
​
     //返回按钮
​
    MyPushButton * backBtn=new MyPushButton(":/res/BackButton.png",":/res/BackButtonSelected.png");
    backBtn->setParent(this);
    backBtn->move(this->width()-backBtn->width(),this->height()-backBtn->height());
​
    //点击返回
    connect(backBtn,&MyPushButton::clicked,[=](){
        //qDebug()<<"点击了返回按钮";
        //主场景监听chooseLevelScene的返回按钮
        //发送自定义信号
        //延时返回,即延时发送信号
        //返回音效
        backSound->play();
        QTimer::singleShot(300,this,[=](){
            emit this->chooseSceneBack();
        });
​
    });
​
    //显示当前的关卡数
    QLabel * label =new QLabel(this);
    QFont font;
    font.setFamily("华文新魏");
    font.setPointSize(20);
    QString str1=QString("Level:%1").arg(this->levelIndex);
    //将字体设置到标签控件中
    label->setFont(font);
    label->setText(str1);
    label->setGeometry(30,this->height()-60,120,50);
​
    dataConfig config;
    //初始化每个关卡的二维数组
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            this->gameArray[i][j]=config.mData[this->levelIndex][i][j];
        }
    }
​
​
    //胜利图片的显示
    QLabel * winLabel=new QLabel;
    QPixmap tempix;
    tempix.load(":/res/LevelCompletedDialogBg.png");
    winLabel->setGeometry(0,0,tempix.width(),tempix.height());
    winLabel->setPixmap(tempix);
    winLabel->setParent(this);
    winLabel->move(this->width()*0.5-tempix.width()*0.5,-tempix.height());
​
    //显示金币的背景图案
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            QLabel *label=new QLabel(this);
            label->setGeometry(0,0,50,50);
            label->setPixmap(QPixmap(":/res/BoardNode.png"));
            label->move(77+i*50,200+j*50);
​
​
​
            //创建金币
            QString str;
            if(this->gameArray[i][j]==1)
            {
                //显示金币
                str=":/res/Coin0001.png";
            }
            else
            {
                str=":/res/Coin0008.png";
            }
​
            Mycoin * coin=new Mycoin(str);
            coin->setParent(this);
            coin->move(79+i*50,204+j*50);
​
            //给金币的属性赋值
            coin->posX=i;
            coin->posY=j;
            coin->flag=this->gameArray[i][j]==1;//1:金币 0:反面
​
            //将硬币放入到硬币的二维数组里,以便于后期的维护
            coinBtn[i][j]=coin;
​
            //点击金币进行翻转
            connect(coin,&Mycoin::clicked,[=](){
                //翻金币音效
                filpSound->play();
                //将所有硬币标志为true,一次只能点击一个硬币,避免BUG
                for(int i=0;i<4;i++)
                {
                    for(int j=0;j<4;j++)
                    {
                        coinBtn[i][j]->isWin=true;
                    }
                }
​
                coin->changeFlag();
                //将动画效果实现完全,再进行下一次的动画
                //实现0到8或者8到0的翻转
               // this->gameArray[i][j]=(this->gameArray[i][j]==0?1:0);
                //或直接取反
                this->gameArray[i][j]=!this->gameArray[i][j];
​
                //翻转周围硬币,延时翻转
                QTimer::singleShot(300,this,[=](){
                    //翻转右侧的硬币
                    if(coin->posX+1<=3)
                    {
                        coinBtn[coin->posX+1][coin->posY]->changeFlag();
                        this->gameArray[coin->posX+1][coin->posY]=!this->gameArray[coin->posX+1][coin->posY];
                    }
                    //翻转左侧的硬币
                    if(coin->posX-1>=0)
                    {
                        coinBtn[coin->posX-1][coin->posY]->changeFlag();
                        this->gameArray[coin->posX-1][coin->posY]=!this->gameArray[coin->posX-1][coin->posY];
                    }
                    //翻转下侧的硬币
                    if(coin->posY+1<=3)
                    {
                        coinBtn[coin->posX][coin->posY+1]->changeFlag();
                        this->gameArray[coin->posX][coin->posY+1]=!this->gameArray[coin->posX][coin->posY+1];
                    }
                    //翻转上侧的硬币
                    if(coin->posY-1>=0)
                    {
                        coinBtn[coin->posX][coin->posY-1]->changeFlag();
                        this->gameArray[coin->posX][coin->posY-1]=!this->gameArray[coin->posX][coin->posY-1];
                    }
​
                    //当周围硬币翻完之后,置false,再次开启
                    for(int i=0;i<4;i++)
                    {
                        for(int j=0;j<4;j++)
                        {
                            coinBtn[i][j]->isWin=false;
                        }
                    }
​
                    //每次翻完金币后,判断是否胜利
                    //也可以遍历数组求和判断
                    this->isWin=true;
                    for(int i=0;i<4;i++)
                    {
                        for(int j=0;j<4;j++)
                        {
                            if(coinBtn[i][j]->flag==false)
                            {
                                this->isWin=false;
                                break;
                            }
                        }
                    }
                    if(this->isWin==true)
                    {
                        //胜利音效
                        winSound->play();
                        qDebug()<<"成功";
                        //将所有按钮的胜利标志改为true,如果用户再次点击按钮,直接return,不做任何响应
                        for(int i=0;i<4;i++)
                        {
                            for(int j=0;j<4;j++)
                            {
                                coinBtn[i][j]->isWin=true;
                            }
                        }
​
                        //将胜利图片出现
                        QPropertyAnimation * animation = new QPropertyAnimation(winLabel,"geometry");
                        //设置事件间隔
                        animation->setDuration(1000);
                        //设置开始位置
                        animation->setStartValue(QRect(winLabel->x(),winLabel->y(),winLabel->width(),winLabel->height()));
                        //结束位置
                        animation->setEndValue(QRect(winLabel->x(),winLabel->y()+114,winLabel->width(),winLabel->height()));
​
                        //缓和曲线
                        animation->setEasingCurve(QEasingCurve::OutBounce);
​
                        //执行动画
                        animation->start();
                    }
​
                });
​
​
            });
        }
    }
​
​
​
​
}
​
void PlayScene::paintEvent(QPaintEvent *)
{
    //背景
    QPainter painter(this);
    QPixmap pix;
    pix.load(":/res/PlayLevelSceneBg.png");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
​
    //加载标题图片
    pix.load(":/res/Title.png");
    //缩放图片:原尺寸*放缩倍数
    pix=pix.scaled(pix.width()*0.5,pix.height()*0.5);
    //绘制标题
    painter.drawPixmap(10,30,pix);
}
​
#ifndef MYCOIN_H
#define MYCOIN_H
​
#include <QTimer>
#include <QPushButton>
​
class Mycoin : public QPushButton
{
    Q_OBJECT
public:
    explicit Mycoin(QPushButton *parent = nullptr);
    //参数代表传入的金币或银币路径
    Mycoin(QString btnImg);
​
    //金币的属性
    int posX;
    int posY;
    bool flag;
​
    //改变标志的方法
    void changeFlag();
​
    QTimer *timer1=NULL;//正面翻反面的定时器
    QTimer *timer2=NULL;//反面翻正面的定时器
    int min=1;
    int max=8;
    //执行动画的标志
    bool isAnimation=false;
​
    //重写按下
    void mousePressEvent(QMouseEvent *e);
    //是否胜利的标志
    bool isWin;
​
​
signals:
};
​
#endif // MYCOIN_H
​
#include "mycoin.h"
#include <QDebug>
​
// Mycoin::Mycoin(QPushButton *parent)
//     : QPushButton{parent}
// {}
​
​
//参数代表传入的金币或银币路径
Mycoin::Mycoin(QString btnImg)
{
    QPixmap pix;
    bool ret=pix.load(btnImg);
    if(!ret)
    {
        QString str=QString("图片%1加载失败").arg(btnImg);
        qDebug()<<"str";
        return;
    }
​
    this->setFixedSize(pix.width(),pix.height());
    this->setStyleSheet("QPushButton{border:0px}");
    this->setIcon(pix);
    this->setIconSize(QSize(pix.width(),pix.height()));
​
    //初始化定时器
    timer1 = new QTimer(this);
    timer2 = new QTimer(this);
​
    //监听正面翻反面的信号,并翻转金币
    connect(timer1,&QTimer::timeout,[=](){
        QPixmap pix;
        //利用MIN实现金币的逐步翻转
        QString str=QString(":/res/Coin000%1.png").arg(this->min++);
        pix.load(str);
​
        this->setFixedSize(pix.width(),pix.height());
        this->setStyleSheet("QPushButton{border:0px}");
        this->setIcon(pix);
        this->setIconSize(QSize(pix.width(),pix.height()));
​
        //判断 如果翻完了,将min重置为1,并关闭定时器
        if(this->min>this->max)
        {
            this->min=1;
            isAnimation=false;
            timer1->stop();
        }
    });
​
    //监听反面翻正面的信号,并翻转银币
    connect(timer2,&QTimer::timeout,[=](){
        QPixmap pix;
        //利用MIN实现金币的逐步翻转
        QString str=QString(":/res/Coin000%1.png").arg(this->max--);
        pix.load(str);
​
        this->setFixedSize(pix.width(),pix.height());
        this->setStyleSheet("QPushButton{border:0px}");
        this->setIcon(pix);
        this->setIconSize(QSize(pix.width(),pix.height()));
​
        //判断 如果翻完了,将min重置为1,并关闭定时器
        if(this->min>this->max)
        {
            this->max=8;
            isAnimation=false;
            timer2->stop();
        }
    });
}
​
void Mycoin::mousePressEvent(QMouseEvent *e)
{
    if(this->isAnimation||this->isWin)
    {
        //如果在做动画,则不能点击
        return;
    }
    else
    {//返回给父类
        QPushButton::mousePressEvent(e);
    }
}
​
​
//改变标志的方法
void Mycoin:: changeFlag()
{
    //如果是正面,则翻成反面,金为正
    if(this->flag)
    {
        //开启正面翻反面的定时器
        timer1->start(30);
        //开始动画效果
        isAnimation=true;
        this->flag=false;
    }
    else//反面翻正面
    {
        //开启反面翻正面的定时器
        timer2->start(30);
        //开始动画效果
        isAnimation=true;
        this->flag=true;
    }
​
}
​

6.项目优化

--场景切换的位置保持一致

主场景与选择关卡场景保持位置一致

选择关卡场景与游戏场景保持位置一致

7.项目打包

1.将左下角的Debug状态修改为Release状态

2.编译

3.打开项目所在文件,找到Release版本的exe文件

资源文件及游戏数据配置文件链接:qt_code: 有关于qt学习中的一些代码与资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值