前言
? ? 事情的起因需要從一只蝙蝠說起原叮,那是2020年過年時(shí),沒有攜帶所有娛樂性工具的我回到老家后,經(jīng)過麻將奋隶、電影擂送、電視的洗禮,終于掏出來mac想學(xué)習(xí)一下c++唯欣。
? ? c++基礎(chǔ)學(xué)完后嘹吨,發(fā)現(xiàn)了Qt這門語言,經(jīng)過了解是一門c++編寫的跨平臺(tái)桌面程序開發(fā)的框架境氢,就繼續(xù)進(jìn)行學(xué)習(xí)觀看蟀拷,這個(gè)demo也是Qt教學(xué)視頻中的老師最后帶著一起完成的翻金幣小游戲,日常生活中我從事的方向時(shí)J2EE方向萍聊,并不是過多的使用到學(xué)習(xí)到的東西问芬,記錄到簡(jiǎn)書中便于以后觀看查閱。
? ? 視頻學(xué)習(xí)網(wǎng)站:B站
? ? 視頻路徑:B站-Qt學(xué)習(xí)視頻
? ? *素材是在評(píng)論中翻找好多以后某位大哥的寿桨,很多鏈接都失效了
? ? *如有侵權(quán)此衅,請(qǐng)聯(lián)系我進(jìn)行刪除及修改
? ? 個(gè)人建議有興趣的同學(xué)最好還是自己來一遍,如果實(shí)在敲的過程中有問題亭螟,也可以去我Github下載成品的所有代碼挡鞍。Github地址
????在學(xué)習(xí)的最后老師也提到過新加一些功能,我要立一個(gè)Flag:在閑暇的時(shí)候也會(huì)對(duì)這個(gè)成品進(jìn)行一定程度的優(yōu)化和修改媒佣。
1.代碼結(jié)構(gòu)說明
項(xiàng)目結(jié)構(gòu)
主窗體-mainscene
選擇關(guān)卡-chooseselevelscene
翻金幣-playscene
金幣封裝-mycoin
關(guān)卡數(shù)據(jù)封裝-dataconfig
自定義按鈕類-mypushbutton
2.難點(diǎn)記錄
? ? 01.跳轉(zhuǎn)設(shè)置新窗打開位置屬性
????????跳轉(zhuǎn)時(shí)設(shè)置新窗體的geometry屬性和本窗體相同匕累,這樣設(shè)置會(huì)解決窗體移動(dòng)過后,打開的新窗體和舊窗體位置不同的bug;
? ? 02.創(chuàng)建新窗體默伍,初始化屬性
? ? ? ? //設(shè)置固定大小,并且讓窗體無法被更改
? ? ? ? setFixedSize(320, 588);
? ? ? ? //設(shè)置應(yīng)用圖標(biāo)
? ? ? ? setWindowIcon(QPixmap(":/res/Coin0001.png"));
? ? ? ? //設(shè)置窗口標(biāo)題
? ? ? ? setWindowTitle("選擇關(guān)卡");
? ? ? ? //設(shè)置菜單欄
? ? ? ? QMenuBar * qMenuBar = menuBar();
? ? ? ? QAction * qAction = qMenuBar->addMenu("開始")->addAction("退出");
? ? ? ? this->setMenuBar(qMenuBar);
? ? ? ? //點(diǎn)擊退出完成程序退出
? ? ? ? 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.定時(shí)器QTimer使用
? ? Qt的定時(shí)器實(shí)現(xiàn)有兩種,一個(gè)是重寫定時(shí)事件(沒使用過不清楚)也糊,另一個(gè)就是使用QTimer的靜態(tài)方法:
? ? //500是延遲多少時(shí)間執(zhí)行代碼,單位是毫秒
? ? //[=](){ ... }? ? Lamda表達(dá)式(很屌炼蹦,推薦學(xué)習(xí)而且使用不難)
? ? QTimer::singleShot(500, this, [=](){
? ? ? ? //operator code
? ? });
04.事件穿透設(shè)置上下對(duì)齊居中
? ? 選擇關(guān)卡時(shí)繪制關(guān)卡是通過自定義按鈕MyPushButton進(jìn)行繪制,顯示關(guān)卡名稱是通過QLabel相同大小覆蓋在自定義按鈕上狸剃。
? ? 此時(shí)點(diǎn)擊時(shí)無法觸發(fā)自定義按鈕上選擇關(guān)卡后的操作掐隐,可使用鼠標(biāo)點(diǎn)擊事件穿透設(shè)置到QLabel上,label->setAttribute(Qt::WA_TransparentForMouseEvents);這時(shí)鼠標(biāo)點(diǎn)擊后QLabel不會(huì)阻攔點(diǎn)擊事件钞馁,可以正常觸發(fā)自定義按鈕虑省。
? ? 在QLabel中設(shè)置text后默認(rèn)時(shí)居左,設(shè)置上下左右對(duì)齊居中僧凰,label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
05.設(shè)置開始游戲按鈕的點(diǎn)擊下沉彈回的動(dòng)畫
? ? //圖標(biāo)下沉
? ? void MyPushButton::zoom1()
? ? {
? ? ? ? QPropertyAnimation * animation1 = new QPropertyAnimation(this, "geometry");
? ? ? ? //設(shè)置事件間隔
? ? ? ? animation1->setDuration(200);
? ? ? ? //設(shè)置起始位置
? ? ? ? animation1->setStartValue(QRect(this->x(), this->y(), this->width(), this->height()));
? ? ? ? animation1->setEndValue(QRect(this->x(), this->y()+10, this->width(), this->height()));
? ? ? ? //設(shè)置動(dòng)畫,彈跳式,類似彈性球
? ? ? ? animation1->setEasingCurve(QEasingCurve::OutBounce);
? ? ? ? animation1->start();
? ? }
? ? //圖標(biāo)上浮
? ? void MyPushButton::zoom2()
? ? {
? ? ? ? QPropertyAnimation * animation1 = new QPropertyAnimation(this, "geometry");
? ? ? ? //設(shè)置事件間隔
? ? ? ? animation1->setDuration(200);
? ? ? ? //設(shè)置起始位置
? ? ? ? animation1->setStartValue(QRect(this->x(), this->y()+10, this->width(), this->height()));
? ? ? ? animation1->setEndValue(QRect(this->x(), this->y(), this->width(), this->height()));
? ? ? ? //設(shè)置動(dòng)畫,彈跳式,類似彈性球
? ? ? ? animation1->setEasingCurve(QEasingCurve::OutBounce);
? ? ? ? animation1->start();
? ? }
? ? //給start按鈕綁定點(diǎn)擊事件
? ? connect(btn_start, &QPushButton::clicked, [=](){
? ? ? ? btn_start->zoom1();
? ? ? ? btn_start->zoom2();
? ? ? ? //點(diǎn)擊音效
? ? ? ? startSound->play();
? ? ? ? //延時(shí)0.5秒執(zhí)行切換,展示start按鈕的動(dòng)效
? ? ? ? QTimer::singleShot(500, this, [=](){
? ? ? ? ? ? chooseLevel->setGeometry(this->geometry());
? ? ? ? ? ? this->hide();
? ? ? ? ? ? chooseLevel->show();
? ? ? ? });
? ? });
06.繪制一個(gè)4*4的選擇關(guān)卡矩陣,不使用雙層for循環(huán)的前提下,一個(gè)for循環(huán)完成繪制
? ? //創(chuàng)建關(guān)卡選擇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是每個(gè)矩陣x軸大小,i%4在第一行0训措、1伪节、2光羞、3四列,每一行計(jì)算的值是0*70怀大、1*70纱兑、2*70、3*70化借;
*y軸:160 + (i/4)*70? ? 160為偏移量潜慎,70是每個(gè)矩陣y軸大小,i/4在第一列0屏鳍、1勘纯、2、3四行钓瞭,每一行計(jì)算的值是0*70驳遵、1*70、2*70山涡、3*70堤结;
*在記錄其中每一個(gè)金幣的坐標(biāo)時(shí),構(gòu)建了新的二維數(shù)組保存位置信息鸭丛,因?yàn)檫@種構(gòu)建不太好保存位置信息