Demo_2:Qt實現猜字小遊戲

1  環境

系統:windows 10

代碼編寫運行環境:Qt Creator 4.4.1 (community)

Github:

2  簡介

參考視頻://www.bilibili.com/video/BV1XW411x7NU?p=35//www.bilibili.com/video/BV1XW411x7NU?p=35

參考博客://blog.csdn.net/fengge2018/article/details/106411326

實現功能:一個猜字小遊戲,系統隨機產生一個4位數,在規定時間內,我們輸入4位數進行匹配,如果相同,則贏了;不同且時間到了,則輸了。

贏了的實現效果如下:

輸了的實現效果如下:

3  實現過程

下面簡單說明一下實現的過程:

(1)先創建一個帶ui的項目工程,主要包含了如下文件。

(2)ui界面的設計

我們進入widget.ui進行界面設計。使用QStackWidget來存放多個頁面,包括以下4個頁面:

pageSet是我們剛開始運行時的頁面,包含兩個QLabel、一個QComboBox、兩個QPushButton,如下圖:

pageGame是我們玩遊戲時的頁面,包含一個QProgressBar、一個QTextEdit、10個按鈕,如下圖:

pageWin是勝利時顯示的頁面,就只包含一個QLabel組件:

pageLose是輸了的時候顯示的頁面,也只包含一個QLabel組件:

(3)代碼邏輯

啟動後,我們點擊「進入遊戲按鈕」切換到pageGame,並讀取出QComboBox中設置的倒計時時間,啟動一個計數器開始計數,並生成一個四位數的隨機數;

然後我們輸入數字按鈕開始進行匹配,數字按鈕的槽函數使用同一個,因為它們處理的邏輯是一樣的;

若我們輸入的數字和隨機數相同,則計數器停止計數,並切換到pageWin,啟動另一個計時器,顯示5s動畫後,回到pageSet;

若我們輸入的數字和隨機數不同,則判斷其和隨機數的大小,並給出對應的提示;

若時間到了且我們沒有猜出成功的答案,則切換到pageLose,啟動另一個計時器,顯示5s動畫後,回到pageSet。

(4)實現代碼

widget.h代碼:

 1 #ifndef WIDGET_H
 2 #define WIDGET_H
 3 
 4 #include <QWidget>
 5 #include <QString>
 6 #include <QTimer>
 7 #include <QMovie>
 8 
 9 namespace Ui {
10 class Widget;
11 }
12 
13 //目的:實現一個猜字遊戲
14 //說明:
15 //
16 
17 class Widget : public QWidget
18 {
19     Q_OBJECT
20 
21 public:
22     explicit Widget(QWidget *parent = 0);
23     ~Widget();
24 
25     //槽函數
26     void on_PushButtonStart_clicked();
27     void on_PushButtonQuit_clicked();
28     void on_PushButtonRollback_clicked();
29     void on_PushButtonNotice_clicked();
30     void dealNum();
31     void timerEvent(QTimerEvent *event);
32 
33 private:
34     int gameTime;
35     int gameTimerId;   //遊戲定時器
36     int loseTimerId;   //輸了
37     int winTimerId;    //贏了
38     QString randStr;   //隨機數
39     QString resultStr; //結果數
40     QMovie winMovie;   //贏了的動畫
41     QMovie loseMovie;  //輸了的動畫
42 
43 
44 private:
45     Ui::Widget *ui;
46 };
47 
48 #endif // WIDGET_H

View Code

