项目描述
点击硬币,实现其周围硬币的翻转,最后使页面中全显示为金币
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对象
-
QString str2 =QString("Level:%1").arg(this->levelIndex)
-
为标签指定其字体的大小的类型
-
label设置文字
-
通过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学习中的一些代码与资料