mypushbutton.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 presslImgPath;
// 弹跳特性
void zoom1(); // 向下跳
void zoom2(); // 向上跳
// 重写按钮的按下和释放
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
signals:
public slots:
};
#endif // MYPUSHBUTTON_H
mypushbutton.cpp文件
#include "mypushbutton.h"
#include <QDebug>
#include <QPropertyAnimation>
//MyPushButton::MyPushButton(QWidget *parent) : QPushButton(parent)
//{
//}
MyPushButton::MyPushButton(QString normalImg, QString pressImg)
{
this->normalImgPath = normalImg;
this->presslImgPath = 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()));
}
// 向下跳
void MyPushButton::zoom1()
{
// 创建动态对象
QPropertyAnimation * animation = new QPropertyAnimation(this, "geometry");
// 设置动画的时间间隔
animation->setDuration(200);
// 起始位置
animation->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
// 结束位置
animation->setEndValue(QRect(this->x(), this->y() + 10, this->width(), this->height()));
// 设置弹跳曲线
animation->setEasingCurve(QEasingCurve::OutBounce);
// 执行动画
animation->start();
}
// 向上跳
void MyPushButton::zoom2()
{
// 创建动态对象
QPropertyAnimation * animation = new QPropertyAnimation(this, "geometry");
// 设置动画的时间间隔
animation->setDuration(200);
// 起始位置
animation->setStartValue(QRect(this->x(), this->y() + 10, 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->presslImgPath != "") // 传入的按下图片不为空 说明需要有按下状态,切换图片
{
QPixmap pix;
bool ret = pix.load(this->presslImgPath);
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->presslImgPath != "") // 传入的按下图片不为空 说明需要有按下状态,切换成初始图片
{
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);
}
mainscene.h文件
#ifndef MAINSCENE_H
#define MAINSCENE_H
#include <QMainWindow>
#include "chooselevelscene.h"
namespace Ui {
class MainScene;
}
class MainScene : public QMainWindow
{
Q_OBJECT
public:
explicit MainScene(QWidget *parent = 0);
~MainScene();
// 重现paintEvent事件 画背景图
void paintEvent(QPaintEvent *event);
ChooseLevelScene * chooseScene = NULL;
private:
Ui::MainScene *ui;
};
#endif // MAINSCENE_H
mainscene.cpp文件
#include "mainscene.h"
#include "ui_mainscene.h"
#include "mypushbutton.h"
#include <QPainter>
#include <QDebug>
#include <QTimer>
#include <QSound> // 多媒体模块下的头文件
MainScene::MainScene(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainScene)
{
ui->setupUi(this);
// 配置主场景
// 设置固定大小
setFixedSize(320, 588);
// 设置图标
setWindowIcon(QIcon(":/res/Coin0001.png"));
// 设置标题
setWindowTitle("翻金币主场景");
// 退出按钮实现
connect(ui->actionquit, &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, this, [=](){
// 设置chooseScene返回的场景位置
this->setGeometry(chooseScene->geometry());
// 隐藏关卡
chooseScene->hide();
// 重新显示主场景
this->show();
});
connect(startBtn, &MyPushButton::clicked, [=](){
qDebug() << "点击了开始";
// 播放开始音效资源
startSound->play();
// 做弹起的特效
startBtn->zoom1();
startBtn->zoom2();
// 延时进入选择关卡场景中
QTimer::singleShot(500, this, [=](){
// 设置chooseScene去的场景位置
chooseScene->setGeometry(this->geometry());
// 将自身隐藏掉
this->hide();
// 显示选择关卡场景
chooseScene->show();
});
});
}
// 创建画家,指定绘图设备
// 重现paintEvent事件 画背景图
void MainScene::paintEvent(QPaintEvent *event)
{
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);
}
MainScene::~MainScene()
{
delete ui;
}
chooselevelscene.h文件
#ifndef CHOOSELEVELSCENE_H
#define CHOOSELEVELSCENE_H
#include <QMainWindow>
#include "playscene.h"
class ChooseLevelScene : public QMainWindow
{
Q_OBJECT
public:
explicit ChooseLevelScene(QWidget *parent = nullptr);
// 重写paintEvent事件 画背景图
void paintEvent(QPaintEvent *event);
// 游戏场景对象指针
PlayScene * play = NULL;
signals:
// 写一个自定义信号,告诉主场景点击了返回
void chooseSceneBack();
public slots:
};
#endif // CHOOSELEVELSCENE_H
chooselevelscene.cpp文件
#include "chooselevelscene.h"
#include <QMenuBar>
#include <QPainter>
#include <QDebug>
#include <QTimer>
#include <QLabel>
#include "mypushbutton.h"
#include <QSound> // 多媒体模块下的头文件
ChooseLevelScene::ChooseLevelScene(QWidget *parent) : QMainWindow(parent)
{
// 配置选择关卡场景
this->setFixedSize(320, 588);
// 设置图标
this->setWindowIcon(QPixmap(":/res/Coin0001.png"));
// 设置标题
this->setWindowTitle("选择关卡");
// 创建菜单栏
QMenuBar * bar = menuBar();
setMenuBar(bar);
// 创建开始菜单
QMenu * startMenu = bar->addMenu("开始");
// 创建退出菜单项
QAction * quitAction = startMenu->addAction("退出");
connect(quitAction, &QAction::triggered, [=](){
this->close();
});
// 准备关卡按钮的音效
QSound * startSound = 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, [=](){
// 返回按钮音效
backSound->play();
qDebug() << "点击了返回";
// 告诉主场景 返回了,主场景监听chooseSceneBack的返回按钮
// 延时返回
QTimer::singleShot(200, this, [=](){
emit this->chooseSceneBack();
});
});
// 创建选择关卡按钮
for(int i=0; i<20; i++) {
MyPushButton * menuBtn = new MyPushButton(":/res/LevelIcon.png");
menuBtn->setParent(this);
menuBtn->move(25 + i%4 * 70, 130 + i/4 * 70);
// 监听每个按钮的点击事件
connect(menuBtn, &MyPushButton::clicked, [=](){
QString str = QString("你选择的是第 %1 关").arg(i+1);
qDebug() << str;
// 音效
startSound->play();
// 进入到游戏场景
this->hide(); // 将选关场景隐藏掉
play = new PlayScene(i+1);
// 设置游戏场景的初始位置
play->setGeometry(this->geometry());
play->show(); // 显示游戏场景
connect(play, &PlayScene::playSceneBack, this, [=](){
this->setGeometry(play->geometry());
// 重新显示关卡场景
this->show();
// 销毁退出的关卡场景
delete play;
play = NULL;
});
});
// 使用label添加数字
QLabel * label = new QLabel;
label->setParent(this);
label->setFixedSize(menuBtn->width(), menuBtn->height());
label->setText(QString::number(i+1));
label->move(25 + i%4 * 70, 130 + i/4 * 70);
// 设置label上的文字对其方式 水平居中和垂直居中
label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
// 设置让鼠标进行穿透label
label->setAttribute(Qt::WA_TransparentForMouseEvents);
}
}
void ChooseLevelScene::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPixmap pix;
pix.load(":/res/OtherSceneBg.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((this->width() - pix.width()) * 0.5, 30, pix.width(), pix.height(), pix);
}
mycoin.h
#ifndef MYCOIN_H
#define MYCOIN_H
#include <QPushButton>
#include <QTimer>
class MyCoin : public QPushButton
{
Q_OBJECT
public:
// explicit MyCoin(QWidget *parent = nullptr);
// 参数代表传入的金币路径还是银币路径
MyCoin(QString btnImg);
// 金币是的属性
int posX; // x坐标位置
int posY; // y坐标位置
bool flag; // 正反标志
// 改变标志的方法
void changeFlag();
QTimer * timer1; // 正面翻反面的定时器
QTimer * timer2; // 反面翻正面的定时器
int min = 1;
int max = 8;
// 执行动画的标志
bool isAnimation = false;
// 是否胜利标志
bool isWin = false;
signals:
public slots:
};
#endif // MYCOIN_H
mycoin.cpp
#include "mycoin.h"
#include <QDebug>
#include <QSound>
//MyCoin::MyCoin(QWidget *parent) : QWidget(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);
// 点击金币音效
QSound * flipSound = new QSound(":/res/ConFlipSound.wav", this);
// 监听正面翻反面信号,并且翻转金币
connect(timer1, &QTimer::timeout, [=](){
QPixmap pix;
QString str = QString(":/res/Coin000%1").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)
{
// // 开始点击金币音效
// flipSound->play();
this->min = 1;
isAnimation = false; // 停止做动画了
timer1->stop();
}
});
// 监听反面翻正面信号,并且翻转金币
connect(timer2, &QTimer::timeout, [=](){
QPixmap pix;
QString str2 = QString(":/res/Coin000%1").arg(this->max--);
pix.load(str2);
//
this->setFixedSize(pix.width(), pix.height());
this->setStyleSheet("QPushButton{border:0px;}");
this->setIcon(pix);
this->setIconSize(QSize(pix.width(),pix.height()));
// 判断如果翻完了, 将max重置为8
if(this->min > this->max)
{
// // 开始点击金币音效
// flipSound->play();
this->max = 8;
isAnimation = false; // 停止做动画了
timer2->stop();
}
});
}
// 正反面标志的方法
void MyCoin::changeFlag()
{
// 点击金币音效
QSound * flipSound = new QSound(":/res/ConFlipSound.wav", this);
if(!this->isAnimation && !this->isWin)
{
// 开始点击金币音效
flipSound->play();
qDebug() << "zc";
if(this->flag)
{
// 如果是正面 翻成反面
timer1->start(30);
isAnimation = true; // 开始做动画了
this->flag = false;
}else{
// 如果是正面 翻成反面
timer2->start(30);
isAnimation = true; // 开始做动画了
this->flag = true;
}
}
}
playscene.h
#ifndef PLAYSCENE_H
#define PLAYSCENE_H
#include <QMainWindow>
#include "mycoin.h"
class PlayScene : public QMainWindow
{
Q_OBJECT
public:
// explicit PlayScene(QWidget *parent = nullptr);
PlayScene(int levelNum);
int levelIndex; // 内部成员属性,记录所选关卡
// 重现paintEvent事件 画背景图
void paintEvent(QPaintEvent *event);
int gameArray[4][4]; // 二维数组 维护每个关卡的具体数据
// 二维数组 维护每个关卡的具体数据
MyCoin * coinBtn[4][4];
// 是否胜利标志
bool isWin = false;
//
bool isSucc = false;
signals:
// 写一个自定义信号,告诉关卡场景点击了返回
void playSceneBack();
public slots:
};
#endif // PLAYSCENE_H
playscene.h
#include "playscene.h"
#include <QDebug>
#include <QMenuBar>
#include <QTimer>
#include <QPainter>
#include <QLabel>
#include <QFont>
#include "mypushbutton.h"
#include "mycoin.h"
#include "dataconfig.h"
#include <QPropertyAnimation>
#include <QSound>
//PlayScene::PlayScene(QWidget *parent) : QMainWindow(parent)
//{
//}
PlayScene::PlayScene(int levelNum)
{
QString str = QString("进入了第 %1 关").arg(levelNum);
qDebug() << str;
// 将传进来的关卡数值进行存储到当前作用域中
this->levelIndex = levelNum;
// 初始化游戏场景
// 设置固定大小
this->setFixedSize(320, 588);
// 设置图标
this->setWindowIcon(QPixmap(":/res/Coin0001.png"));
// 设置标题
this->setWindowTitle(str);
// 创建菜单栏
QMenuBar * bar = menuBar();
setMenuBar(bar);
// 创建开始菜单
QMenu * startMenu = bar->addMenu("开始");
// 创建退出菜单项
QAction * quitAction = startMenu->addAction("退出");
// 点击退出 实现退出游戏
connect(quitAction, &QAction::triggered, [=](){
this->close();
});
// 返回按钮的音效
QSound * backSound = new QSound(":/res/BackButtonSound.wav", this);
// // 点击金币音效
// QSound * flipSound = 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, [=](){
// // 返回按钮音效
backSound->play();
qDebug() << "点击了返回";
// 告诉选关场景 返回了,主场景监听playSceneBack的返回按钮
// 延时返回
QTimer::singleShot(200, this, [=](){
emit this->playSceneBack();
});
});
// 显示当前关卡
QLabel * label = new QLabel;
label->setParent(this);
label->setFixedSize(150, 50);
label->setFont(QFont("华文新魏", 20));
QString str2 = QString("Leavel: %1").arg(levelIndex);
label->setText(str2);
label->move(20, this->height()-40);
// 初始化每个关卡的二维数组
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 tmpPix;
tmpPix.load(":/res/LevelCompletedDialogBg.png");
winLabel->setGeometry(0, 0, tmpPix.width(), tmpPix.height());
winLabel->setPixmap(tmpPix);
winLabel->setParent(this);
winLabel->move((this->width() - tmpPix.width())*0.5, -tmpPix.height());
// 显示金币的背景图案
for(int i=0; i<4; i++)
{
for(int j = 0; j<4; j++) {
// 绘制金币背景图
QLabel * label2 = new QLabel;
label2->setGeometry(0, 0, 50, 50);
label2->setPixmap(QPixmap(":/res/BoardNode(1).png"));
label2->setParent(this);
label2->move(57 + 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(59 + i*50, 204+j*50);
// 给金币属性赋值
coin->posX = i;
coin->posY = j;
coin->flag = this->gameArray[i][j]; // 1正面,0反面
// 将金币放入金币的二维数组中,以便后期的维护
coinBtn[i][j] = coin;
// 点击金币 进行翻转
connect(coin, &MyCoin::clicked, [=](){
coin->changeFlag();
this->gameArray[i][j] = this->gameArray[i][j] == 0 ? 1 : 0;
// 翻转周围金币
// 右侧
QTimer::singleShot(200, this, [=](){
if(coin->posX + 1 <= 3)
{
qDebug() << coin->posX;
coinBtn[coin->posX + 1][coin->posY]->changeFlag();
this->gameArray[coin->posX + 1][coin->posY] = this->gameArray[coin->posX + 1][coin->posY] == 0 ? 1 : 0;
}
// 左侧
if(coin->posX - 1 >= 0)
{
qDebug() << coin->posX;
coinBtn[coin->posX - 1][coin->posY]->changeFlag();
this->gameArray[coin->posX - 1][coin->posY] = this->gameArray[coin->posX - 1][coin->posY] == 0 ? 1 : 0;
}
// 上侧
if(coin->posY + 1 <= 3)
{
qDebug() << coin->posY;
coinBtn[coin->posX][coin->posY + 1]->changeFlag();
this->gameArray[coin->posX][coin->posY + 1] = this->gameArray[coin->posX][coin->posY + 1] == 0 ? 1 : 0;
}
// 下侧
if(coin->posY - 1 >= 0)
{
qDebug() << coin->posY;
coinBtn[coin->posX][coin->posY - 1]->changeFlag();
this->gameArray[coin->posX][coin->posY - 1] = this->gameArray[coin->posX][coin->posY - 1] == 0 ? 1 : 0;
}
// 判断是否胜利
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 && !this->isSucc)
{
// 胜利了
//胜利音效
winSound->play();
qDebug() << "游戏胜利";
this->isSucc = true;
// 将所有按钮的胜利标志改为true
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();
}
});
});
}
}
}
// 创建画家,指定绘图设备
// 重现paintEvent事件 画背景图
void PlayScene::paintEvent(QPaintEvent *event)
{
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);
}