widget.cpp代碼:

  1 #include "widget.h"
  2 #include "ui_widget.h"
  3 #include <QDebug>
  4 #include <QTime>
  5 #include <QMessageBox>
  6 
  7 Widget::Widget(QWidget *parent) :
  8     QWidget(parent),
  9     ui(new Ui::Widget)
 10 {
 11     ui->setupUi(this);
 12 
 13     //顯示第一個頁面,設置頁面
 14     ui->stackedWidget->setCurrentWidget(ui->pageSet);
 15     //失敗動畫
 16     loseMovie.setFileName(":/new/prefix1/image/over.gif");
 17     ui->label_lose->setMovie(&loseMovie);//給標籤設置動畫
 18     ui->label_lose->setScaledContents(true);//讓動畫自動適應標籤大小
 19     //勝利動畫
 20     winMovie.setFileName(":/new/prefix1/image/win.gif");
 21     ui->label_win->setMovie(&winMovie);
 22     ui->label_win->setScaledContents(true);
 23 
 24     //啟動遊戲
 25     connect(ui->pushButton_enter, &QPushButton::clicked, this, &Widget::on_PushButtonStart_clicked);
 26     //退出遊戲
 27     connect(ui->pushButton_quit,  &QPushButton::clicked, this, &Widget::close);
 28     //刪除前一個數字
 29     connect(ui->pushButton_rollback, &QPushButton::clicked, this, &Widget::on_PushButtonRollback_clicked);
 30     //提示
 31     connect(ui->pushButton_notice, &QPushButton::clicked, this, &Widget::on_PushButtonNotice_clicked);
 32 
 33     //對數字按鈕的處理使用同一個槽函數
 34     connect(ui->pushButton_0, &QPushButton::clicked, this, &Widget::dealNum);
 35     connect(ui->pushButton_1, &QPushButton::clicked, this, &Widget::dealNum);
 36     connect(ui->pushButton_2, &QPushButton::clicked, this, &Widget::dealNum);
 37     connect(ui->pushButton_3, &QPushButton::clicked, this, &Widget::dealNum);
 38     connect(ui->pushButton_4, &QPushButton::clicked, this, &Widget::dealNum);
 39     connect(ui->pushButton_5, &QPushButton::clicked, this, &Widget::dealNum);
 40     connect(ui->pushButton_6, &QPushButton::clicked, this, &Widget::dealNum);
 41     connect(ui->pushButton_7, &QPushButton::clicked, this, &Widget::dealNum);
 42     connect(ui->pushButton_8, &QPushButton::clicked, this, &Widget::dealNum);
 43     connect(ui->pushButton_9, &QPushButton::clicked, this, &Widget::dealNum);
 44 }
 45 
 46 void Widget::on_PushButtonStart_clicked()
 47 {
 48     //獲取下拉框時間,並將字符串轉換為整數
 49     gameTime = ui->comboBox->currentText().toInt();
 50     qDebug() << gameTime << "s";
 51 
 52     //切換到遊戲界面
 53     ui->stackedWidget->setCurrentWidget(ui->pageGame);
 54 
 55     int num;
 56     //從0時0分0秒到現在的秒數為種子
 57     qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));
 58     //調用全局的qsrand()函數生成隨機數,對10000取余,保證位於10000的範圍內
 59     while((num = qrand()%10000) < 999);
 60     randStr = QString::number(num);
 61     qDebug() << "randNum" << randStr;
 62 
 63     //設置進度條
 64     ui->progressBar->setMinimum(0); //最小值
 65     ui->progressBar->setMaximum(gameTime);  //最大值
 66     ui->progressBar->setValue(gameTime); //當前值
 67 
 68     //啟動定時器
 69     gameTimerId = startTimer(1000);  //以1000ms為間隔
 70     resultStr.clear();
 71     ui->textEdit->clear();
 72 }
 73 
 74 void Widget::on_PushButtonRollback_clicked()
 75 {
 76     //退格按鈕,刪除最後一個數字
 77     if(resultStr.size() == 1) {
 78         resultStr.clear();
 79         ui->textEdit->clear();
 80     } else {
 81         resultStr.chop(1); //截斷最後一位字符
 82         ui->textEdit->setText(resultStr);
 83     }
 84 }
 85 
 86 void Widget::on_PushButtonNotice_clicked()
 87 {
 88     //提示
 89     resultStr.clear();
 90     QString str = "正確答案為:" + randStr;
 91     ui->textEdit->setText(str);
 92 }
 93 
 94 void Widget::timerEvent(QTimerEvent *event)
 95 {
 96     if(event->timerId() == gameTimerId) {  //遊戲時間
 97         gameTime--;
 98         //設置進度條
 99         ui->progressBar->setValue(gameTime); //當前值
100         //時間到
101         if(0 == gameTime) {
102             //關閉定時器
103             killTimer(gameTimerId);
104             QMessageBox::information(this, "失敗", "時間到了啊!!!");
105             loseMovie.start();//啟動動畫
106             //切換失敗動畫頁面
107             ui->stackedWidget->setCurrentWidget(ui->pageLose);
108             loseTimerId = startTimer(5000); //啟動定時器
109         }
110     } else if(event->timerId() == loseTimerId) {  //失敗動畫時間
111         //停止動畫,停止定時器,回到遊戲設置頁面
112         loseMovie.stop();//停止動畫
113         killTimer(loseTimerId);  //停止定時器
114         //切換到遊戲設置頁面
115         ui->stackedWidget->setCurrentWidget(ui->pageSet);
116     } else if(event->timerId() == winTimerId) {  //勝利動畫時間
117         winMovie.stop();//停止動畫
118         killTimer(winTimerId);  //停止定時器
119         //切換到遊戲設置頁面
120         ui->stackedWidget->setCurrentWidget(ui->pageSet);
121     }
122 }
123 
124 void Widget::dealNum()
125 {
126     //獲取信號發送者
127     QObject *mysender = sender();
128     //轉換為按鈕類型
129     QPushButton *pb = (QPushButton *)mysender;
130     if (NULL != pb) {
131         //獲取按鈕內容
132         QString numStr = pb->text();
133         resultStr += numStr;
134         //數字不能以0開始
135         if (resultStr.size() == 1 && resultStr=="0") {
136             resultStr.clear();
137         }
138         //保證顯示結果為4位
139         if(resultStr.size() <= 4) {
140             ui->textEdit->setText(resultStr);
141             if (resultStr.size() == 4) {
142                 if (resultStr > randStr) {
143                     ui->textEdit->append("數字大了點!!!");
144                 } else if (resultStr < randStr) {
145                     ui->textEdit->append("數字小了點!!!");
146                 } else {
147                     ui->textEdit->append("恭喜你答對了!!!");
148                     //停止定時器
149                     killTimer(gameTimerId);
150                     QMessageBox::information(this, "勝利", "恭喜你!!!");
151                     //啟動win頁面
152                     winMovie.start();
153                     ui->stackedWidget->setCurrentWidget(ui->pageWin);
154                     //啟動定時器
155                     winTimerId = startTimer(5000); //5s
156                 }
157                 //初始化字符串結果,清空
158                 resultStr.clear();
159             }
160         }
161     }
162 }
163 
164 Widget::~Widget()
165 {
166     delete ui;
167 }

View Code

4  總結

主要有以下問題可能實現的時候會遇到:

(1)布局

布局這個確實不好弄,我也不太熟悉,當布局時最好先把相關聯的組件放在一個Widget裏面布好局之後,再進行全體布局。

(2)按鈕的字體設置在QWidget類裏面,而不是在QAbstractButton里。

(3)代碼中,定時器我們是使用的定時器事件處理函數timerEvent()來做的,而不是信號與槽。

如果代碼中還有其它問題,希望網友指出來。