2048游戏_QT实现

时间:2022-09-17 13:18:35

2048游戏_QT实现2048游戏_QT实现

 #ifndef GAMEWIDGET_H
 #define GAMEWIDGET_H

 #include <QWidget>
 #include <QMouseEvent>
 #include <QEventLoop>
 #include <QTimer>
 #include <QPainter>
 #include <QList>

 // 手势的方向
 enum GestureDirect
 {
     LEFT = ,   // 向左
     RIGHT = ,  // 向右
     UP = ,     // 向上
     DOWN =     // 向下
 };

 // 定义动画的类型
 enum AnimationType
 {
     MOVE = ,       // 方格移动动画
     APPEARANCE =   // 方格出现动画
 };

 // 动画结构体
 struct Animation
 {
     AnimationType type;     // 动画类型
     GestureDirect direct;   // 方向
     QPointF startPos;       // 起始点坐标 出现动画仅仅使用这个坐标
     QPointF endPos;         // 终止点坐标 移动动画的终点坐标
     int digit;              // 数码
     int digit2;             // 第二数码 数码可能被合并
 };

 // 游戏部件类 继承自QWidget
 class GameWidget : public QWidget
 {
     Q_OBJECT
 public:
     // 构造函数
     );

 private:
     // 游戏面板 存储每个格子的数值
     ][];
     // 数码的个数 存储当前面板上的数字的个数
     int digitCount;
     // 分数 存储当前得分
     int score;
     // 起始点坐标 存储手势起点坐标
     QPoint startPos;
     // 存储所有需要展现的动画
     QList<Animation> animationList;
     // 小格子的宽度和高度
     qreal w, h;
     // 缓存图像
     QImage *cacheImg;
     // 是否在播放动画效果
     bool isAnimating;

     // 检测游戏是否结束
     bool checkGameOver();
     // 检测游戏是否获胜
     bool checkWin();
     /* 获取一个数字的二进制位数 当然这里获取的不完全是二进制位数 而是对应颜色数组的下标
     比如 2 对应 0    8 对应 2*/
     int getBitCount(int);
     // 绘制动画效果
     bool playAnimation(Animation&, QPainter&);
     // 鼠标按下触发的事件
     void mousePressEvent(QMouseEvent *);
     // 鼠标释放触发的时间
     void mouseReleaseEvent(QMouseEvent *);
     // 绘制事件
     void paintEvent(QPaintEvent *);

     // 以下为一些信号
 signals:
     // 手势移动信号
     void GestureMove(GestureDirect);
     // 分数增加信号
     void ScoreInc(int);
     // 游戏结束信号
     void GameOver();
     // 游戏获胜信号
     void win();

     // 以下为一些槽函数
 public slots:
     // 处理手势移动信号的槽函数
     void onGestureMove(GestureDirect);
     // 重新开始的槽函数
     void restart();

 };

 #endif // GAMEWIDGET_H
 #include "GameWidget.h"

 // 颜色数组 存储每个数字对应的背景色
 QColor digitBkg[] = {QColor::fromRgb(0xFF, 0xFF, 0xCC), QColor::fromRgb(0xFF, 0xFF, 0x99),
                             QColor::fromRgb(0xFF, 0xCC, 0xCC), QColor::fromRgb(0xFF, 0xCC, 0x99),
                             QColor::fromRgb(0xFF, 0x99, 0x99), QColor::fromRgb(0xFF, 0x99, 0x66),
                             QColor::fromRgb(0xFF, 0x66, 0x66), QColor::fromRgb(0xCC, 0x99, 0x66),
                             QColor::fromRgb(0xCC, 0x33, 0x33), QColor::fromRgb(0xCC, 0x00, 0x33),
                             QColor::fromRgb(0xFF, 0x00, 0x00)};

 // 每个方向位置的增量
 QPointF dPos[] = {QPointF(-, ), QPointF(, ), QPointF(, -), QPointF(, ), QPointF(-, -)};

 GameWidget::GameWidget(QWidget *parent) :
     QWidget(parent)
 {
     // 连接手势移动信号和相应的槽函数
     connect(this, SIGNAL(GestureMove(GestureDirect)), SLOT(onGestureMove(GestureDirect)));
     // 初始化board数组
     memset(board, , sizeof(board));
     // 随机填入两个2
     board[rand() % ][rand() % ] = ;
     board[rand() % ][rand() % ] = ;
     // 分数初始化为0
     score = ;
     // 数码个数初始化为2
     digitCount = ;
     isAnimating = false;
     cacheImg = NULL;
 }

 void GameWidget::mousePressEvent(QMouseEvent *e)
 {
     // 获取起点坐标
     startPos = e->pos();
 }

 void GameWidget::mouseReleaseEvent(QMouseEvent *e)
 {
     // 如果在播放动画效果则直接退出防止重复产生手势事件
     if (isAnimating)
         return;
     // 根据终点坐标和起点坐标计算XY坐标的增量
     float dX = (float)(e->pos().x() - startPos.x());
     float dY = (float)(e->pos().y() - startPos.y());
     // 确定手势方向
     if (abs(dX) > abs(dY))
     {
         )
             emit GestureMove(LEFT);
         else
             emit GestureMove(RIGHT);
     }
     else
     {
         )
             emit GestureMove(UP);
         else
             emit GestureMove(DOWN);
     }
 }

 void GameWidget::onGestureMove(GestureDirect direct)
 {
     int i, j, k;
     Animation a;
     // 是否合并过方格
     bool combine = false;
     // 处理不同方向
     switch (direct)
     {
     // 向左
     case LEFT:
         // 循环每一行
         ; i < ; i++)
         {
             /* 初始化j k为0
              * 这里j表示要交换的数字列号
              * k表示交换到的位置的列号
              * */
             j = , k = , combine = false;
             while (true)
             {
                 // 循环找到第一个不是0的数字对应的列号
                  && board[i][j] == )
                     j++;
                 // 如果超过了3则说明搜索完毕 推出循环
                 )
                     break;
                 // 交换两个数字
                 qSwap(board[i][k], board[i][j]);
                 // 记录动画信息
                 a.type = MOVE;
                 a.startPos = QPointF( + (w + ) * j,  + (h + ) * i);
                 a.endPos = QPointF( + (w + ) * k,  + (h + ) * i);
                 a.digit = a.digit2 = board[i][k];
                 a.direct = LEFT;
                 //如果交换后的数字与其前一列的数字相同
                  && board[i][k] == board[i][k - ])
                 {
                     // 前一列的数字*2
                     board[i][k - ] <<= ;
                     // 这一列的数字置为0
                     board[i][k] = ;
                     // 记录动画信息
                     a.digit2 = board[i][k - ];
                     a.endPos = QPointF( + (w + ) * (k - ),  + (h + ) * i);
                     // 增加分数
                     score += board[i][k - ];
                     // 发射增加分数的信号
                     emit ScoreInc(score);
                     // 数码个数-1
                     digitCount--;
                     combine = true;
                 }
                 else
                     k++;
                 j++;
                 // 添加到动画链表
                 animationList.append(a);
             }
         }
         break;
         // 其余三个方向与左向类似
     case RIGHT:
         ; i < ; i++)
         {
             j = , k = , combine = false;
             while (true)
             {
                  && board[i][j] == )
                     j--;
                 )
                     break;
                 qSwap(board[i][k], board[i][j]);
                 a.type = MOVE;
                 a.startPos = QPointF( + (w + ) * j,  + (h + ) * i);
                 a.endPos = QPointF( + (w + ) * k,  + (h + ) * i);
                 a.digit = a.digit2 = board[i][k];
                 a.direct = RIGHT;
                  && board[i][k] == board[i][k + ])
                 {
                     board[i][k + ] <<= ;
                     board[i][k] = ;
                     a.digit2 = board[i][k + ];
                     a.endPos = QPointF( + (w + ) * (k + ),  + (h + ) * i);
                     score += board[i][k + ];
                     emit ScoreInc(score);
                     digitCount--;
                     combine = true;
                 }
                 else
                     k--;
                 j--;
                 animationList.append(a);
             }
         }
         break;
     case UP:
         ; i < ; i++)
         {
             j = , k = , combine = false;
             while (true)
             {
                  && board[j][i] == )
                     j++;
                 )
                     break;
                 qSwap(board[k][i], board[j][i]);
                 a.type = MOVE;
                 a.startPos = QPointF( + (w + ) * i,  + (h + ) * j);
                 a.endPos = QPointF( + (w + ) * i,  + (h + ) * k);
                 a.digit = a.digit2 = board[k][i];
                 a.direct = UP;
                  && board[k][i] == board[k - ][i])
                 {
                     board[k - ][i] <<= ;
                     board[k][i] = ;
                     a.digit2 = board[k - ][i];
                     a.endPos = QPointF( + (w + ) * i,  + (h + ) * (k - ));
                     score += board[k - ][i];
                     emit ScoreInc(score);
                     digitCount--;
                     combine = true;
                 }
                 else
                     k++;
                 j++;
                 animationList.append(a);
             }
         }
         break;
     case DOWN:
         ; i < ; i++)
         {
             j = , k = , combine = false;
             while (true)
             {
                  && board[j][i] == )
                     j--;
                 )
                     break;
                 qSwap(board[k][i], board[j][i]);
                 a.type = MOVE;
                 a.startPos = QPointF( + (w + ) * i,  + (h + ) * j);
                 a.endPos = QPointF( + (w + ) * i,  + (h + ) * k);
                 a.digit = a.digit2 = board[k][i];
                 a.direct = DOWN;
                  && board[k][i] == board[k + ][i])
                 {
                     board[k + ][i] <<= ;
                     board[k][i] = ;
                     a.digit2 = board[k + ][i];
                     a.endPos = QPointF( + (w + ) * i,  + (h + ) * (k + ));
                     score += board[k + ][i];
                     emit ScoreInc(score);
                     digitCount--;
                     combine = true;
                 }
                 else
                     k--;
                 j--;
                 animationList.append(a);
             }
         }
         break;
     }
     // 如果数字木有填满
     )
     {
         // 随机产生行号和列号
         i = rand() % , j = rand() % ;
         // 循环直到行和列对应的元素为0
         )
             i = rand() % , j = rand() % ;
         // 填入2
         board[i][j] = (rand() %  + ) * ;
         // 记录动画信息
         a.type = APPEARANCE;
         a.startPos = a.endPos = QPointF( + (w + ) * j,  + (h + ) * i);
         a.startPos += QPointF(w / , h / );
         a.digit = board[i][j];
         // 数码个数加一
         digitCount++;
     }
     else
     {
         // 如果数字填满了 检测游戏是否over
         if (checkGameOver())
             emit GameOver();// 如果游戏over了则发射GameOver信号
     }

     // 开始绘制动画效果
     isAnimating = true;
     // 动画列表的迭代器
     QList<Animation>::iterator it;
     // 事件循环 用于延时
     QEventLoop eventLoop;
     // 删除之前的缓存图像
     if (cacheImg)
         delete cacheImg;
     // 建立缓存图像
     cacheImg = new QImage(width(), height(), QImage::Format_ARGB32);
     // 清空图像
     cacheImg->fill();
     // 构造一个QPainter对象
     QPainter painter(cacheImg);
     // 字体
     QFont font;
     font.setFamily("Consolas");
     font.setBold(true);
     font.setPixelSize();
     painter.setFont(font);
     // 标识所有方格动画是否都播放完毕
     bool ok = false;
     while (true)
     {
         // 构造一个画刷 颜色为R G B分量分别为141 121 81的颜色
         QBrush brush(QColor::fromRgb(, , ));
         // 使painter应用这个画刷
         painter.setBrush(brush);

         // 设置画笔为空笔 目的是使绘制的图形没有描边
         painter.setPen(Qt::NoPen);

         // 绘制一个矩形
         painter.drawRect(, , width() - , height() - );

         // 设置画刷颜色为 RGB分量为171 165 141的颜色
         brush.setColor(QColor::fromRgb(, , ));
         // 应用这个画刷
         painter.setBrush(brush);

         // 循环绘制游戏面板
         ; i < ; i++)
             ; j < ; j++)
                 // 绘制小方格
                 painter.drawRect(QRectF( + (w + ) * j,  + (h + ) * i, w, h));

         // 假设都播放完毕
         ok = true;

         // 循环播放每个方格动画
         for (it = animationList.begin(); it != animationList.end(); it++)
             if (!playAnimation(*it, painter))
                 ok = false;

         // 刷新部件
         update();

         // 全部播放完则退出
         if (ok)
             break;

         // 延时5ms
         QTimer::singleShot(, &eventLoop, SLOT(quit()));
         eventLoop.exec();
     }
     // 播放方格出现的动画
     while (!playAnimation(a, painter))
     {
         update();
         QTimer::singleShot(, &eventLoop, SLOT(quit()));
         eventLoop.exec();
     }
     //清除所有动画
     animationList.clear();
     //刷新当前部件
     isAnimating = false;

     // 检测游戏是否获胜
     if (checkWin())
         emit win();// 如果获胜则发射win信号

     update();
 }

 bool GameWidget::playAnimation(Animation& a, QPainter& painter)
 {
     bool rtn = false;
     QBrush brush(Qt::SolidPattern);

     // 移动方格位置
     if (a.type == MOVE)
     {
         switch (a.direct)
         {
         case LEFT:
             if (a.startPos.x() > a.endPos.x())
                 a.startPos += dPos[LEFT];
             else
                 a.startPos = a.endPos, rtn = true;
             break;
         case RIGHT:
             if (a.startPos.x() < a.endPos.x())
                 a.startPos += dPos[RIGHT];
             else
                 a.startPos = a.endPos, rtn = true;
             break;
         case UP:
             if (a.startPos.y() > a.endPos.y())
                 a.startPos += dPos[UP];
             else
                 a.startPos = a.endPos, rtn = true;
             break;
         case DOWN:
             if (a.startPos.y() < a.endPos.y())
                 a.startPos += dPos[DOWN];
             else
                 a.startPos = a.endPos, rtn = true;
         }
         // 如果方格移动到终点
         if (!rtn)
         {
             brush.setColor(digitBkg[getBitCount(a.digit)]);
             painter.setBrush(brush);
             painter.drawRect(QRectF(a.startPos.x(), a.startPos.y(), w, h));
             painter.setPen(QColor::fromRgb(, , ));
             painter.drawText(QRectF(a.startPos.x(), a.startPos.y(), w, h), Qt::AlignCenter,
                              QString::number(a.digit));
         }
         else
         {
             brush.setColor(digitBkg[getBitCount(a.digit2)]);
             painter.setBrush(brush);
             painter.drawRect(QRectF(a.startPos.x(), a.startPos.y(), w, h));
             painter.setPen(QColor::fromRgb(, , ));
             painter.drawText(QRectF(a.startPos.x(), a.startPos.y(), w, h), Qt::AlignCenter,
                              QString::number(a.digit2));
         }
         painter.setPen(Qt::NoPen);
     }
     else
     {
         // 方格出现的动画效果
         if (a.startPos.x() > a.endPos.x())
             a.startPos += dPos[];
         else
             a.startPos = a.endPos, rtn = true;
         brush.setColor(digitBkg[getBitCount(a.digit)]);
         painter.setBrush(brush);
         painter.drawRect(QRectF(a.startPos.x(), a.startPos.y(),
                          w -  * (a.startPos.x() - a.endPos.x()),
                          h -  * (a.startPos.y() - a.endPos.y())));
         painter.setPen(QColor::fromRgb(, , ));
         painter.drawText(QRectF(a.endPos.x(), a.endPos.y(), w, h),
                          Qt::AlignCenter, QString::number(a.digit));
         painter.setPen(Qt::NoPen);
     }
     return rtn;
 }

 void GameWidget::paintEvent(QPaintEvent *)
 {
     // 构造一个QPainter对象 使用它来进行绘图
     QPainter painter(this);

     // 如果正在播放动画效果则绘制缓存位图
     if (isAnimating)
     {
         painter.drawImage(, , *cacheImg);
         return;
     }

     // 构造一个画刷 颜色为R G B分量分别为141 121 81的颜色
     QBrush brush(QColor::fromRgb(, , ));
     // 使painter应用这个画刷
     painter.setBrush(brush);

     // 设置画笔为空笔 目的是使绘制的图形没有描边
     painter.setPen(Qt::NoPen);

     // 绘制一个矩形
     painter.drawRect(, , width() - , height() - );

     // 计算每个小格子的宽度和高度
     w = width() - , h = height() - ;
     w = (w - ) / , h = (h - ) / ;

     /* 构造一个字体
      * 字体名字为Consolas
      * 字体设置为粗体
      * 字体大小为40像素
      * */
     QFont font;
     font.setFamily("Consolas");
     font.setBold(true);
     font.setPixelSize();
     // 使painter应用这个字体
     painter.setFont(font);

     // 循环绘制游戏面板
     ; i < ; i++)
         ; j < ; j++)
         {
             // 如果方格中有数字
             if (board[i][j])
             {
                 // 设置画刷颜色为数码对应的颜色
                 brush.setColor(digitBkg[getBitCount(board[i][j])]);
                 // 应用这个画刷
                 painter.setBrush(brush);
                 // 绘制一个小方格
                 painter.drawRect(QRectF( + (w + ) * j,  + (h + ) * i, w, h));
                 // 设置画笔为黑色画笔
                 painter.setPen(QColor::fromRgb(, , ));
                 // 绘制数码
                 painter.drawText(QRectF( + (w + ) * j,  + (h + ) * i, w, h), Qt::AlignCenter,
                                  QString::number(board[i][j]));
                 // 设置画笔为空笔
                 painter.setPen(Qt::NoPen);
             }
             // 如果方格中没有数字
             else
             {
                 // 设置画刷颜色为 RGB分量为171 165 141的颜色
                 brush.setColor(QColor::fromRgb(, , ));
                 // 应用这个画刷
                 painter.setBrush(brush);
                 // 绘制小方格
                 painter.drawRect(QRectF( + (w + ) * j,  + (h + ) * i, w, h));
             }
         }
 }

 void GameWidget::restart()
 {
     // 初始化相关变量 同构造函数
     score = ;
     digitCount = ;
     memset(board, , sizeof(board));
     board[rand() % ][rand() % ] = ;
     board[rand() % ][rand() % ] = ;
     emit ScoreInc(score);
     update();
 }

 bool GameWidget::checkGameOver()
 {
     // 循环检测是否含有相邻的相同数码
     ; i < ; i++)
         ; j < ; j++)
         {
              && board[i][j] == board[i][j + ])
                 return false;
              && board[i][j] == board[i + ][j])
                 return false;
         }
     return true;
 }

 bool GameWidget::checkWin()
 {
     // 循环检测是否某个方格的数字为2048
     ; i < ; i++)
         ; j < ; j++)
             )
                 return true;
     return false;
 }

 int GameWidget::getBitCount(int n)
 {
     // 循环获取数字二进制位数
     ;
     )
         c++;
     // 返回位数-1
     ;
 }

