[Qt 5.6.2] 利用Qt实现一个难度可变的2048小游戏

利用Qt实现一个难度随时可调的2048小游戏

 

一、游戏简介

1、规则创新

  胜利条件:达成2048

  难度变化:玩家可以通过调整难度条来控制随机池(2、4、8、16)中各个数出现的概率,同时也会改变分数的加成比例

  移动触发:每次移动后会从随机池中按照概率随机选取一个数,将其随机放置在一个空余位置上

  分数计算:总分=基础分+加成分,基础分+=合并的数值,加成分+=随机生成的数值*加成比例

 

2、游戏效果

   

 

 

二、设计思路

  先将该项目分为游戏入口、主窗口设计与游戏逻辑三个主要模块,再在这三个模块的基础上继续细分,分割成若干个小的功能模块,最后逐一实现。由MainWindow与GameLogic两个类分别实现主界面的显示功能与游戏的实现逻辑。

  程序入口较为简单,故不赘述。

  主窗口设计主要实现棋盘数据的显示与颜色变化、分数与难度的显示、检测方向键并连接进入游戏逻辑的入口。

  游戏逻辑是整个项目的核心部分,主要实现整个游戏的逻辑判断,根据主窗口提供的难度计算出难度系数与随机池各个数据出现概率。

 

 

三、代码分析

  文件具体分为gamelogic.cpp、main.cpp与mainwindow.cpp三个.cpp文件,gamelogic.h、mainwindow.h两个.h文件与一个mainwindow.ui文件。

1、程序入口:main.cpp

 1 #include "mainwindow.h"
 2 #include <QApplication>
 3 
 4 int main(int argc, char *argv[])
 5 {
 6     QApplication a(argc, argv);
 7     MainWindow w;
 8     w.show();
 9 
10     return a.exec();
11 }

 如果想进行人员管理与登陆的拓展可改为以下代码,可自行设计login登录规则:

 1 #include "mainwindow.h"
 2 #include <QApplication>
 3 
 4 int main(int argc, char *argv[])
 5 {
 6     QApplication a(argc, argv);
 7     MainWindow w;
 8     w.show();
 9 
10     return a.exec();
11 }
View Code

 

 

2、主窗口设计:mainwindow.cpp/.h/.ui

2.1 mainwindow.ui

      

 

2.2 mainwindow.h

 1 #ifndef MAINWINDOW_H
 2 #define MAINWINDOW_H
 3 
 4 #include <QMainWindow>
 5 #include <QKeyEvent>
 6 #include <QDebug>
 7 #include <QMessageBox>
 8 #include <QTextBrowser>
 9 #include "gamelogic.h"
10 
11 namespace Ui {
12 class MainWindow;
13 }
14 
15 class MainWindow : public QMainWindow
16 {
17     Q_OBJECT
18 
19 public:
20     GameLogic* game;
21     explicit MainWindow(QWidget *parent = 0);
22     ~MainWindow();
23     void initAll(); 
24     void showMessage();
25     void showBroad();
26     void keyPressEvent(QKeyEvent *event);
27     void changeColor(QLabel* label, int num);
28 
29 private slots:
30     void on_pushButton_start_clicked();
31 
32     void on_pushButton_close_clicked();
33 
34     void on_horizontalSlider_valueChanged(int value);
35 
36 private:
37     Ui::MainWindow *ui;
38 };
39 
40 #endif // MAINWINDOW_H

 

