扫雷的游戏规则
首先简单的说一下扫雷的游戏规则,是一款9宫格类型的鼠标点击游戏。
点击到地雷,即游戏结束。
标识完全部的地雷,或者将除了地雷以外的地图全部打开即完成游戏的胜利。
每个地雷周围的8个格子都会显示相应数量的地雷数。因此可以判定该格子周边有多少个地雷,依据这个提示信息进行排查。
扫雷游戏实现
布图总的来说是基于9宫格类型来实现的,即按照X,Y坐标轴进行布图。
游戏规则则是通过二维显示层与二维显示层所对应的逻辑层,通过鼠标点击事件衔接在一起实现。
即C++的两个变长数组相套用。vector中再放置一个vector。
因为是相对应,所以单个显示的框框是两个变长数组的vector;
逻辑判断层也是两个变长数组的vector;
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++;
}
}
基本就是这个思路完成了游戏,下面就是自已写的自定义之类的,细节完善的工作,根据自己的癖好修饰修饰;