Qt實(shí)現(xiàn)打地鼠游戲的方法詳解
今天與大家分享一個(gè)小游戲的實(shí)現(xiàn):打地鼠
看一下實(shí)現(xiàn)效果吧~
在指定的時(shí)間內(nèi)打中一定數(shù)額的地鼠,否則失敗,就如上述展示效果一樣,自己寫的小程序,居然連第二關(guān)也過不去,還挺尷尬的!
實(shí)現(xiàn)打地鼠小游戲不難,最主要的核心就是依靠定時(shí)器,按照一定間隔觸發(fā)。接下來,我來講解下是如何實(shí)現(xiàn)的吧!
功能講解
開發(fā)環(huán)境:VS2017 + Qt5.14.2 x64
1.確定地鼠數(shù)量
對于打地鼠這款游戲來說,地鼠是從任意的洞口鉆出。
在效果中,一共存在6個(gè)地鼠洞,最容易實(shí)現(xiàn)的方式:創(chuàng)建6個(gè)地鼠,每個(gè)地鼠洞都對應(yīng)一個(gè)地鼠。
實(shí)現(xiàn)代碼如下:
for (int i = 0; i < num; i++) { QPushButton *btn = new QPushButton(this); int nTop = i / 3 == 0 ? 300 : 450; int nRemainder = i % 3; if (nRemainder == 0) { btn->setGeometry(190, nTop, 180, 130); } else if (nRemainder == 1) { btn->setGeometry(480, nTop, 180, 130); } else if(nRemainder == 2) { btn->setGeometry(780, nTop, 180, 130); } btn->setStyleSheet(qsBtnStyle); btn->setProperty("num", i); btn->hide(); connect(btn, &QPushButton::clicked, this, &QGrameWhacAmole::OnBnClickedSusliks); //選中地鼠 m_vetBtnCtrls.push_back(btn); }
代碼解析:
num:此刻代表的是6,表明了需要?jiǎng)?chuàng)建6個(gè)地鼠,平均分配到每個(gè)洞中。
對每個(gè)地鼠按鈕響應(yīng)對應(yīng)的clicked消息,每當(dāng)打中一個(gè)地鼠,OnBnClickedSusliks消息內(nèi)就對分?jǐn)?shù)+1。
并且,創(chuàng)建出的地鼠默認(rèn)是隱藏狀態(tài)的。
2.定義游戲難易程序
在程序中定義了四種難度,設(shè)置了枚舉類型:
enum ENUM_GameMode { GameMode_difficulty1, GameMode_difficulty2, GameMode_difficulty3, GameMode_difficulty4, GameMode_OK, GameMode_Failed, };
GameMode_difficulty1:難度1,說明有1個(gè)地鼠出沒
GameMode_difficulty2:難度2,說明有2個(gè)地鼠出沒,
GameMode_difficulty3:難度3,說明有3個(gè)地鼠出沒,
GameMode_difficulty4:難度4,說明有4個(gè)地鼠出沒
在程序中,如何判斷通過某一關(guān)呢?
宏定義確定通關(guān)分?jǐn)?shù)
#define difficulty1Count 10 //難度1個(gè)數(shù) #define difficulty2Count 30 #define difficulty3Count 60 #define difficulty4Count 100
當(dāng)?shù)谝魂P(guān)時(shí),只需要打中10個(gè)地鼠;第二關(guān)需要累計(jì)打中30個(gè)地鼠,以此類推。
3.難度切換
在OnBnClickedSusliks消息中,根據(jù)當(dāng)前的分?jǐn)?shù)來確定是否要晉級(jí)。
響應(yīng)消息后,對分?jǐn)?shù)進(jìn)行+1處理
m_nScore += 1;
m_nScore是當(dāng)前類的成員變量,表示:打中的地鼠次數(shù)也就是當(dāng)前分?jǐn)?shù)。
打中后隱藏該地鼠
當(dāng)打中某個(gè)地鼠后,需要立刻隱藏地鼠,此時(shí)就運(yùn)用到了剛剛在創(chuàng)建地鼠時(shí)"setProperty"綁定的變量了。
QPushButton *btn = qobject_cast<QPushButton*>(sender()); int num = btn->property("num").toInt(); m_vetBtnCtrls[num]->hide(); //隱藏對應(yīng)編號(hào)控件
分?jǐn)?shù)判斷是否晉級(jí)
當(dāng)分?jǐn)?shù)到達(dá)難度1時(shí),晉升成難度2,其它的關(guān)卡都一樣
if (m_nScore == difficulty1Count) //難度1通過 { killTimer(m_nTimerStartId); m_nTimerStartId = 0; this->HideTotalSucliks(); m_enumMode = GameMode_difficulty2; this->SetTipsStyle(m_enumMode); m_nTimerStartId = startTimer(difficulty2Time); m_dwBeginTime = GetTickCount(); }
當(dāng)通過第一關(guān)后,停止定時(shí)器,隱藏正在展示的所有地鼠,更改模式狀態(tài),重新設(shè)置提示文本,開始定時(shí)器,重新記錄開始通關(guān)時(shí)間。
m_dwBeginTime:是記錄每次開始游戲時(shí)的時(shí)間,主要作用于挑戰(zhàn)失敗的判斷,也就是說,每次觸發(fā)定時(shí)器時(shí),當(dāng)前最新時(shí)間與最開始通關(guān)時(shí)間的差值 大于 通關(guān)時(shí)間時(shí),說明當(dāng)前關(guān)卡挑戰(zhàn)失??!
4.定時(shí)器處理
這也是當(dāng)前小游戲中最核心的處理部分了~
為了方便起見,直接使用QWidget自帶的定時(shí)器,而不是使用new QTimer的方式
virtual void timerEvent(QTimerEvent *event);
在定時(shí)器的處理中,分成了4部分,我們分別講述~
獲取定時(shí)器Id的觸發(fā)消息
if (event->timerId() == m_nTimerStartId) { //消息處理 }
只有當(dāng)定時(shí)器的觸發(fā)id與我們設(shè)定的id一致時(shí),才可以。
關(guān)閉提示頁面
在進(jìn)行難度切換時(shí),設(shè)置了提示文本,也就是效果圖中的“開始”、“開始第二關(guān)”等文字提示信息,在進(jìn)入到定時(shí)器事件中,首先判斷,該控件是否隱藏?如果未隱藏,先進(jìn)行隱藏。
if (ui.labTips->isHidden() == false) { ui.labTips->hide(); }
在這里需要我走過一個(gè)坑:使用isVisible()不一定獲取出控件的顯示狀態(tài),但是isHidden()始終是有效的。
判斷當(dāng)前關(guān)卡是否超時(shí)?
這也就是上文說到的m_dwBeginTime與最新觸發(fā)時(shí)間的差值
DWORD dwTime = GetTickCount() - m_dwBeginTime; if (dwTime > difficultyTimeout) { this->RunningFailed(); }
根據(jù)關(guān)卡不同,顯示不同的地鼠
這里,就是對地鼠顯示的邏輯處理了,根據(jù)枚舉模式不同,分別處理
switch (m_enumMode) { case QGrameWhacAmole::GameMode_difficulty1: this->RunningGamedifficulty(1); break; case QGrameWhacAmole::GameMode_difficulty2: this->RunningGamedifficulty(2); break; case QGrameWhacAmole::GameMode_difficulty3: this->RunningGamedifficulty(3); break; case QGrameWhacAmole::GameMode_difficulty4: this->RunningGamedifficulty(4); break; default: break; }
核心函數(shù)是:RunningGamedifficulty
如何讓地鼠進(jìn)行隨機(jī)顯示呢?
在當(dāng)前例子中,獲取隨機(jī)數(shù)[0,6)之間的值,隨機(jī)到哪個(gè)數(shù),哪個(gè)下標(biāo)下對應(yīng)的地鼠被顯示,其余的地鼠處于隱藏狀態(tài)。
隨機(jī)數(shù)生成方法:
int QGrameWhacAmole::GetRandomNumber() { QTime time = QTime::currentTime(); qsrand(time.msec() + time.second() * 1000); int n = qrand() % 6; return n; }
有人說使用這種方法可以在短時(shí)間內(nèi)生成的隨機(jī)數(shù)不相同,這個(gè)方法我已經(jīng)驗(yàn)證過了,不行!
還有的人說可以添加sleep,我也嘗試過了,不行!
那么,該如何獲取不重復(fù)的隨機(jī)數(shù)呢?
在這里,采用了std::set<int>
容器的方式,RunningGamedifficulty中的部分代碼如下:
void QGrameWhacAmole::RunningGamedifficulty(int nCount) { 1:隨機(jī)數(shù)生成 std::set<int> setRandom; //存儲(chǔ)隨機(jī)數(shù) for (int i = 0; setRandom.size() < nCount; i++) { //獲取隨機(jī)數(shù) int num = this->GetRandomNumber(); //如果隨機(jī)數(shù)在容器中從未出現(xiàn)過,存儲(chǔ)并應(yīng)用 if (setRandom.size() != 0) { std::set<int>::iterator itFind = setRandom.find(num); if (itFind != setRandom.end()) { continue; //存在重復(fù)值,后續(xù)不進(jìn)行處理 } } //容器中存在數(shù)據(jù),存儲(chǔ)之前進(jìn)行判斷 setRandom.insert(num); } }
根據(jù)上述代碼也可以看出,每生成一個(gè)隨機(jī)數(shù),就進(jìn)行存儲(chǔ),當(dāng)容器中出現(xiàn)相同的隨機(jī)數(shù)時(shí),重新生成。
nCount:就是需要展示的地鼠個(gè)數(shù),在for循環(huán)中,中間的判斷條件與以往不同,當(dāng)有效地地鼠編號(hào)大于地鼠個(gè)數(shù)后,就不再獲取隨機(jī)數(shù)了。
這種方式,無論是獲取多少個(gè)地鼠個(gè)數(shù)都是適用的。
其次,根據(jù)獲取的顯示的地鼠下標(biāo)數(shù)就可以對所有的地鼠進(jìn)行做顯示、隱藏操作了,代碼如下:
for (int m = 0; m < m_vetBtnCtrls.size(); m++) { std::set<int>::iterator itNum = setRandom.find(m); if (itNum != setRandom.end()) { m_vetBtnCtrls[m]->show(); } else { m_vetBtnCtrls[m]->hide(); } }
總結(jié)
到這里,核心的實(shí)現(xiàn)功能就已經(jīng)講解完了,功能難點(diǎn):
1:根據(jù)地鼠個(gè)數(shù)隨機(jī)顯示地鼠位置(RunningGamedifficulty處理邏輯)。
2:關(guān)卡晉級(jí)。
3:挑戰(zhàn)失敗處理。
到此這篇關(guān)于Qt實(shí)現(xiàn)打地鼠游戲的方法詳解的文章就介紹到這了,更多相關(guān)Qt打地鼠游戲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MATLAB中subplot函數(shù)的語法與使用實(shí)例
subplot()是將多個(gè)圖畫到一個(gè)平面上的工具,下面這篇文章主要給大家介紹了關(guān)于MATLAB中subplot函數(shù)的語法與使用的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08C++實(shí)現(xiàn)選擇性排序(SelectionSort)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)選擇性排序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04