1、项目简介
制作简易翻金币小游戏
2、创建项目并添加项目资源
2.1 创建项目
-》选择“Qt Widget Application”-》确定项目名称(MainSence)及位置-》选择相应的基类(QMainWindow)以类名。
2.2 添加项目资源
-》
(先添加前缀,再添加文件,最后保存。)
3、项目的基本配置
3.1设置背景图标
//设置图标
setWindowIcon(QIcon(":/res/Coin0001.png"));
3.2设置固定大小
//设置固定大小
setFixedSize(320, 588);
3.3 设置项目标题
setWindowTitle("翻金币主场景");
3.4 设置背景及背景标题
重载QPaintEvent事件
void MainScene::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(20,40,pix);
}
3.5 创建开始菜单以退出功能
在.ui文件中创建开始菜单,并设置退出功能(actionquit)
//退出按钮实现
connect(ui.actionquit, &QAction::triggered, [=]() {
this->close();
});
4、构造MyPushButton按钮
提供MyPushButton的构造的重载版本,可以让MyPushButton提供正常的图片以及按下后显示的图片
右键项目-》添加-》新建项-》Qt Class类
MyPushButton.h
//重写构造函数 参数1:正常显示的图片路径 ,参数2:按下后显示的图片路径
MyPushButton(QString normalImg, QString pressImg = "");
//成员属性 保存用户传入的默认显示路径以及按下后显示的图片路径
QString normalImgPath;
QString pressImgPath;
MyPushButton.cpp
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()));
}
zoom1和zoom2为MyPushButton的特效
zoom1与zoom2代码相似,更改起始位置
void MyPushButton::zoom1()//向下跳
{
//创建动态对象
QPropertyAnimation * animation = new QPropertyAnimation(this, "geometry");
//设置动画间隔
animation->setDuration(200);
//起始位置
animation->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
//结束位置
animation->setStartValue(QRect(this->x(), this->y()+10, this->width(), this->height()));
//设置弹跳曲线
animation->setEasingCurve(QEasingCurve::OutBounce);
//执行动画
animation->start();
}
5、选择关卡场景基本配置
创建选择关卡场景(Qt Widget Class),基类为(QMainWindow),同主窗口配置相似
.cpp
ChooseLevelScence::ChooseLevelScence(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
//设置固定大小
setFixedSize(320, 588);
//设置图标
setWindowIcon(QIcon(":/res/Coin0001.png"));
setWindowTitle("选择关卡场景");
//退出按钮实现
connect(ui.actionquit, &QAction::triggered, [=]() {
this->close();
});
//返回按钮
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, [=]() {
});
}
void ChooseLevelScence::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(20, 40, pix);
}
6、选择关卡的返回按钮特效制作
6.1 点击后切换另一个图片
重载mousePressEvent、mouseReleaseEvent事件
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->pressImgPath != "")//传入的按下图片不为空 说明需要有按下状态 切换成初始图片
{
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);
}
6.2 功能实现(点击返回按钮,返回主窗口)
.h
signals:
//写一个自定义信号,告诉主场景 点击了返回
void chooseSceneBack();
.cpp
//点击返回
connect(backBtn, &MyPushButton::clicked, [=]() {
//告诉主场景 我返回了,主场景监听信号
emit this->chooseSceneBack();
});
6.3 选择关卡按钮创建
//创建选择关卡的按钮
for (int i = 0; i < 20; i++)
{
MyPushButton* memuBtn = new MyPushButton(":/res/LevelIcon.png");
memuBtn->setParent(this);
memuBtn->move(25 + i % 4 * 70, 130 + i / 4 * 70);
QLabel* label = new QLabel(this);
label->setFixedSize(memuBtn->width(), memuBtn->height());
label->setText(QString::number(1 + i));
label->move(25 + i % 4 * 70, 130 + i / 4 * 70);
//设置label上的文字对齐方式(水平居中和垂直居中)
label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
//设置让鼠标穿透事件
label->setAttribute(Qt::WA_TransparentForMouseEvents);
}
7、创建翻金币场景
点击关卡按钮后,会进入游戏的核心场景,也就是翻金币的场景,首先创建出该场景的.h和.cpp文件
创建PlayScence:右键项目-》添加-》新建项-》Qt Class类
7.1 重写PlayScene的构造函数
Playscene::Playscene(int levelNum)
{
this->levelIndex = levelNum;
//初始化游戏场景
//设置固定大小
setFixedSize(320, 588);
//设置图标
setWindowIcon(QIcon(":/res/Coin0001.png"));
setWindowTitle("游戏场景");
//创建菜单栏
QMenuBar* bar = menuBar();
setMenuBar(bar);
//创建开始菜单
QMenu* startMenu = bar->addMenu("开始");
//创建退出 菜单项
QAction* quitAction = startMenu->addAction("退出");
//点击退出 实现退出游戏
connect(quitAction, &QAction::triggered, [=]() {
this->close();
});
//返回按钮
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, [=]() {
//告诉主场景 我返回了,主场景监听信号
emit this->playSceneBack();
});
//显示当前关卡数
QLabel* label = new QLabel(this);
QFont font;
font.setFamily("华文新魏");
font.setPointSize(20);
QString str = QString("Level:%1").arg(this->levelIndex);
//将字体设置到标签控件中
label->setFont(font);
label->setText(str);
label->setGeometry(30, this->height() - 50, 120, 50);
//显示金币背景图案
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(57 + i * 50, 200 + j * 50);
}
}
}
重写绘图事件与主窗口类似.
7.2 创建金币类(MyCoin)
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()));
}
7.2.1 在游戏窗口中显示金币
//创建金币
MyCoin* coin = new MyCoin(":/res/Coin0001.png");
coin->setParent(this);
coin->move(59 + i * 50, 204 + j * 50);
7.2.2 进入关卡数据
添加现有文件dataconfig.cpp,dataconfig.h
初始化各个关卡:
(1)在playScence中声明一个成员变量,记录当前关卡的二维数据
int gameArray[4][4];//二维数组 维护每个关卡的具体数据
(2)初始化每个关卡的二维数组
//初始化每个关卡的二维数组
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
this->gameArray[i][j] = config.mData[this->levelIndex][i][j];
}
}
(3)金币翻转特效实现
添加金币属性,定位金币的位置
//金币的属性
int posX;//x坐标位置
int posY;//y坐标位置
bool flag;//正反标志
//给金币属性赋值
coin->posX = i;
coin->posY = j;
coin->flag = this->gameArray[i][j];//1正面,0反面
单个金币翻转实现:
在MyCoin.h中声明:
//改变标志的方法
void changeFlag();
QTimer timer1;//正面翻反面的定时器
QTimer timer2;//反面翻正面的定时器
int min = 1;
int max = 8;
方法实现,MyCoin.cpp中
void MyCoin::changeFlag()
{
//如果是正面 翻成反面
if (this->flag)
{
//开始正面翻反面的定时器
timer1->start(30);
this->flag = false;
}
else
{
timer2->start(30);
this->flag = true;
}
}
//初始化定时器对象
timer1 = new QTimer(this);
timer2 = new QTimer(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)
{
this->min = 1;
timer1->stop();
}
});
//监听反面翻正面的信号,并且反转金币
connect(timer2, &QTimer::timeout, [=]() {
QPixmap pix;
QString str = QString(":/res/Coin000%1").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->max< this->min)
{
this->max = 8;
timer2->stop();
}
});
周围金币翻转实现:
//将金币放到金币的二维数组里 以便于后期的维护
coinBtn[i][j] = coin;
//点击金币翻转
connect(coin, &MyCoin::clicked, [=]() {
coin->changeFlag();
this->gameArray[i][j] == this->gameArray[i][j] == 0 ? 1 : 0;
//翻转周围金币
//右侧金币的翻转
if (coin->posX + 1 <= 3)
{
coinBtn[coin->posX + 1][coin->posY]->changeFlag();
this->gameArray[coin->posX + 1][coin->posY] == this->gameArray[i][j] == 0 ? 1 : 0;
}
//左侧金币翻转
if (coin->posX- 1 >= 0)
{
coinBtn[coin->posX - 1][coin->posY]->changeFlag();
this->gameArray[coin->posX - 1][coin->posY] == this->gameArray[i][j] == 0 ? 1 : 0;
}
//上侧金币翻转
if (coin->posY + 1 <= 3)
{
coinBtn[coin->posX ][coin->posY+1]->changeFlag();
this->gameArray[coin->posX ][coin->posY+1] == this->gameArray[i][j] == 0 ? 1 : 0;
}
//下侧金币翻转
if (coin->posY - 1 >= 0)
{
coinBtn[coin->posX][coin->posY - 1]->changeFlag();
this->gameArray[coin->posX][coin->posY - 1] == this->gameArray[i][j] == 0 ? 1 : 0;
}
});
判断胜利
在MyCoin.h中加入isWin标志,代表是否胜利
//判断是否胜利
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)
{
//将所有按钮的胜利标志改为true
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
coinBtn[i][j]->isWin = true;
}
}