2.3 mainwindow.cpp(代码共177行,折叠)

  1 #include "mainwindow.h"
  2 #include "ui_mainwindow.h"
  3 #include "gamelogic.h"
  4 
  5 MainWindow::MainWindow(QWidget *parent) :
  6     QMainWindow(parent),
  7     ui(new Ui::MainWindow)
  8 {
  9     game = new GameLogic;
 10     ui->setupUi(this);
 11     showBroad();
 12 }
 13 
 14 MainWindow::~MainWindow()
 15 {
 16     delete ui;
 17 }
 18 
 19 void MainWindow::initAll()
 20 {
 21     game->initAll();
 22     on_horizontalSlider_valueChanged(ui->horizontalSlider->value());
 23 }
 24 
 25 
 26 void MainWindow::on_pushButton_start_clicked()
 27 {
 28     ui->pushButton_start->setText("重新开始");
 29     initAll();
 30 
 31     game->createNum();
 32     game->createNum();
 33     game->setGameStart(true);
 34 
 35     showBroad();
 36     showMessage();
 37 }
 38 
 39 void MainWindow::on_pushButton_close_clicked()
 40 {
 41     this->close();
 42 }
 43 
 44 void MainWindow::on_horizontalSlider_valueChanged(int value)
 45 {
 46     value = ui->horizontalSlider->value();
 47     ui->label_showGradeUpCoefficient->setText(QString::number(value*2)+"%");
 48     game->setGradeUpCoefficient((float)ui->horizontalSlider->value()/100);
 49 
 50     if     (20 > value) ui->label_showDifficult->setText("简单");
 51     else if(40 > value) ui->label_showDifficult->setText("正常");
 52     else if(60 > value) ui->label_showDifficult->setText("困难");
 53     else if(80 > value) ui->label_showDifficult->setText("地狱");
 54     else                ui->label_showDifficult->setText("混沌");
 55 }
 56 
 57 void MainWindow::keyPressEvent(QKeyEvent *event)
 58 {
 59     if(!game->getGameStart()) return;
 60     switch(event->key())
 61     {
 62     case Qt::Key_Up:    game->process(CMD_UP);    break;
 63     case Qt::Key_Down:  game->process(CMD_DOWN);  break;
 64     case Qt::Key_Left:  game->process(CMD_LEFT);  break;
 65     case Qt::Key_Right: game->process(CMD_RIGHT); break;
 66     }
 67     showBroad();
 68     showMessage();
 69     switch(game->judge())
 70     {
 71     case STAT_PROCESS: break;
 72     case STAT_WIN:  QMessageBox::information(NULL,"2048","大吉大利,今晚吃鸡!"); break;
 73     case STAT_LOSE: QMessageBox::information(NULL,"2048","再接再厉,永不放弃!"); break;
 74     }
 75 }
 76 
 77 void MainWindow::showMessage()
 78 {
 79     ui->label_showGrade->setText(QString::number(game->getGrade()));
 80     ui->label_showGradeBasic->setText(QString::number(game->getGradeBasic()));
 81     ui->label_showGradeUp->setText(QString::number(game->getGradeUp()));
 82     ui->label_showStep->setText(QString::number(game->getStep()));
 83 }
 84 
 85 void MainWindow::showBroad()
 86 {
 87     //第一行
 88     if(game->getData(0,0)) ui->label_00->setText(QString::number(game->getData(0,0)));
 89     else                   ui->label_00->setText(" ");
 90     if(game->getData(0,1)) ui->label_01->setText(QString::number(game->getData(0,1)));
 91     else                   ui->label_01->setText(" ");
 92     if(game->getData(0,2)) ui->label_02->setText(QString::number(game->getData(0,2)));
 93     else                   ui->label_02->setText(" ");
 94     if(game->getData(0,3)) ui->label_03->setText(QString::number(game->getData(0,3)));
 95     else                   ui->label_03->setText(" ");
 96     changeColor(ui->label_00, game->getData(0,0));
 97     changeColor(ui->label_01, game->getData(0,1));
 98     changeColor(ui->label_02, game->getData(0,2));
 99     changeColor(ui->label_03, game->getData(0,3));
100 
101     //第二行
102     if(game->getData(1,0)) ui->label_10->setText(QString::number(game->getData(1,0)));
103     else                   ui->label_10->setText(" ");
104     if(game->getData(1,1)) ui->label_11->setText(QString::number(game->getData(1,1)));
105     else                   ui->label_11->setText(" ");
106     if(game->getData(1,2)) ui->label_12->setText(QString::number(game->getData(1,2)));
107     else                   ui->label_12->setText(" ");
108     if(game->getData(1,3)) ui->label_13->setText(QString::number(game->getData(1,3)));
109     else                   ui->label_13->setText(" ");
110     changeColor(ui->label_10, game->getData(1,0));
111     changeColor(ui->label_11, game->getData(1,1));
112     changeColor(ui->label_12, game->getData(1,2));
113     changeColor(ui->label_13, game->getData(1,3));
114 
115     //第三行
116     if(game->getData(2,0)) ui->label_20->setText(QString::number(game->getData(2,0)));
117     else                   ui->label_20->setText(" ");
118     if(game->getData(2,1)) ui->label_21->setText(QString::number(game->getData(2,1)));
119     else                   ui->label_21->setText(" ");
120     if(game->getData(2,2)) ui->label_22->setText(QString::number(game->getData(2,2)));
121     else                   ui->label_22->setText(" ");
122     if(game->getData(2,3)) ui->label_23->setText(QString::number(game->getData(2,3)));
123     else                   ui->label_23->setText(" ");
124     changeColor(ui->label_20, game->getData(2,0));
125     changeColor(ui->label_21, game->getData(2,1));
126     changeColor(ui->label_22, game->getData(2,2));
127     changeColor(ui->label_23, game->getData(2,3));
128 
129     //第四行
130     if(game->getData(3,0)) ui->label_30->setText(QString::number(game->getData(3,0)));
131     else                   ui->label_30->setText(" ");
132     if(game->getData(3,1)) ui->label_31->setText(QString::number(game->getData(3,1)));
133     else                   ui->label_31->setText(" ");
134     if(game->getData(3,2)) ui->label_32->setText(QString::number(game->getData(3,2)));
135     else                   ui->label_32->setText(" ");
136     if(game->getData(3,3)) ui->label_33->setText(QString::number(game->getData(3,3)));
137     else                   ui->label_33->setText(" ");
138     changeColor(ui->label_30, game->getData(3,0));
139     changeColor(ui->label_31, game->getData(3,1));
140     changeColor(ui->label_32, game->getData(3,2));
141     changeColor(ui->label_33, game->getData(3,3));
142 }
143 
144 //改变方块的StyleSheet
145 void MainWindow::changeColor(QLabel* label, int num)
146 {
147     label->setAlignment(Qt::AlignCenter);
148     switch (num)
149     {
150     case 2:    label->setStyleSheet("background-color: rgb(238,228,218);"
151                                     "font:bold 75 30pt ""微软雅黑"""); break;
152     case 4:    label->setStyleSheet("background-color: rgb(237,224,200);"
153                                     "font:bold 75 30pt ""微软雅黑"""); break;
154     case 8:    label->setStyleSheet("background-color: rgb(242,177,121);"
155                                     "font:bold 75 30pt ""微软雅黑"""); break;
156     case 16:   label->setStyleSheet("background-color: rgb(245,150,100);"
157                                     "font:bold 75 30pt ""微软雅黑"""); break;
158     case 32:   label->setStyleSheet("background-color: rgb(245,125,95);"
159                                     "font:bold 75 30pt ""微软雅黑"""); break;
160     case 64:   label->setStyleSheet("background-color: rgb(245,95,60);"
161                                     "font:bold 75 30pt ""微软雅黑"""); break;
162     case 128:  label->setStyleSheet("background-color: rgb(237,207,114);"
163                                     "font:bold 75 25pt ""微软雅黑"""); break;
164     case 256:  label->setStyleSheet("background-color: rgb(237,204,97);"
165                                     "font:bold 75 25pt ""微软雅黑"""); break;
166     case 512:  label->setStyleSheet("background-color: rgb(237,204,97);"
167                                     "font:bold 75 25pt ""微软雅黑"""); break;
168     case 1024: label->setStyleSheet("background-color: rgb(237,204,97);"
169                                     "font:bold 75 20pt ""微软雅黑"""); break;
170     case 2048: label->setStyleSheet("background-color: rgb(237,204,97);"
171                                     "font:bold 75 20pt ""微软雅黑"""); break;
172     default:   label->setStyleSheet("background-color: rgb(238,228,218);"
173                                     "font:bold 75 40pt ""微软雅黑"""); break;
174     }
175 }
View Code
    ① 初始化所有数据,锁定检测:
    void initAll();
    ② 通过按钮开始或结束游戏,并且可随时调节游戏难度:
    void on_pushButton_start_clicked();

    void on_pushButton_close_clicked();
    void on_horizontalSlider_valueChanged(int value);
    ③ 显示界面与各类信息,根据各个方块的数值来调整游戏显示画面:
    void showMessage();

    void showBroad();
    void changeColor(QLabel* label, int num);
    ④ 检测方向键,执行成员变量game的逻辑函数:
    void keyPressEvent(QKeyEvent *event);


