这是我参考创智学院的教程做的一个小游戏,素材均来自于创智学院。因为我是做嵌入式有快一年了,之前接触的东西都有限,想玩一玩QT,提升一下自己的知识面,觉得这个游戏作为QT入门还是不错,所以将这个项目总结一下。
本来很久之前就决定将自己在入门嵌入式的遇到的一些问题总结出来,总是因为没有时间。以后会陆陆续续的分享一些自己遇到的问题,包括STM32、STM8、ESP8266、硬件设计相关、linux-ARM、QT等相关东西。
自从入坑以来,每天都把自己搞的心力交瘁,不知道自己能坚持多久,但是看到成效之后又因为哪一点小成就感坚持下来,愿你我能成为你想成为的样子。废话不多说,进入正题。
先上图
第一个画面我是用UI来做的,删除状态栏、工具栏,只用添加一个菜单,然后添加一个退出按钮,名字可以随便取非汉字,在text处修改显示
设置主场景
#include "mainscene.h"
#include "ui_mainscene.h"
#include
#include
#include
#include
#include
#include
#include
#include
Mainscene::Mainscene(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Mainscene)
{
ui->setupUi(this);
//配置主场景
//设定固定大小
setFixedSize(320,588);
//设定图标
setWindowIcon(QIcon(":/res/Coin0001.png"));
//设置标题
setWindowTitle("GameMenu");
connect(ui->actionQuit,&QAction::triggered,[=](){
this->close();
});
connect(ui->actionAbout,&QAction::triggered,[=](){
QMessageBox::about(this, "About The Game","游戏介绍:翻金币,全翻为金币则获胜\r\n\r\n每次点击翻动金币,上下左右若存在金币则跟随反转\r\n\r\n QTGame_V0.0 by Shaozi");
});
connect(ui->actionWay,&QAction::triggered,[=](){
if(QMessageBox::Yes==QMessageBox::question(this,"攻略查看","真不行了?要看攻略?",QMessageBox::Yes|QMessageBox::No,QMessageBox::No))
{
QMessageBox::information(this,"XXXXXXX");
}
});
QSound *startSound = new QSound(":/res/TapButtonSound.wav",this);
QSound *Rain = new QSound(":/res/Rain1.wav",this);
Rain->setLoops(-1);
Rain->play();
//开始按钮
MyPushButton * startBtn = new MyPushButton(":/res/MenuSceneStartButton.png");
startBtn->setParent(this);
startBtn->move(this->width()*0.5-startBtn->width()*0.5,this->height()*0.7);
//选择关卡场景
ChooseLevelScene *chooseScene = new ChooseLevelScene;
//监听选择场景的返回按钮
connect(chooseScene,&ChooseLevelScene::chooseSceneBack,[=](){
this->setGeometry(chooseScene->geometry());//记录当前窗口位置
this->show();
});
connect(startBtn,&MyPushButton::clicked,this,[=](){
qDebug()<<"start push";
startSound->play();//播放开始音效
//sky->play();
startBtn->zoom1();
startBtn->zoom2();
//延时0.5秒后 进入选择场景
QTimer::singleShot(500, this,[=](){
chooseScene->setGeometry(this->geometry());
this->hide();
chooseScene->show();
});
});
}
//画图事件函数
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);//将图标缩小0.5倍
painter.drawPixmap(10,30,pix);
}
Mainscene::~Mainscene()
{
delete ui;
}
#include "chooselevelscene.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
ChooseLevelScene::ChooseLevelScene(QWidget *parent) : QMainWindow(parent)
{
//设置窗口固定大小
this->setFixedSize(320,588);
//设置图标
this->setWindowIcon(QPixmap(":/res/Coin0001.png"));
//设置标题
this->setWindowTitle("选择关卡");
//创建菜单栏
QMenuBar * bar = this->menuBar();
this->setMenuBar(bar);
//创建开始菜单
QMenu * startMenu = bar->addMenu("开始");
//创建按钮菜单项
QAction * way = startMenu->addAction("攻略");
startMenu->addSeparator();
QAction * about = startMenu->addAction("关于");
startMenu->addSeparator();
QAction * quitAction = startMenu->addAction("退出");
//点击退出 退出游戏
connect(quitAction,&QAction::triggered,[=](){this->close();});
connect(about,&QAction::triggered,[=](){
QMessageBox::about(this, "About The Game","游戏介绍:翻金币,全翻为金币则获胜\r\n\r\n每次点击翻动金币,上下左右若存在金币则跟随反转\r\n\r\n QTGame_V0.0 by Shaozi");
});
connect(way,&QAction::triggered,[=](){
if(QMessageBox::Yes==QMessageBox::question(this,"攻略查看","真不行了?要看攻略?",QMessageBox::Yes|QMessageBox::No,QMessageBox::No))
{
QMessageBox::information(this,"攻略详情","辣鸡,要攻略没有\r\n\r\n除非打死你虎哥\r\n\r\n呸!!!!!\r\n");
}
});
//返回按钮音效
QSound *backSound = new QSound(":/res/BackButtonSound.wav",this);
//选择关卡按钮音效
QSound *chooseSound = new QSound(":/res/TapButtonSound.wav",this);
//返回按钮
MyPushButton * closeBtn = new MyPushButton(":/res/BackButton.png",":/res/BackButtonSelected.png");
closeBtn->setParent(this);
closeBtn->move(this->width()-closeBtn->width(),this->height()-closeBtn->height());
//点击返回
connect(closeBtn,&MyPushButton::clicked,this,[=](){
qDebug()<<"backbutton ";
backSound->play();
QTimer::singleShot(500, this,[=](){
this->hide();
//触发自定义信号,关闭自身,该信号写到 signals下做声明
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);
//按钮上显示的文字
QLabel * label = new QLabel;
label->setParent(this);
label->setFixedSize(menuBtn->width(),menuBtn->height());
label->setText(QString::number(i+1));
label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); //设置居中
label->move(25 + (i%4)*70 , 130+ (i/4)*70);
label->setAttribute(Qt::WA_TransparentForMouseEvents,true); //鼠标事件穿透
//监听选择关卡按钮的信号槽
connect(menuBtn,&MyPushButton::clicked,[=](){
qDebug() << "select: " << i+1;
chooseSound->play();
this->hide();//隐藏当前
pScene = new PlayScene(i+1); //将选择的关卡号 传入给PlayerScene
pScene->setGeometry(this->geometry());
pScene->show();
connect(pScene,&PlayScene::chooseSceneBack,[=](){
this->setGeometry(pScene->geometry());
this->show();
delete pScene;
pScene = NULL;
});
});
}
}
//鼠标事件
void MyPushButton::mousePressEvent(QMouseEvent *e)
{
if(pressedImgPath != "") //选中路径不为空,显示选中图片
{
QPixmap pixmap;
bool ret = pixmap.load(pressedImgPath);
if(!ret)
{
qDebug() << pressedImgPath << "加载图片失败!";
}
this->setFixedSize( pixmap.width(), pixmap.height() );
this->setStyleSheet("QPushButton{border:0px;}");
this->setIcon(pixmap);
this->setIconSize(QSize(pixmap.width(),pixmap.height()));
}
//交给父类执行按下事件
return QPushButton::mousePressEvent(e);
}
void MyPushButton::mouseReleaseEvent(QMouseEvent *e)
{
if(normalImgPath != "") //选中路径不为空,显示选中图片
{
QPixmap pixmap;
bool ret = pixmap.load(normalImgPath);
if(!ret)
{
qDebug() << normalImgPath << "加载图片失败!";
}
this->setFixedSize( pixmap.width(), pixmap.height() );
this->setStyleSheet("QPushButton{border:0px;}");
this->setIcon(pixmap);
this->setIconSize(QSize(pixmap.width(),pixmap.height()));
}
//交给父类执行 释放事件
return QPushButton::mouseReleaseEvent(e);
}
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( (this->width() - pix.width())*0.5,30,pix.width(),pix.height(),pix);
}
ChooseLevelScene::~ChooseLevelScene()
{
}
游戏介绍:翻金币,全翻为金币则获胜
每次点击翻动金币,上下左右若存在金币则跟随反转
#include “playscene.h”
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//PlayScene::PlayScene(QWidget *parent) : QMainWindow(parent)
//{
//}
PlayScene::~PlayScene()
{
}
PlayScene::PlayScene(int index)
{
qDebug() << “当前关卡为”<< index;
this->levalIndex = index;
//设置窗口固定大小
this->setFixedSize(320,588);
//设置图标
this->setWindowIcon(QPixmap(":/res/Coin0001.png"));
//设置标题
this->setWindowTitle(“翻金币”);
//创建菜单栏
QMenuBar * bar = this->menuBar();
this->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 * closeBtn = new MyPushButton(":/res/BackButton.png",":/res/BackButtonSelected.png");
closeBtn->setParent(this);
closeBtn->move(this->width()-closeBtn->width(),this->height()-closeBtn->height());
//返回按钮功能实现
connect(closeBtn,&MyPushButton::clicked,[=](){
qDebug()<<"play中的返回按钮";
backSound->play();
QTimer::singleShot(500, this,[=](){
this->hide();
//触发自定义信号,关闭自身,该信号写到 signals下做声明
emit this->chooseSceneBack();
});
});
//当前关卡标题
QLabel * label = new QLabel;
label->setParent(this);
QFont font;
font.setFamily("华文新魏");
font.setPointSize(16);
label->setFont(font);
QString str = QString("Leavel: %1").arg(this->levalIndex);
label->setText(str);
label->setGeometry(QRect(30, this->height() - 50,120, 50)); //设置大小和位置
//初始化二维数组
dataConfig config;
for(int i = 0 ; i < 4;i++)
{
for(int j = 0 ; j < 4; j++)
{
gameArray[i][j] = config.mData[this->levalIndex][i][j];
}
}
//创建胜利的图片,注意Y坐标为-,胜利之后才会将胜利图片移下来
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++)
{
//绘制背景图片
QPixmap pix = QPixmap(":/res/BoardNode(1).png");
QLabel* label = new QLabel;
label->setGeometry(0,0,pix.width(),pix.height());
label->setPixmap(pix);
label->setParent(this);
label->move(57 + i*50,200+j*50);
//金币对象
QString img;
if(gameArray[i][j] == 1)
{
img = ":/res/Coin0001.png";
}
else
{
img = ":/res/Coin0008.png";
}
//金币对象,根据数组来设置图片
MyCoin * coin = new MyCoin(img);
coin->setParent(this);
coin->move(59 + i*50,204+j*50);
//给每个金币赋值
coin->posX = i; //记录x坐标
coin->posY = j; //记录y坐标
coin->flag =gameArray[i][j]; //记录正反标志
coinBtn[i][j] = coin;//将金币放到维护二维数组中
connect(coin,&MyCoin::clicked,[=](){
//qDebug() << "点击的位置: x = " << coin->posX << " y = " << coin->posY ;
flipSound->play();
for(int i = 0 ; i < 4;i++) //bug修复:在胜利的瞬间点其他按钮,会有效。点击之后禁用所有按钮
{
for(int j = 0 ; j < 4; j++)
{
coinBtn[i][j]->isWin = true;
}
}
coin->changeFlag();
gameArray[i][j] = gameArray[i][j] == 0 ? 1 : 0; //数组内部记录的标志同步修改
QTimer::singleShot(300, this,[=](){
if(coin->posX+1 <=3)//翻右侧金币
{
coinBtn[coin->posX+1][coin->posY]->changeFlag();
gameArray[coin->posX+1][coin->posY] = gameArray[coin->posX+1][coin->posY]== 0 ? 1 : 0;
}
if(coin->posX-1>=0)//翻左侧金币
{
coinBtn[coin->posX-1][coin->posY]->changeFlag();
gameArray[coin->posX-1][coin->posY] = gameArray[coin->posX-1][coin->posY]== 0 ? 1 : 0;
}
if(coin->posY+1<=3)//翻下侧金币
{
coinBtn[coin->posX][coin->posY+1]->changeFlag();
gameArray[coin->posX][coin->posY+1] = gameArray[coin->posX+1][coin->posY]== 0 ? 1 : 0;
}
if(coin->posY-1>=0)//翻上侧金币
{
coinBtn[coin->posX][coin->posY-1]->changeFlag();
gameArray[coin->posX][coin->posY-1] = gameArray[coin->posX+1][coin->posY]== 0 ? 1 : 0;
}
//金币翻完了再解开矩阵
for(int i = 0 ; i < 4;i++)
{
for(int j = 0 ; j < 4; j++)
{
coinBtn[i][j]->isWin = false;
}
}
//判断是否胜利
this->isWin=true;//这个是playscene下的对象
for(int i = 0 ; i < 4;i++)
{
for(int j = 0 ; j < 4; j++)
{
//qDebug() << coinBtn[i][j]->flag ;
if( coinBtn[i][j]->flag == false)
{
this->isWin = false;
break;
}
}
}
if(this->isWin)
{
qDebug() << "胜利";
winSound->play();
//禁用所有按钮点击事件
for(int i = 0 ; i < 4;i++)
{
for(int j = 0 ; j < 4; j++)
{
coinBtn[i][j]->isWin = true;
}
}
QPropertyAnimation * animation1 = new QPropertyAnimation(winLabel,"geometry");
animation1->setDuration(1000);
animation1->setStartValue(QRect(winLabel->x(),winLabel->y(),winLabel->width(),winLabel->height()));
animation1->setEndValue(QRect(winLabel->x(),winLabel->y()+114,winLabel->width(),winLabel->height()));
animation1->setEasingCurve(QEasingCurve::OutBounce);
animation1->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.width(),pix.height(),pix);
}
另外,我们还创建了两个QWidget的类,一个用来封装按钮,一个用来封装每一个金币的属性
自己本来打算添加mp3作为背景音乐,但是需要添加multimedia以及对应的头文件,但是使用的时候发现需要安装一个解码器LAV,但是我安装了任然播放不了,就只有将格式转化成wav,然而转化最后文件太大了,运行时内存溢出,只好剪辑一下。
PS:如果有遇到以上问题并解决的朋友,希望能分享一下
算了,第一次写文章,差不多就算介绍了一下,还是直接
链接:https://pan.baidu.com/s/1SkF6SlryEKFeeDMyeRZJOA
提取码:79mn
github连接