QT扫雷小结

作者: Seven禅那 | 来源:发表于2017-02-08 12:39 被阅读326次

    扫雷的游戏规则

    首先简单的说一下扫雷的游戏规则,是一款9宫格类型的鼠标点击游戏。
    点击到地雷,即游戏结束。
    标识完全部的地雷,或者将除了地雷以外的地图全部打开即完成游戏的胜利。
    每个地雷周围的8个格子都会显示相应数量的地雷数。因此可以判定该格子周边有多少个地雷,依据这个提示信息进行排查。

    扫雷游戏实现

    布图总的来说是基于9宫格类型来实现的,即按照X,Y坐标轴进行布图。
    游戏规则则是通过二维显示层与二维显示层所对应的逻辑层,通过鼠标点击事件衔接在一起实现。
    即C++的两个变长数组相套用。vector中再放置一个vector。
    因为是相对应,所以单个显示的框框是两个变长数组的vector;
    逻辑判断层也是两个变长数组的vector;

    扫雷.png

    QT界面层

    基于VSI框架

    QGraphicsView容器类

    在这个界面容器类中可以放置QGraphicsScene场景类

    QGraphicsScene场景类

    在这个场景类中可以放置QGraphicsItem图元类,即单个显示的雷框

    QGraphicsItem图元类

    在这个图元类中可以支持贴图和鼠标点击事件,点击事件对应的坐标图元和图元对应逻辑的响应,实现扫雷的游戏

    逻辑处理层

    前面已经提到时两个变长的二维数组相对应实现。
    二维数组xxx[X][Y]相应地址的值与QGraphicsItem的单个坐标图元相对应。

    由于场景显示中共有10种情况,即雷,空白格,和数字1~8;
    所以可以通过给二维变长数组的赋不同值进行区别;
    判断不同的值显示不同的图片;

    QT代码实现

    界面生成

    mian函数

    重点在于要定义一个全局的mainwindow的对象,方便其他类调用

    #include "mainwindow.h"
    #include "myscene.h"
    #include <QApplication>
    #include "model.h"
    
    int width1=8; //单元长度
    int height1=8;//单元高度
    int boomNum=5;//起始地雷数
    int showBoom=boomNum;//显示地雷数字
    int flag=0;//标识
    int go_flag=0;//游戏结束标识
    int time_num;//运行时间
    int win_game=width1*height1-boomNum;//游戏胜利条件
    model m; //图元类对象
    MainWindow *w;//主要窗口指针,方便调用
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow p;
        w=&p; //指针指向分配空间的窗口对象
        w->show();
        return a.exec(); //阻塞显示
    }
    

    mianwindow类

    重点在于那个自适应的边框设定,以后要拉出来,方便自定义游戏的宽度和高度

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        ui->graphicsView->setScene(&sc); //设置界面
    
        sc.setSceneRect(sc.itemsBoundingRect());
        ui->graphicsView->setFixedSize(sc.sceneRect().width() +5,sc.sceneRect().height()+5);//设置单个图元间距
        this->resize(ui->graphicsView->width(),ui->graphicsView->height()+ 105);//设置场景边框大小
    
        ui->label_time->setText("0"); //显示默认时间
        QString temp = QString::number(boomNum,10);
        ui->label_boom->setText(temp);//显示雷数
        time_num=0;
        p=new QTimer;  //计时器
        connect(p,SIGNAL(timeout()),this,SLOT(settime())); //连接计时信号函数
    }
    

    QGraphicsScene类

    构建场景
    固定的格式,将图元添加进场景中;
    重点要新建一个二维变长的vector

    #ifndef MYSCENE_H
    #define MYSCENE_H
    #include "myitem.h"
    #include <QGraphicsScene>
    #include <vector>
    using namespace std;
    typedef vector<myitem*> irow;
    typedef vector<irow> imap;  //变长的二维vector
    class myscene : public QGraphicsScene
    {
        Q_OBJECT
    public:
        explicit myscene(QObject *parent = 0);
        static int Long,Width;
        void removeAlliMx();
        void resetAlliMx();
        imap iMx;
    signals:
    
    public slots:
    };
    
    #endif // MYSCENE_H
    
    myscene::myscene(QObject *parent) : QGraphicsScene(parent)
    {
        for(int i=0;i<width1;i++)
        {
            iMx.push_back(irow(height1));
            for(int j=0;j<height1;j++)
            {
                iMx[i][j] = new myitem(i,j);
                //添加进场景
                addItem(iMx[i][j]);
                //设置图元位置
                iMx[i][j]->setPos(iMx[i][j]->boundingRect().width()*j,iMx[i][j]->boundingRect().height()*i); //坐标构建   iMx对象
            }
        }
    }
    

    QGraphicsPixmapItem类

    整个游戏的难点应该在这个类里面
    要写一个相应图元的递归函数

    #include "myitem.h"
    #include <QPixmap>
    #include "myscene.h"
    #include <QGraphicsScene>
    #include <vector>
    #include <QDebug>
    #include <QGraphicsSceneMouseEvent>
    #include "model.h"
    #include "dialog_gameover.h"
    #include "dialog_wingame.h"
    #include "mainwindow.h"
    extern model m;
    extern int flag;
    extern int width1;
    extern int height1;
    extern int go_flag;
    extern int win_game;
    extern int boomNum;
    extern int showBoom;
    extern MainWindow *w;
    //初始每个图元的显示
    myitem::myitem(int x,int y)
    {
        QPixmap t(":/1.jpg");
        t = t.scaled(60,60);
        setPixmap(t);
        m_x = x;m_y = y;
        rightClick=0;
        m_flag=0;
    }
    
    void myitem::mousePressEvent(QGraphicsSceneMouseEvent * event)//鼠标点击事件虚函数
    {
        ((myscene*)scene())->iMx;
        if(event->button()==Qt::LeftButton)//分辨左点击和右点击
        {
            w->run(); //计时器运行
            showItem(); //调用显示函数
        }
        if(event->button()==Qt::RightButton) //右击事件
        {
            if(0==rightClick) //右击单次
            {
                QPixmap t(":/3.jpg");
                t = t.scaled(60,60);
                setPixmap(t);
                rightClick=1;
                if(showBoom>0)//地雷显示数
                showBoom--;
                w->showboomNum();
            }
            else if(1==rightClick)//右击双次
            {
                QPixmap t(":/1.jpg");
                t = t.scaled(60,60);
                setPixmap(t);
                rightClick=0;
                if(showBoom>=0&&showBoom<boomNum)//地雷显示数
                showBoom++;
                w->showboomNum();
            }
        }
    }
    
    void myitem::showItem()
    {
        if(m_flag)return;
        m_flag=1;
        switch (m.mMx[m_x][m_y]) //匹配二维变长容器,并显示对应图片
        {
        case 0:
        {
            QPixmap t(":/4.jpg");  //导入资源文件
            t = t.scaled(60,60);//设置界面大小
            setPixmap(t);  //显示文件
            win_game--;
            break;
        }
        case -1:
        {
            QPixmap t(":/2.jpg");
            t = t.scaled(60,60);//设置界面大小
            setPixmap(t);
            win_game+=1000;
            showAllItem(); //点击雷则游戏结束,打开全局场景
            break;
        }
        case 1:
        {
            QPixmap t(":/01.jpg");
            t = t.scaled(60,60);//设置界面大小
            setPixmap(t);
            win_game--;
            break;
        }
        case 2:
        {
            QPixmap t(":/02.jpg");
            t = t.scaled(60,60);//设置界面大小
            setPixmap(t);
            win_game--;
            break;
        }
        case 3:
        {
            QPixmap t(":/03.jpg");
            t = t.scaled(60,60);//设置界面大小
            setPixmap(t);
            win_game--;
            break;
        }
        case 4:
        {
            QPixmap t(":/04.jpg");
            t = t.scaled(60,60);//设置界面大小
            setPixmap(t);
            win_game--;
            break;
        }
        case 5:
        {
            QPixmap t(":/05.jpg");
            t = t.scaled(60,60);//设置界面大小
            setPixmap(t);
            win_game--;
            break;
        }
        case 6:
        {
            QPixmap t(":/06.jpg");
            t = t.scaled(60,60);//设置界面大小
            setPixmap(t);
            win_game--;
            break;
        }
        case 7:
        {
            QPixmap t(":/07.jpg");
            t = t.scaled(60,60);//设置界面大小
            setPixmap(t);
            win_game--;
            break;
        }
        case 8:
        {
            QPixmap t(":/08.jpg");
            t = t.scaled(60,60);//设置界面大小
            setPixmap(t);
            win_game--;
            break;
        }
    
        }
    
        if(m.mMx[m_x][m_y]==0) //如果是空白则递归显示
        {
            int myrow;
            int mycolumn;
            for(int i=-1;i<2;i++)
            {
                for(int j=-1;j<2;j++)
                {
                    if(i==0&&j==0)
                    {
                        continue;
                    }
                    myrow=m_x+i;
                    mycolumn=m_y+j;
                    if(myrow<0||mycolumn<0||myrow>=width1||mycolumn>=height1)
                    {
                        continue;
                    }
                    ((myscene*)scene())->iMx[myrow][mycolumn]->showItem(); //循环调用递归函数
    
                }
    
            }
    
        }
        if(0==win_game) //判断胜利
        {
            win_game+=1000;
            go_flag+=1000;
            Dialog_wingame *win = new Dialog_wingame;
            win->show();
            w->stop();
            showAllItem();
        }
    }
    
    
    void myitem::showAllItem()
    {
        for(int i =0;i<width1;i++)
        {
            for(int j=0;j<height1;j++)
            {
                ((myscene*)scene())->iMx[i][j]->showItem();
            }
        }
        if(0 == go_flag) //判断游戏结束
        {
        Dialog_gameover *d = new Dialog_gameover;
        d->show();
        w->stop();
        go_flag++;
        }
    }
    

    基本就是这个思路完成了游戏,下面就是自已写的自定义之类的,细节完善的工作,根据自己的癖好修饰修饰;

    相关文章

      网友评论

        本文标题:QT扫雷小结

        本文链接:https://www.haomeiwen.com/subject/xjngbttx.html