QT扫雷小结

扫雷的游戏规则

首先简单的说一下扫雷的游戏规则,是一款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++;
    }
}

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容