2048游戏_QT实现的更多相关文章

  1. 用javascript实现一个2048游戏

    早就想自己写一个2048游戏了,昨晚闲着没事,终于写了一个 如下图,按方向键开始玩吧. 如果觉得操作不方便,请直接打开链接玩吧: http://gujianbo.1kapp.com/2048/2048 ...

  2. powershell字符界面的,powershell加WPF界面的,2048游戏

    ------[序言]------ 1 2048游戏,有段时间很火,我在地铁上看有人玩过.没错,坐地铁很无聊,人家玩我就一直盯着看. 2 我在电脑上找了一个,试玩了以下,没几次格子就满了.我就气呼呼的放 ...

  3. &lbrack;python&rsqb; python实现2048游戏,及代码解析。

    我初学python,有不对之处望大家指教.转载请征得同意. 我在网络上也找了一些2048游戏代码的讲解,但都不是特别详细.所以我希望能够尽量详细的讲解.同时,有的地方我也不懂,希望大家能帮助补充.我会 ...

  4. Android项目开发实战-2048游戏

    <2048>是一款比较流行的数字游戏,最早于2014年3月20日发行.原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台.这款游戏是基于&l ...

  5. 对弈类游戏的人工智能&lpar;5&rpar;--2048游戏AI的解读

    前言: 闲得没事, 网上搜"游戏AI", 看到一篇<<2048游戏的最佳算法是?来看看AI版作者的回答>>的文章. 而这篇文章刚好和之前讲的对弈类游戏AI对 ...

  6. 最少javascript代码完成一个2048游戏

    原生javascript代码写的2048游戏.建议在谷歌浏览器下跑.'WASD'控制方向.演示地址请移步:http://runjs.cn/detail/bp8baf8b 直接贴代码~ html: &l ...

  7. cocos2d-x游戏开发实战原创视频讲座系列1之2048游戏开发

     cocos2d-x游戏开发实战原创视频讲座系列1之2048游戏开发 的产生 视持续更新中.... 视频存放地址例如以下:http://ipd.pps.tv/user/1058663622     ...

  8. 用Python做2048游戏 网易云课堂配套实验课。通过GUI来体验编程的乐趣。

    第1节 认识wxpython 第2节 画几个形状 第3节 再做个计算器 第4节 最后实现个2048游戏 实验1-认识wxpython 一.实验说明 1. 环境登录 无需密码自动登录,系统用户名shiy ...

  9. 一个用 C 语言写的迷你版 2048 游戏,仅仅有 500个字符

    Jay Chan 用 C 语言写的一个迷你版 2048 游戏,仅仅有 487 个字符. 来围观吧 M[16],X=16,W,k;main(){T(system("stty cbreak&qu ...

随机推荐

  1. HDU 1556 线段树或树状数组,插段求点

    1.HDU 1556  Color the ball   区间更新,单点查询 2.题意:n个气球,每次给(a,b)区间的气球涂一次色,问最后每个气球各涂了几次. (1)树状数组 总结:树状数组是一个查 ...

  2. C&num; 检测操作系统是否空闲,实现系统空闲后做一些操作

    public class CheckComputerFreeState { /// <summary> /// 创建结构体用于返回捕获时间 /// </summary> [St ...

  3. js控制只能输入数字

    onkeyup=clearNoNum(this) function clearNoNum(obj) {    obj.value = obj.value.replace(/[^\d.]/g,&quot ...

  4. VMware虚拟机扩容

    作者:金良(golden1314521@gmail.com) csdn博客:http://blog.csdn.net/u012176591 用了一段Linux虚拟机.发现安装虚拟机时分配的空间不够用, ...

  5. css笔记——小图标文字对齐中级解决方案

    出处:http://www.zhangxinxu.com/study/201603/icon-text-vertical-align.html css .icon { display: inline- ...

  6. 遍历、显示ftp下的文件夹和文件信息

    今天做了通过ftp读取ftp根目录下的所有文件夹和文件,嵌套文件夹查询,总共用到了一下代码: 1.FtpFile_Directory package com.hs.dts.web.ftp; impor ...

  7. oracle 表查询&lpar;2&rpar;

    使用逻辑操作符号 问题:查询工资高于500 或者是岗位为MANAGER 的雇员,同时还要满足他们的姓名首字母为大写的J? or job = 'MANAGER') and ename LIKE 'J%' ...

  8. WEB 小案例 -- 网上书城(一)

    距离上次写博客有两周了吧,最多的原因就是自己期末考试了,上课没听就只能在期末狠狠的复习了,毕竟已经挂科了.当然还是因为自己懒吧!!!废话不多说开始我们今天的正题,网上书城! 一. 新建数据表(MySQ ...

  9. opencart分类筛选逻辑修改为并且条件

    opencart分类筛选模式默认是或的逻辑,满足条件1或条件2都展现出来,如果想要改成既满足条件1又满足条件2要怎么改呢?有一个插件可以实现,FixFilter OC2x,可以修改默认的筛选条件 1. ...

  10. JAVA 重写equals和重写hashCode

    面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?” 首先你需要了解: hashCode()的作用是获取哈希码(散列码) 它实 ...