3、游戏逻辑:gamelogic.cpp/.h
3.1 gamelogic.h
 1 #ifndef GAMELOGIC_H
 2 #define GAMELOGIC_H
 3 
 4 #include <iostream>
 5 
 6 #define ROW 4
 7 #define COL 4
 8 
 9 enum CMD
10 {
11     CMD_UP,
12     CMD_DOWN,
13     CMD_LEFT,
14     CMD_RIGHT,
15 };
16 
17 enum STAT
18 {
19     STAT_WAIT,
20     STAT_PROCESS,
21     STAT_WIN,
22     STAT_LOSE,
23 };
24 
25 class GameLogic
26 {
27 public:
28     GameLogic();
29     bool createNum();
30     void process(int cmd);
31     int judge();
32     void initAll();
33     void calProb();
34 
35     void moveUp();
36     void moveDown();
37     void moveLeft();
38     void moveRight();
39 
40     bool getGameStart();
41     void setGameStart(bool);
42     void setGradeUpCoefficient(float);
43     int getData(int,int);
44     int getGrade();
45     int getGradeBasic();
46     int getGradeUp();
47     int getStep();
48 
49 private:
50     bool gameStart;
51     int data[4][4];
52     float grade;
53     int gradeBasic;
54     float gradeUp;
55     int step;
56     float gradeUpCoefficient;
57     int prob2;
58     int prob4;
59     int prob8;
60     int prob16;
61 };
62 
63 #endif // GAMELOGIC_H

 

