zoukankan      html  css  js  c++  java
  • QT实现2048

    2048是一款很流行的手机游戏。下面我们用QT实现在windows下展现其效果
    程序的启动图:
    这里写图片描述
    下面的代码部分
    (1)widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    #include <QLabel>
    #include <QPushButton>
    #include <QMessageBox>
    #include <QFile>
    #include "GameWidget.h"
    
    #define LBLSTYLESHEET "QLabel {color: orange;background: #FFFFCC;border: %1px solid orange;border-radius: %2px;}"
    #define BTNSTYLESHEET "QPushButton {color: red;background: lightgray;border: %1px solid darkgray;border-radius: %2px;} QPushButton:pressed{color: white;background: orange;border: %1px solid darkgray;border-radius: %2px;}"
    
    // 主窗口部件类
    class Widget : public QWidget
    {
        Q_OBJECT
    
    public:
        // 构造&析构函数
        Widget(QWidget *parent = 0);
        ~Widget();
    
    private:
        // “restart”按钮
        QPushButton *restartBtn;
        // “score”标签
        QLabel *scoreLbl;
        // “HightScore”标签
        QLabel *highScoreLbl;
        // 游戏部件
        GameWidget *gameWidget;
        // 宽度和高度的缩放比例 用来使窗口部件随主窗口的尺寸改变而改变位置与尺寸
        qreal ratioW, ratioH;
        // 记录最高分
        int highScore;
    
    protected:
        // 窗口尺寸改变触发的事件
        void resizeEvent(QResizeEvent *);
    
    public slots:
        // 处理分数增加信号的槽函数
        void onScoreInc(int);
        // 处理游戏结束信号的槽函数
        void onGameOver();
        // 处理游戏获胜信号的槽函数
        void onWin();
    };
    
    #endif // WIDGET_H
    

    widget.cpp

    #include "widget.h"
    
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
    {
        // 初始化最高分为0
        highScore = 0;
        // 读取存储最高分的文件
        QFile file("score.j");
        if (file.open(QIODevice::ReadOnly))
        {
            file.read((char *)&highScore, sizeof(highScore));
            file.close();
        }
    
        // 构造一个游戏部件对象
        gameWidget = new GameWidget(this);
        gameWidget->setGeometry(2, 200, 400, 400);
        connect(gameWidget, SIGNAL(ScoreInc(int)), this, SLOT(onScoreInc(int)));
        connect(gameWidget, SIGNAL(GameOver()), this, SLOT(onGameOver()));
        connect(gameWidget, SIGNAL(win()), this, SLOT(onWin()));
    
        // 构造一个字体对象
        QFont font;
        font.setFamily("Consolas");
        font.setBold(true);
        font.setPixelSize(25);
    
        // 构造一个按钮对象
        restartBtn = new QPushButton("Restart", this);
        restartBtn->setGeometry(100, 120, 200, 50);
        restartBtn->setFont(font);
        restartBtn->setStyleSheet(QString(BTNSTYLESHEET).arg(3).arg(15));
        connect(restartBtn, SIGNAL(clicked()), gameWidget, SLOT(restart()));
    
        // 构造一个标签对象
        highScoreLbl = new QLabel(QString("High Score:
    %1").arg(highScore),this);
        highScoreLbl->setGeometry(209, 20, 180, 70);
        highScoreLbl->setFont(font);
        highScoreLbl->setAlignment(Qt::AlignCenter);
        highScoreLbl->setStyleSheet(QString(LBLSTYLESHEET).arg(5).arg(20));
    
        // 构造一个标签对象
        scoreLbl = new QLabel("Score:
    0", this);
        scoreLbl->setGeometry(15, 20, 180, 70);
        scoreLbl->setFont(font);
        scoreLbl->setAlignment(Qt::AlignCenter);
        scoreLbl->setStyleSheet(QString(LBLSTYLESHEET).arg(5).arg(20));
    
        // 重置窗口大小
        //resize(404, 606);
    }
    
    Widget::~Widget()
    {
        // 释放相关对象
        delete restartBtn;
        delete scoreLbl;
        delete highScoreLbl;
        delete gameWidget;
    }
    
    void Widget::onScoreInc(int score)
    {
        // 更新分数显示
        scoreLbl->setText(QString("Score:
    %1").arg(score));
        // 如果当前分数高于最高分
        if (score > highScore)
        {
            // 更新最高分
            highScore = score;
            highScoreLbl->setText(QString("High Score:
    %1").arg(highScore));
    
            // 将新的最高分存入文件
            QFile file("score.j");
            file.open(QIODevice::WriteOnly);
            file.write((char *)&highScore, sizeof(highScore));
            file.close();
        }
    }
    
    void Widget::onGameOver()
    {
        QMessageBox::information(this, "GameOver", "You lost !");
    }
    
    void Widget::onWin()
    {
        QMessageBox::information(this, "Congratulation", "You win !");
    }
    
    void Widget::resizeEvent(QResizeEvent *)
    {
        // 计算宽度和高度的缩放比例
        ratioW = width() / 404.0;
        ratioH = height() / 606.0;
        // 构造一个字体对象
        QFont font;
        font.setFamily("Consolas");
        font.setBold(true);
        font.setPixelSize(25 * ratioH);
        restartBtn->setFont(font);
        highScoreLbl->setFont(font);
        scoreLbl->setFont(font);
        restartBtn->setStyleSheet(QString(BTNSTYLESHEET).arg(3 * ratioW).arg(15 * ratioW));
        highScoreLbl->setStyleSheet(QString(LBLSTYLESHEET).arg(5 * ratioW).arg(20 * ratioW));
        scoreLbl->setStyleSheet(QString(LBLSTYLESHEET).arg(5 * ratioW).arg(20 * ratioW));
        // 重置子部件大小和位置
        gameWidget->setGeometry(2 * ratioW, 200 * ratioH, 400 * ratioW, 400 * ratioH);
        restartBtn->setGeometry(100 * ratioW, 120 * ratioH, 200 * ratioW, 50 * ratioH);
        highScoreLbl->setGeometry(209 * ratioW, 20 * ratioH, 180 * ratioW, 70 * ratioH);
        scoreLbl->setGeometry(15 * ratioW, 20 * ratioH, 180 * ratioW, 70 * ratioH);
    }
    

    GameWidget.h

    #ifndef GAMEWIDGET_H
    #define GAMEWIDGET_H
    
    #include <QGLWidget>
    #include <QMouseEvent>
    #include <QEventLoop>
    #include <QTimer>
    #include <QPainter>
    #include <QList>
    
    // 手势的方向
    enum GestureDirect
    {
        LEFT = 0,   // 向左
        RIGHT = 1,  // 向右
        UP = 2,     // 向上
        DOWN = 3    // 向下
    };
    
    // 定义动画的类型
    enum AnimationType
    {
        MOVE = 0,       // 方格移动动画
        APPEARANCE = 1  // 方格出现动画
    };
    
    // 动画结构体
    struct Animation
    {
        AnimationType type;     // 动画类型
        GestureDirect direct;   // 方向
        QPointF startPos;       // 起始点坐标 出现动画仅仅使用这个坐标
        QPointF endPos;         // 终止点坐标 移动动画的终点坐标
        int digit;              // 数码
        int digit2;             // 第二数码 数码可能被合并
    };
    
    // 游戏部件类 继承自QWidget
    class GameWidget : public QGLWidget
    {
        Q_OBJECT
    public:
        // 构造函数
        explicit GameWidget(QWidget *parent = 0);
    
    private:
        // 游戏面板 存储每个格子的数值
        int board[4][4];
        // 数码的个数 存储当前面板上的数字的个数
        int digitCount;
        // 分数 存储当前得分
        int score;
        // 起始点坐标 存储手势起点坐标
        QPoint startPos;
        // 存储所有需要展现的动画
        QList<Animation> animationList;
        // 小格子的宽度和高度
        qreal w, h;
        // 宽度和高度的缩放比例
        qreal ratioW, ratioH;
        // 小圆角的 x y
        qreal rX, rY;
        // 缓存图像
        //QImage *cacheImg;
        // 是否在播放动画效果
        bool isAnimating;
        // 计时器
        QTimer timer;
    
        // 初始化两个方格
        void init2Block();
        // 检测游戏是否结束
        bool checkGameOver();
        // 检测游戏是否获胜
        bool checkWin();
        /* 获取一个数字的二进制位数 当然这里获取的不完全是二进制位数 而是对应颜色数组的下标
        比如 2 对应 0    8 对应 2*/
        int getBitCount(int);
        // 播放一帧动画
        bool playAnimation(Animation&, QPainter&);
        // 绘制动画效果
        bool drawAnimation(QPainter&);
        // 鼠标按下触发的事件
        void mousePressEvent(QMouseEvent *);
        // 鼠标释放触发的时间
        void mouseReleaseEvent(QMouseEvent *);
        // 绘制事件
        void paintEvent(QPaintEvent *);
        // 窗口尺寸改变事件
        void resizeEvent(QResizeEvent *);
    
        // 以下为一些信号
    signals:
        // 手势移动信号
        void GestureMove(GestureDirect);
        // 分数增加信号
        void ScoreInc(int);
        // 游戏结束信号
        void GameOver();
        // 游戏获胜信号
        void win();
    
        // 以下为一些槽函数
    public slots:
        // 处理手势移动信号的槽函数
        void onGestureMove(GestureDirect);
        // 重新开始的槽函数
        void restart();
    
    };
    
    #endif // GAMEWIDGET_H
    

    GameWidget.cpp

    #include "GameWidget.h"
    
    // 颜色数组 存储每个数字对应的背景色
    QColor digitBkg[11] = {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[5];
    
    GameWidget::GameWidget(QWidget *parent) :
        QGLWidget(QGLFormat(QGL::SampleBuffers), parent),
        timer(this)
    {
        // 连接手势移动信号和相应的槽函数
        connect(this, SIGNAL(GestureMove(GestureDirect)), SLOT(onGestureMove(GestureDirect)));
        // 连接时钟信号和画板更新的槽
        connect(&timer, SIGNAL(timeout()), this, SLOT(update()));
        // 初始化board数组
        memset(board, 0, sizeof(board));
        // 分数初始化为0
        score = 0;
        // 数码个数初始化为2
        digitCount = 2;
        // 没有在播放动画效果
        isAnimating = false;
        // 初始化两个方格
        init2Block();
    }
    
    void GameWidget::init2Block()
    {
        board[rand() % 4][rand() % 4] = 2;
        int i = rand() % 4, j = rand() % 4;
        while (board[i][j] != 0)
            i = rand() % 4, j = rand() % 4;
        board[i][j] = 2;
        update();
    }
    
    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))
        {
            if (dX < 0)
                emit GestureMove(LEFT);
            else
                emit GestureMove(RIGHT);
        }
        else
        {
            if (dY < 0)
                emit GestureMove(UP);
            else
                emit GestureMove(DOWN);
        }
    }
    
    void GameWidget::onGestureMove(GestureDirect direct)
    {
        int i, j, k;
        Animation a;
        // 记录是否移动过方格以及是否有方格合并
        bool move = false, combine = false;
        // 记录某个格子是否参与过合并
        bool isCombined[4][4];
        memset(isCombined, 0, sizeof(isCombined));
        // 处理不同方向
        switch (direct)
        {
        // 向左
        case LEFT:
            // 循环每一行
            for (i = 0; i < 4; i++)
            {
                /* 初始化j k为0
                 * 这里j表示要交换的数字列号
                 * k表示交换到的位置的列号
                 * */
                j = 0, k = 0;
                while (true)
                {
                    // 循环找到第一个不是0的数字对应的列号
                    while (j < 4 && board[i][j] == 0)
                        j++;
                    // 如果超过了3则说明搜索完毕 推出循环
                    if (j > 3)
                        break;
                    // 交换两个数字
                    qSwap(board[i][k], board[i][j]);
                    if (j != k)
                        move = true;
                    // 记录动画信息
                    a.type = MOVE;
                    a.startPos = QPointF(7 * ratioW + (w + 5 * ratioW) * j, 7 * ratioH + (h + 5 * ratioH) * i);
                    a.endPos = QPointF(7 * ratioW + (w + 5 * ratioW) * k, 7 * ratioH + (h + 5 * ratioH) * i);
                    a.digit = a.digit2 = board[i][k];
                    a.direct = LEFT;
                    //如果交换后的数字与其前一列的数字相同
                    if (k > 0 && board[i][k] == board[i][k - 1] && !isCombined[i][k - 1])
                    {
                        // 前一列的数字*2
                        board[i][k - 1] <<= 1;
                        // i k-1 方格参与过合并
                        isCombined[i][k - 1] = true;
                        // 这一列的数字置为0
                        board[i][k] = 0;
                        // 有方格合并
                        combine = true;
                        // 记录动画信息
                        a.digit2 = board[i][k - 1];
                        a.endPos = QPointF(7 * ratioW + (w + 5 * ratioW) * (k - 1), 7 * ratioH + (h + 5 * ratioH) * i);
                        // 增加分数
                        score += board[i][k - 1];
                        // 发射增加分数的信号
                        emit ScoreInc(score);
                        // 数码个数-1
                        digitCount--;
                    }
                    else
                        k++;
                    j++;
                    // 添加到动画链表
                    animationList.append(a);
                }
            }
            break;
            // 其余三个方向与左向类似
        case RIGHT:
            for (i = 0; i < 4; i++)
            {
                j = 3, k = 3;
                while (true)
                {
                    while (j > -1 && board[i][j] == 0)
                        j--;
                    if (j < 0)
                        break;
                    qSwap(board[i][k], board[i][j]);
                    if (j != k)
                        move = true;
                    a.type = MOVE;
                    a.startPos = QPointF(7 * ratioW + (w + 5 * ratioW) * j, 7 * ratioH + (h + 5 * ratioH) * i);
                    a.endPos = QPointF(7 * ratioW + (w + 5 * ratioW) * k, 7 * ratioH + (h + 5 * ratioH) * i);
                    a.digit = a.digit2 = board[i][k];
                    a.direct = RIGHT;
                    if (k < 3 && board[i][k] == board[i][k + 1] && !isCombined[i][k + 1])
                    {
                        board[i][k + 1] <<= 1;
                        isCombined[i][k + 1] = true;
                        board[i][k] = 0;
                        combine = true;
                        a.digit2 = board[i][k + 1];
                        a.endPos = QPointF(7 * ratioW + (w + 5 * ratioW) * (k + 1), 7 * ratioH + (h + 5 * ratioH) * i);
                        score += board[i][k + 1];
                        emit ScoreInc(score);
                        digitCount--;
                    }
                    else
                        k--;
                    j--;
                    animationList.append(a);
                }
            }
            break;
        case UP:
            for (i = 0; i < 4; i++)
            {
                j = 0, k = 0;
                while (true)
                {
                    while (j < 4 && board[j][i] == 0)
                        j++;
                    if (j > 3)
                        break;
                    qSwap(board[k][i], board[j][i]);
                    if (j != k)
                        move = true;
                    a.type = MOVE;
                    a.startPos = QPointF(7 * ratioW + (w + 5 * ratioW) * i, 7 * ratioH + (h + 5 * ratioH) * j);
                    a.endPos = QPointF(7 * ratioW + (w + 5 * ratioW) * i, 7 * ratioH + (h + 5 * ratioH) * k);
                    a.digit = a.digit2 = board[k][i];
                    a.direct = UP;
                    if (k > 0 && board[k][i] == board[k - 1][i] && !isCombined[k - 1][i])
                    {
                        board[k - 1][i] <<= 1;
                        isCombined[k - 1][i] = true;
                        board[k][i] = 0;
                        combine = true;
                        a.digit2 = board[k - 1][i];
                        a.endPos = QPointF(7 * ratioW + (w + 5 * ratioW) * i, 7 * ratioH + (h + 5 * ratioH) * (k - 1));
                        score += board[k - 1][i];
                        emit ScoreInc(score);
                        digitCount--;
                    }
                    else
                        k++;
                    j++;
                    animationList.append(a);
                }
            }
            break;
        case DOWN:
            for (i = 0; i < 4; i++)
            {
                j = 3, k = 3;
                while (true)
                {
                    while (j > -1 && board[j][i] == 0)
                        j--;
                    if (j < 0)
                        break;
                    qSwap(board[k][i], board[j][i]);
                    if (j != k)
                        move = true;
                    a.type = MOVE;
                    a.startPos = QPointF(7 * ratioW + (w + 5 * ratioW) * i, 7 * ratioH + (h + 5 * ratioH) * j);
                    a.endPos = QPointF(7 * ratioW + (w + 5 * ratioW) * i, 7 * ratioH + (h + 5 * ratioH) * k);
                    a.digit = a.digit2 = board[k][i];
                    a.direct = DOWN;
                    if (k < 3 && board[k][i] == board[k + 1][i] && !isCombined[k + 1][i])
                    {
                        board[k + 1][i] <<= 1;
                        isCombined[k + 1][i] = true;
                        board[k][i] = 0;
                        combine = true;
                        a.digit2 = board[k + 1][i];
                        a.endPos = QPointF(7 * ratioW + (w + 5 * ratioW) * i, 7 * ratioH + (h + 5 * ratioH) * (k + 1));
                        score += board[k + 1][i];
                        emit ScoreInc(score);
                        digitCount--;
                    }
                    else
                        k--;
                    j--;
                    animationList.append(a);
                }
            }
            break;
        }
    
        // 如果数字木有填满
        if ((move || combine) && digitCount != 16)
        {
            // 随机产生行号和列号
            i = rand() % 4, j = rand() % 4;
            // 循环直到行和列对应的元素为0
            while (board[i][j] != 0)
                i = rand() % 4, j = rand() % 4;
            // 填入2
            board[i][j] = (rand() % 2 + 1) * 2;
            // 记录动画信息
            a.type = APPEARANCE;
            a.startPos = a.endPos = QPointF(7 * ratioW + (w + 5 * ratioW) * j, 7 * ratioH + (h + 5 * ratioH) * i);
            a.startPos += QPointF(w / 2, h / 2);
            a.digit = board[i][j];
            animationList.append(a);
            // 数码个数加一
            digitCount++;
        }
    
        // 开始绘制动画效果
        isAnimating = true;
    
        // 启动计时器
        timer.start(10);
    }
    
    bool GameWidget::drawAnimation(QPainter &painter)
    {
        // 动画列表的迭代器
        QList<Animation>::iterator it;
    
        // 字体
        QFont font;
        font.setFamily("Consolas");
        font.setBold(true);
        font.setPixelSize(40 * ratioH);
        painter.setFont(font);
    
        // 标识所有方格动画是否都播放完毕
        bool ok = true;
    
        // 构造一个画刷 颜色为R G B分量分别为141 121 81的颜色
        QBrush brush(QColor::fromRgb(141, 121, 81));
        // 使painter应用这个画刷
        painter.setBrush(brush);
    
        // 设置画笔为空笔 目的是使绘制的图形没有描边
        painter.setPen(Qt::NoPen);
    
        // 绘制一个矩形
        painter.drawRoundedRect(QRectF(2 * ratioW, 2 * ratioH, width() - 4 * ratioW, height() - 4 * ratioH), rX, rY);
    
        // 设置画刷颜色为 RGB分量为171 165 141的颜色
        brush.setColor(QColor::fromRgb(171, 165, 141));
        // 应用这个画刷
        painter.setBrush(brush);
    
        // 循环绘制游戏面板
        for (int i = 0; i < 4; i++)
            for (int j = 0; j < 4; j++)
                // 绘制小方格
                painter.drawRoundedRect(QRectF(7 * ratioW + (w + 5 * ratioW) * j, 7 * ratioH + (h + 5 * ratioH) * i, w, h), rX, rY);
    
        // 循环播放每个方格动画
        for (it = animationList.begin(); it != animationList.end(); it++)
            if (!playAnimation(*it, painter))
                ok = false;
    
        return ok;
    }
    
    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.drawRoundedRect(QRectF(a.startPos.x(), a.startPos.y(), w, h), rX, rY);
                painter.setPen(QColor::fromRgb(0, 0, 0));
                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.drawRoundedRect(QRectF(a.startPos.x(), a.startPos.y(), w, h), rX, rY);
                painter.setPen(QColor::fromRgb(0, 0, 0));
                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[4];
            else
                a.startPos = a.endPos, rtn = true;
            brush.setColor(digitBkg[getBitCount(a.digit)]);
            painter.setBrush(brush);
            painter.drawRoundedRect(QRectF(a.startPos.x(), a.startPos.y(),
                             w - 2 * (a.startPos.x() - a.endPos.x()),
                             h - 2 * (a.startPos.y() - a.endPos.y())), rX, rY);
            painter.setPen(QColor::fromRgb(0, 0, 0));
            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);
    
        // 设置反锯齿绘图
        painter.setRenderHint(QPainter::Antialiasing);
    
        // 如果正在播放动画效果则绘制缓存位图
        if (isAnimating)
        {
            if (drawAnimation(painter))
            {
                isAnimating = false;
                timer.stop();
                //清除所有动画
                animationList.clear();
                if (digitCount == 16)
                {
                    // 如果数字填满了 检测游戏是否over
                    if (checkGameOver())
                        emit GameOver();// 如果游戏over了则发射GameOver信号
                }
                // 检测游戏是否获胜
                if (checkWin())
                    emit win();// 如果获胜则发射win信号
            }
            return;
        }
    
        // 构造一个画刷 颜色为R G B分量分别为141 121 81的颜色
        QBrush brush(QColor::fromRgb(141, 121, 81));
        // 使painter应用这个画刷
        painter.setBrush(brush);
    
        // 设置画笔为空笔 目的是使绘制的图形没有描边
        painter.setPen(Qt::NoPen);
    
        // 绘制一个矩形
        painter.drawRoundedRect(QRectF(2 * ratioW, 2 * ratioH, width() - 4 * ratioW, height() - 4 * ratioH), rX, rY);
    
        /* 构造一个字体
         * 字体名字为Consolas
         * 字体设置为粗体
         * 字体大小为40像素
         * */
        QFont font;
        font.setFamily("Consolas");
        font.setBold(true);
        font.setPixelSize(40 * ratioH);
        // 使painter应用这个字体
        painter.setFont(font);
    
        // 循环绘制游戏面板
        for (int i = 0; i < 4; i++)
            for (int j = 0; j < 4; j++)
            {
                // 如果方格中有数字
                if (board[i][j])
                {
                    // 设置画刷颜色为数码对应的颜色
                    brush.setColor(digitBkg[getBitCount(board[i][j])]);
                    // 应用这个画刷
                    painter.setBrush(brush);
                    // 绘制一个小方格
                    painter.drawRoundedRect(QRectF(7 * ratioW + (w + 5 * ratioW) * j, 7 * ratioH + (h + 5 * ratioH) * i, w, h), rX, rY);
                    // 设置画笔为黑色画笔
                    painter.setPen(QColor::fromRgb(0, 0, 0));
                    // 绘制数码
                    painter.drawText(QRectF(7 * ratioW + (w + 5 * ratioW) * j, 7 * ratioH + (h + 5 * ratioH) * i, w, h), Qt::AlignCenter,
                                     QString::number(board[i][j]));
                    // 设置画笔为空笔
                    painter.setPen(Qt::NoPen);
                }
                // 如果方格中没有数字
                else
                {
                    // 设置画刷颜色为 RGB分量为171 165 141的颜色
                    brush.setColor(QColor::fromRgb(171, 165, 141));
                    // 应用这个画刷
                    painter.setBrush(brush);
                    // 绘制小方格
                    painter.drawRoundedRect(QRectF(7 * ratioW + (w + 5 * ratioW) * j, 7 * ratioH + (h + 5 * ratioH) * i, w, h), rX, rY);
                }
            }
    }
    
    void GameWidget::resizeEvent(QResizeEvent *)
    {
        ratioW = width() / 400.0, ratioH = height() / 400.0;
        // 计算每个小格子的宽度和高度
        w = width() - 4 * ratioW, h = height() - 4 * ratioH;
        w = (w - 25 * ratioW) / 4, h = (h - 25 * ratioH) / 4;
        rX = 15 * ratioW, rY = 15 * ratioH;
        dPos[0] = QPointF(-25 * ratioW, 0);
        dPos[1] = QPointF(25 * ratioW, 0);
        dPos[2] = QPointF(0, -25 * ratioH);
        dPos[3] = QPointF(0, 25 * ratioH);
        dPos[4] = QPointF(-4 * ratioW, -4 * ratioH);
    }
    
    void GameWidget::restart()
    {
        // 初始化相关变量 同构造函数
        score = 0;
        digitCount = 2;
        memset(board, 0, sizeof(board));
        init2Block();
        emit ScoreInc(score);
        update();
    }
    
    bool GameWidget::checkGameOver()
    {
        // 循环检测是否含有相邻的相同数码
        for (int i = 0; i < 4; i++)
            for (int j = 0; j < 4; j++)
            {
                if (j != 3 && board[i][j] == board[i][j + 1])
                    return false;
                if (i != 3 && board[i][j] == board[i + 1][j])
                    return false;
            }
        return true;
    }
    
    bool GameWidget::checkWin()
    {
        // 循环检测是否某个方格的数字为2048
        for (int i = 0; i < 4; i++)
            for (int j = 0; j < 4; j++)
                if (board[i][j] == 2048)
                    return true;
        return false;
    }
    
    int GameWidget::getBitCount(int n)
    {
        // 循环获取数字二进制位数
        int c = 0;
        while (n >>= 1)
            c++;
        // 返回位数-1
        return c - 1;
    }
    

    main.cpp

    #include "widget.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget w;
        w.show();
    
        return a.exec();
    }
    
  • 相关阅读:
    c#基于业务对象的筛选
    SQLServer索引调优实践
    C#中抽象类和接口的区别
    c#基础(2) 理解委托和事件
    建议学习jQuery的步骤!
    SQL SERVER存储过程调用存储过程并接收输出参数或返回值的方法
    ASP.NET基于JQUERY的高性能的TreeView
    GetManifestResourceStream得到的Stream是null的解决
    Using GDI+ on Windows Mobile 初体验
    提供一个Windows mobile Native UI 程序,循序渐进开发,并附有代码!
  • 原文地址:https://www.cnblogs.com/NaCl/p/9580103.html
Copyright © 2011-2022 走看看