前言
事情的起因需要从一只蝙蝠说起,那是2020年过年时,没有携带所有娱乐性工具的我回到老家后,经过麻将、电影、电视的洗礼,终于掏出来mac想学习一下c++。
c++基础学完后,发现了Qt这门语言,经过了解是一门c++编写的跨平台桌面程序开发的框架,就继续进行学习观看,这个demo也是Qt教学视频中的老师最后带着一起完成的翻金币小游戏,日常生活中我从事的方向时J2EE方向,并不是过多的使用到学习到的东西,记录到简书中便于以后观看查阅。
视频学习网站:B站
视频路径:B站-Qt学习视频
*素材是在评论中翻找好多以后某位大哥的,很多链接都失效了
*如有侵权,请联系我进行删除及修改
个人建议有兴趣的同学最好还是自己来一遍,如果实在敲的过程中有问题,也可以去我Github下载成品的所有代码。Github地址
在学习的最后老师也提到过新加一些功能,我要立一个Flag:在闲暇的时候也会对这个成品进行一定程度的优化和修改。
1.代码结构说明
项目结构
主窗体-mainscene
选择关卡-chooseselevelscene
翻金币-playscene
金币封装-mycoin
关卡数据封装-dataconfig
自定义按钮类-mypushbutton
2.难点记录
01.跳转设置新窗打开位置属性
跳转时设置新窗体的geometry属性和本窗体相同,这样设置会解决窗体移动过后,打开的新窗体和旧窗体位置不同的bug;
02.创建新窗体,初始化属性
//设置固定大小,并且让窗体无法被更改
setFixedSize(320, 588);
//设置应用图标
setWindowIcon(QPixmap(":/res/Coin0001.png"));
//设置窗口标题
setWindowTitle("选择关卡");
//设置菜单栏
QMenuBar * qMenuBar = menuBar();
QAction * qAction = qMenuBar->addMenu("开始")->addAction("退出");
this->setMenuBar(qMenuBar);
//点击退出完成程序退出
connect(qAction , &QAction::triggered, [=](){
this->close();
});
重写窗体的画家事件,绘制窗体的背景图
void ChooseLevelScene::paintEvent(QPaintEvent *event)
{
//绘制背景图
QPainter qPainter(this);
QPixmap qPixmap;
qPixmap.load(":/res/PlayLevelSceneBg.png");
//绘制背景图
qPainter.drawPixmap(0,0,this->width(),this->height(),qPixmap);
//绘制左上角游戏名称
qPixmap.load(":/res/Title.png");
qPainter.drawPixmap(20,30,qPixmap.width(),qPixmap.height(),qPixmap);
}
03.定时器QTimer使用
Qt的定时器实现有两种,一个是重写定时事件(没使用过不清楚),另一个就是使用QTimer的静态方法:
//500是延迟多少时间执行代码,单位是毫秒
//[=](){ ... } Lamda表达式(很屌,推荐学习而且使用不难)
QTimer::singleShot(500, this, [=](){
//operator code
});
04.事件穿透设置上下对齐居中
选择关卡时绘制关卡是通过自定义按钮MyPushButton进行绘制,显示关卡名称是通过QLabel相同大小覆盖在自定义按钮上。
此时点击时无法触发自定义按钮上选择关卡后的操作,可使用鼠标点击事件穿透设置到QLabel上,label->setAttribute(Qt::WA_TransparentForMouseEvents);这时鼠标点击后QLabel不会阻拦点击事件,可以正常触发自定义按钮。
在QLabel中设置text后默认时居左,设置上下左右对齐居中,label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
05.设置开始游戏按钮的点击下沉弹回的动画
//图标下沉
void MyPushButton::zoom1()
{
QPropertyAnimation * animation1 = new QPropertyAnimation(this, "geometry");
//设置事件间隔
animation1->setDuration(200);
//设置起始位置
animation1->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
animation1->setEndValue(QRect(this->x(), this->y()+10, this->width(), this->height()));
//设置动画,弹跳式,类似弹性球
animation1->setEasingCurve(QEasingCurve::OutBounce);
animation1->start();
}
//图标上浮
void MyPushButton::zoom2()
{
QPropertyAnimation * animation1 = new QPropertyAnimation(this, "geometry");
//设置事件间隔
animation1->setDuration(200);
//设置起始位置
animation1->setStartValue(QRect(this->x(), this->y()+10, this->width(), this->height()));
animation1->setEndValue(QRect(this->x(), this->y(), this->width(), this->height()));
//设置动画,弹跳式,类似弹性球
animation1->setEasingCurve(QEasingCurve::OutBounce);
animation1->start();
}
//给start按钮绑定点击事件
connect(btn_start, &QPushButton::clicked, [=](){
btn_start->zoom1();
btn_start->zoom2();
//点击音效
startSound->play();
//延时0.5秒执行切换,展示start按钮的动效
QTimer::singleShot(500, this, [=](){
chooseLevel->setGeometry(this->geometry());
this->hide();
chooseLevel->show();
});
});
06.绘制一个4*4的选择关卡矩阵,不使用双层for循环的前提下,一个for循环完成绘制
//创建关卡选择icon
for(int i = 0; i < 20 ; i++)
{
MyPushButton * levelIcon = new MyPushButton(":/res/LevelIcon.png");
levelIcon->setParent(this);
levelIcon->move(25 + (i%4)*70 , 160 + (i/4)*70);
}
* x轴:25 + (i%4)*70 25为偏移量,70是每个矩阵x轴大小,i%4在第一行0、1、2、3四列,每一行计算的值是0*70、1*70、2*70、3*70;
*y轴:160 + (i/4)*70 160为偏移量,70是每个矩阵y轴大小,i/4在第一列0、1、2、3四行,每一行计算的值是0*70、1*70、2*70、3*70;
*在记录其中每一个金币的坐标时,构建了新的二维数组保存位置信息,因为这种构建不太好保存位置信息