3.2 gamelogic.cpp(代码共299行,折叠)

  1 #include "gamelogic.h"
  2 #include "ui_mainwindow.h"
  3 
  4 #include <random>
  5 #include <iostream>
  6 #include <vector>
  7 #include <qDebug>
  8 using namespace std;
  9 
 10 GameLogic::GameLogic()
 11 {
 12     initAll();
 13 }
 14 
 15 void GameLogic::initAll()
 16 {
 17     for(int i=0; i<ROW; i++)
 18     {
 19         for(int j=0; j<COL; j++)
 20         {
 21             data[i][j] = 0;
 22         }
 23     }
 24     gameStart = false;
 25     grade = 0;
 26     gradeBasic = 0;
 27     gradeUp = 0;
 28     step = 0;
 29     gradeUpCoefficient = 0;
 30 
 31     prob2 = 0;
 32     prob4 = 0;
 33     prob8 = 0;
 34     prob16 = 0;
 35 }
 36 
 37 void GameLogic::calProb()
 38 {
 39     qDebug() << "gradeUpCoefficient:" << gradeUpCoefficient ;
 40     if(0.6 > gradeUpCoefficient) // 0->0.6
 41     {
 42         prob2 = 80-gradeUpCoefficient*100*0.5; // 80%->50%
 43         prob4 = 100;                           // 20%->50%
 44         prob8 = 0, prob16 = 0;                 // 0
 45         qDebug() << "2:" << prob2 << " 4:" << prob4 << " 8:" << prob8 << " 16:" << prob16 ;
 46     }
 47     else if(0.8 > gradeUpCoefficient) // 0.6->0.8
 48     {
 49         prob2 = 80-gradeUpCoefficient*100*0.5; // 50%->40%
 50         prob4 = 50+prob2;                      // 50%
 51         prob8 = 100;                           // 0->10%
 52         prob16 = 0;                            // 0
 53         qDebug() << "2:" << prob2 << " 4:" << prob4 << " 8:" << prob8 << " 16:" << prob16 ;
 54     }
 55     else if(1 >= gradeUpCoefficient)// 0.8->1.0
 56     {
 57         prob2 = 40;                                    // 40%
 58         prob4 = -10+gradeUpCoefficient*100*0.5+prob2;  // 30%->40%
 59         prob8 = -10+gradeUpCoefficient*100*0.25+prob4; // 10%->15%
 60         prob16 = 100;                                  // 0->5%
 61         qDebug() << "2:" << prob2 << " 4:" << prob4 << " 8:" << prob8 << " 16:" << prob16 ;
 62     }
 63 }
 64 
 65 bool GameLogic::createNum()
 66 {
 67     vector<int> indexSpace;
 68     for(int i=0; i<ROW; i++)
 69     {
 70         for(int j=0; j<COL; j++)
 71         {
 72             if(!data[i][j])
 73             {
 74                 indexSpace.push_back(i*4+j);
 75             }
 76         }
 77     }
 78     if(!indexSpace.empty())
 79     {
 80         int randNum = rand()%100;
 81         int randPlace = rand()%indexSpace.size();
 82         int chooseNum = -1;
 83 
 84         calProb();
 85         //qDebug() << "randNum:" << randNum;
 86         //qDebug() << "2:" << prob2 << " 4:" << prob4 << " 8:" << prob8 << " 16:" << prob16 ;
 87         if     (prob2 > randNum)  chooseNum = 2;
 88         else if(prob4 > randNum)  chooseNum = 4;
 89         else if(prob8 > randNum)  chooseNum = 8;
 90         else if(prob16 > randNum) chooseNum = 16;
 91         int x = indexSpace[randPlace]/4;
 92         int y = indexSpace[randPlace]%4;
 93         //qDebug("---------- %d %d----------",x,y);
 94         data[x][y] = chooseNum;
 95         gradeUp += 2*chooseNum*gradeUpCoefficient;
 96         grade = gradeBasic + gradeUp;
 97         return true;
 98     }
 99     else
100     {
101         return false;
102     }
103 }
104 
105 void GameLogic::process(int cmd)
106 {
107     switch(cmd)
108     {
109     case CMD_UP:    moveUp();    break;
110     case CMD_DOWN:  moveDown();  break;
111     case CMD_LEFT:  moveLeft();  break;
112     case CMD_RIGHT: moveRight(); break;
113     }
114     createNum();
115     createNum();
116     step++;
117 }
118 
119 void GameLogic::moveUp()
120 {
121     for(int j=0; j<COL; j++)
122     {
123         //取出所有非零元素
124         int t[10] = {0};
125         int cnt = 0;
126         for(int i=0; i<ROW; i++)
127             if(data[i][j])
128                 t[cnt++] = data[i][j];
129 
130         for(int k=0; k<cnt-1; k++)
131         {
132             if(t[k]==t[k+1])
133             {
134                 gradeBasic += t[k];
135                 t[k] *= 2;
136                 t[k+1] = 0;
137             }
138         }
139         //将合并后的非零元素填入data中
140         int n = 0;
141         for(int k=0; k<cnt; k++)
142         {
143             if(t[k])
144                 data[n++][j] = t[k];
145         }
146         //尾部补零
147         for(; n<ROW; n++)
148         {
149             data[n][j] = 0;
150         }
151     }
152 }
153 
154 void GameLogic::moveDown()
155 {
156     for(int j=0; j<COL; j++)
157     {
158         int t[10];
159         int cnt = 0;
160 
161         for(int i=ROW-1; i>=0; i--)
162             if(data[i][j])    t[cnt++] = data[i][j];
163 
164         for(int k=0; k<cnt-1; k++)
165         {
166             if(t[k]==t[k+1])
167             {
168                 gradeBasic += t[k];
169                 t[k] *= 2;
170                 t[k+1] = 0;
171             }
172         }
173 
174         int n = ROW-1;
175         for(int k=0; k<cnt; k++)
176         {
177             if(t[k])    data[n--][j] = t[k];
178         }
179 
180         for(; n>=0; n--)
181         {
182             data[n][j] = 0;
183         }
184     }
185 }
186 
187 void GameLogic::moveLeft()
188 {
189     for(int i=0; i<ROW; i++)
190     {
191         int t[10];
192         int cnt = 0;
193         for(int j=0; j<COL; j++)
194             if(data[i][j])    t[cnt++] = data[i][j];
195 
196         for(int k=0; k<cnt-1; k++)
197         {
198             if(t[k]==t[k+1])
199             {
200                 gradeBasic += t[k];
201                 t[k] *= 2;
202                 t[k+1] = 0;
203             }
204         }
205 
206         int n = 0;
207         for(int k=0; k<cnt; k++)
208         {
209             if(t[k])    data[i][n++] = t[k];
210         }
211 
212         for(; n<COL; n++)
213         {
214             data[i][n] = 0;
215         }
216 
217     }
218 }
219 
220 void GameLogic::moveRight()
221 {
222     for(int i=0; i<ROW; i++)
223     {
224         int t[10];
225         int cnt = 0;
226         for(int j=COL-1; j>=0; j--)
227             if(data[i][j])    t[cnt++] = data[i][j];
228 
229         for(int k=0; k<cnt-1; k++)
230         {
231             if(t[k]==t[k+1])
232             {
233                 gradeBasic += t[k];
234                 t[k] *= 2;
235                 t[k+1] = 0;
236             }
237         }
238 
239         int n = COL-1;
240         for(int k=0; k<cnt; k++)
241         {
242             if(t[k])    data[i][n--] = t[k];
243         }
244 
245         for(; n>=0; n--)
246         {
247             data[i][n] = 0;
248         }
249 
250     }
251 }
252 
253 int GameLogic::judge()
254 {
255     //赢得游戏
256     for (int i=0; i<ROW; i++)
257     {
258         for (int j=0; j<COL; j++)
259         {
260             if (data[i][j] == 2048)
261             {
262                 return STAT_WIN;
263             }
264         }
265     }
266     //横向检查
267     for (int i=0; i<ROW; i++)
268     {
269         for (int j=0; j<COL-1; j++)
270         {
271             if (!data[i][j] || (data[i][j] == data[i][j+1]))
272             {
273                 return STAT_PROCESS;
274             }
275         }
276     }
277     //纵向检查
278     for (int j=0; j<COL; j++)
279     {
280         for (int i=0; i<ROW-1; i++)
281         {
282             if (!data[i][j] || (data[i][j] == data[i+1][j]))
283             {
284                 return STAT_PROCESS;
285             }
286         }
287     }
288     //不符合上述两种状况,游戏结束
289     return STAT_LOSE;
290 }
291 
292 bool GameLogic::getGameStart(){return gameStart;}
293 void GameLogic::setGameStart(bool flag){gameStart = flag;}
294 void GameLogic::setGradeUpCoefficient(float i){gradeUpCoefficient = i;}
295 int GameLogic::getData(int i, int j){return data[i][j];}
296 int GameLogic::getGrade(){return grade;}
297 int GameLogic::getGradeBasic(){return gradeBasic;}
298 int GameLogic::getGradeUp(){return gradeUp;}
299 int GameLogic::getStep(){return step;}
View Code
 ① 宏定义棋盘行列数:#define ROW 4;  #define COL 4;
 ② 枚举定义指令与状态:enum CMD...  enum STAT...
 ③ 定义成员变量:
    游戏状态:bool gameStart;
    棋盘规格:int data[ROW][COL];
    分数统计:float grade;
         int gradeBasic;
        float gradeUp;
        float gradeUpCoefficient;
    当前步数:int step;
   随机数概率:int prob2;
         int prob4;
         int prob8;
         int prob16;
 ④ 定义成员函数:
   初始化数据:void initAll();
    创造随机数:bool createNum();
    状态判定:int judge();
   概率计算:void calProb();
     游戏过程:void process(int cmd);
         void moveUp();
         void moveDown();
         void moveLeft();
         void moveRight();
    数据处理:bool getGameStart();
         void setGameStart(bool);
         void setGradeUpCoefficient(float);
         int getData(int,int);
         int getGrade();
         int getGradeBasic();
         int getGradeUp();
         int getStep();

posted @ 2018-09-04 23:38  caoliu  阅读(4738)  评论(3编辑  收藏  举报