代码拉取完成,页面将自动刷新
#include "MainWindow.h"
#include "ui_mainwindow.h"
#include <QAbstractButton>
#include <QMessageBox>
#include <QPaintEvent>
#include <QPainter>
#include <QTime>
//待解决:需要完善findall条件
//已解决:需要改变界面颜色
//待解决:需要添加历史记录功能
//已解决:改变item点开后的数字大小
//待解决:历史记录功能
//待解决:第一次点击不炸
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//菜单栏 初始化
menu1=new QMenu("新游戏",this);
menu2=new QMenu("难度",this);
menu3=new QMenu("历史纪录",this);
ui->menuBar->addMenu(menu1);
ui->menuBar->addMenu(menu2);
ui->menuBar->addMenu(menu3);
connect(menu1,SIGNAL(aboutToShow()),this,SLOT(slot_newGame()));
//Action 初始化
easy=new QAction("easy",this);
normal=new QAction("normal",this);
hard=new QAction("hard",this);
self=new QAction("自定义",this);
max=new QAction("最高记录",this);
menu2->addAction(easy);
menu2->addAction(normal);
menu2->addAction(hard);
menu2->addAction(self);
menu3->addAction(max);
connect(easy,SIGNAL(triggered()),this,SLOT(slot_level_easy()));
connect(normal,SIGNAL(triggered()),this,SLOT(slot_level_normal()));
connect(hard,SIGNAL(triggered()),this,SLOT(slot_level_hard()));
connect(self,SIGNAL(triggered()),this,SLOT(slot_level_self()));
dialogSelf=new Dialog(this);
connect(dialogSelf,SIGNAL(dia_test()),this,SLOT(slot_level_self_get()));
flagImage = QPixmap(":/images/images/flag.png"); //旗帜
bombImage = QPixmap(":/images/images/bomb.png"); //雷
//默认打开为简单难度
rows = 9;
cols = 9;
mine = 10;
newGame();
}
//主窗口的析构函数
MainWindow::~MainWindow()
{
delete ui;
}
//定义初始化游戏并放置方格的函数
void MainWindow::initItems()
{
//随机初始化 雷
Mines.clear();
for(int i = 0; i<mine; i++)
{
qsrand(QTime::currentTime().msec());
int x = qrand()%cols;
int y = qrand()%rows;
while(Mines.contains(QPoint(x,y)))
{//当已经包含了这个雷 则重新随机生成一个雷
x = qrand()%cols;
y = qrand()%rows;
}
Mines.append(QPoint(x,y));
}
//建立2维数组保存所有元素位置,方便索引
for(int i=0; i<cols; i++) //列
{
QVector<Item*> rowItems;//Item对象指针的容器
for(int j=0; j<rows; j++)
{
QPoint pos = QPoint(i,j);
Item* pItem = new Item(pos);
if(Mines.contains(pos)) //若该位置是雷
{
pItem->isMine = true;
}
rowItems.append(pItem);
}
items.append(rowItems);
}
//计算格子的数字
for(int i=0; i<cols; i++)
{
for(int j=0; j<rows; j++)
{
if (items[i][j]->isMine)
{
continue;
}
int nCountMines = 0;
//求每个点附近的8个点的是雷的总数
for (int m=-1;m<=1;m++)
{
for (int n=-1; n<=1;n++)
{
if (m==0 && n==0)
{
continue;
}
QPoint ptNew = QPoint(i+m,j+n);
if (!pointInGameArea(ptNew))
{
continue;
}
if (items[i+m][j+n]->isMine)
{
nCountMines++;
}
}
}
items[i][j]->number = nCountMines;
}
}
}
//定义释放所有方格对象的函数
void MainWindow::releaseItems()
{ //清除所有的指针
//释放空间
for (int i=0; i<items.size(); i++)
{
for (int j=0;j<items[i].size(); j++)
{
if (items[i][j] != nullptr)
{
delete items[i][j];
items[i][j] = nullptr;
}
}
}
items.clear();
}
//定义新游戏函数
void MainWindow::newGame()
{
m_bGameFail = false;
//初始化界面大小
resize(START_X*2 + cols*RECT_WIDTH ,START_Y*2 + rows*RECT_HEIGHT);
//设置固定大小
this->setFixedSize(START_X*2 + cols*RECT_WIDTH ,START_Y*2 + rows*RECT_HEIGHT);
//释放所有方格对象
releaseItems();
//初始化游戏并放置方格
initItems();
}
//定义失败结束游戏的函数(需要改进结束条件)
void MainWindow::overGame()
{
m_bGameFail = true;
for (int i=0; i<items.size(); i++)
{
for (int j=0;j<items[i].size(); j++)
{
if (items[i][j]->isMine)
{
items[i][j]->isMarked = true;
}
else
{
items[i][j]->isMarked = false;
items[i][j]->isOpen = true;
}
}
}
}
//每次点击之后都会调用这个函数 判断是否找全
bool MainWindow::findAll()
{
//创建布尔值 表示默认已经找到全部雷 后续遍历中只要有一个非雷格子没有被打开 那么就是没有findall
bool bFindAll = true;
int findnum=0;
//遍历二维数组 QVector<QVector<Item*>> m_items 也就是对每一个item进行判断
for (int i=0; i<items.size(); i++)
{
for (int j=0;j<items[i].size(); j++)
{
//findall的情形
//全部的非雷都被打开
//否则没有findall
//创建对应坐标的item类对象
Item* pItem = items[i][j];
//忽略是雷的格子
//无论是雷的格子是否标记、是否全部标记
//只要非雷的格子全部打开就代表findall
//初始值为true findall
//遍历过程中只要找到一个没有打开的非雷格子
//bFindAll值就变为false
//遍历后没有没打开的非雷格子
//bFindAll值维持true
if(!pItem->isMine)
{
if(!pItem->isOpen)
{
bFindAll=false;
}
}
//原始判定条件
// //如果该对象是雷
// if (pItem->isMine)
// {
// if (!pItem->isMarked)
// {
// bFindAll = false;
// }
// }
// //如果该对象不是雷
// else
// {
// if (!pItem->isOpen)
// {
// bFindAll = false;
// }
// }
}
}
return bFindAll;
}
//绘图事件 布置背景板和方格
void MainWindow::paintEvent(QPaintEvent *)
{
drawBoard();
drawItems();
//刷新游戏画面
update();
}
//鼠标事件 左键右键点击 点击后都要判断是否findall
void MainWindow::mousePressEvent(QMouseEvent *e)
{
//得到鼠标处的格子坐标
QPoint pt;
pt.setX( (e->pos().x() - START_X ) / RECT_WIDTH);
pt.setY( (e->pos().y() - START_X ) / RECT_HEIGHT);
//是否点在游戏区域内
if (!pointInGameArea(pt))
{
return; //如果不在游戏区域内 不做反应
}
//获取所点击矩形元素
Item* pItem = items[pt.x()][pt.y()];
//左键打开元素
if(e->button()==Qt::LeftButton)
{
//不是已标记的或已打开的空白点,也就是未处理的
if(!pItem->isMarked && !pItem->isOpen)
{
//如果是雷,就GAME OVER
if (pItem->isMine)
{
//弹出游戏结束窗口
overGame();
//弹出选择窗口 选择yes就newgame重新初始化游戏 选择no就退出程序
QMessageBox::StandardButton ret;
ret=QMessageBox::information(nullptr, "失败","是否重试?",
QMessageBox::Yes , QMessageBox::No);
if(ret==QMessageBox::Yes)
{
newGame();
}
else
{
QApplication::quit();
}
return;
}
//如果不是雷,打开并判断是否findall
else
{
//打开
pItem->isOpen = true;
if (pItem->number == 0)
{
//如果数字是0,也就是不含任何相邻雷的元素,那么递归打开所有的相邻数字是0的元素
//也就是点到一个空白处,一下打开一大片的效果
openEmptyItem(pt);
}
//如果已找到所有雷 这里需要完善findall的条件
if (findAll())
{
//弹出成功窗口
QMessageBox::StandardButton ret;
//弹出选择窗口 选择yes就newgame重新初始化游戏 选择no就退出程序
ret=QMessageBox::information(nullptr, "成功","是否开始新游戏?",
QMessageBox::Yes , QMessageBox::No);
if(ret==QMessageBox::Yes)
{
newGame();
}
else
{
QApplication::quit();
}
return;
}
}
}
}
//右键插旗帜标记
else if(e->button()==Qt::RightButton)
{
//已标记过的,取消标记
if (pItem->isMarked)
{
pItem->isMarked = false;
}
else if (!pItem->isOpen)
{
//没标记也没打开,就插旗帜标记上
pItem->isMarked = true;
//判断是否findall
if (findAll())
{
QMessageBox::StandardButton ret;
//弹出选择窗口 选择yes就newgame重新初始化游戏 选择no就退出程序
ret=QMessageBox::information(nullptr, "成功","是否开始新游戏?",
QMessageBox::Yes , QMessageBox::No);
if(ret==QMessageBox::Yes)
{
newGame();
}
else
{
QApplication::quit();
}
return;
}
}
}
}
//(初始化)绘制背景板的函数
void MainWindow::drawBoard()
{
QPainter painter(this);
painter.setBrush(Qt::lightGray);
painter.drawRect( 0,0,width(),height());
}
//(初始化)绘制格子的函数
void MainWindow::drawItems()
{
QPainter painter(this);
painter.setBrush(Qt::lightGray);
painter.setPen(QPen(QColor(Qt::black),2));
for(int i=0; i<cols; i++)
{
for(int j=0; j<rows; j++)
{
drawItem(painter,items[i][j]);
}
}
}
//格子变化后的绘制函数
void MainWindow::drawItem(QPainter &painter, Item *pItem)
{
//如果格子已经插旗
if(pItem->isMarked)
{
if (m_bGameFail)
{
//如果扫雷失败,游戏结束,显示雷
QRect rcSrc(0,0,flagImage.width(),flagImage.height());
QRect rcTarget(START_X + pItem->m_pos.x()*RECT_WIDTH + 2,START_Y + pItem->m_pos.y()*RECT_HEIGHT + 2,RECT_WIDTH-4,RECT_HEIGHT-4);
painter.drawPixmap(rcTarget,bombImage,rcSrc);
}
else
{
//游戏没结束,显示为旗子
QRect rcSrc(0,0,flagImage.width(),flagImage.height());
QRect rcTarget(START_X + pItem->m_pos.x()*RECT_WIDTH + 2,START_Y + pItem->m_pos.y()*RECT_HEIGHT + 2,RECT_WIDTH-4,RECT_HEIGHT-4);
painter.drawPixmap(rcTarget,flagImage,rcSrc);
}
painter.setBrush(Qt::transparent);
painter.drawRect( START_X + pItem->m_pos.x()*RECT_WIDTH,START_Y + pItem->m_pos.y()*RECT_HEIGHT,RECT_WIDTH,RECT_HEIGHT);
return;
}
//如果格子被点开
else if (pItem->isOpen)
{
if(pItem->number == 0)
{
painter.setBrush(Qt::gray);
}
else
{
QFont font;
font.setPointSize(20);
font.setFamily(("msyh"));
font.setBold(true);
font.setFamily("Microsoft YaHei");
font.setPointSize(6);
//float f = pItem->m_nNumber/8;
//painter.setBrush(QColor(f*255,f*255,0));
painter.setBrush(Qt::gray);
painter.drawRect( START_X + pItem->m_pos.x()*RECT_WIDTH,
START_Y + pItem->m_pos.y()*RECT_HEIGHT,RECT_WIDTH,RECT_HEIGHT);
painter.setBrush(Qt::white);
painter.setFont(font);
painter.drawText( START_X + pItem->m_pos.x()*RECT_WIDTH + 8,
START_Y + pItem->m_pos.y()*RECT_HEIGHT + 22,QString("%1").arg(pItem->number));
return;
}
}
else
{
painter.setBrush(Qt::white);
}
painter.drawRect( START_X + pItem->m_pos.x()*RECT_WIDTH,START_Y + pItem->m_pos.y()*RECT_HEIGHT,RECT_WIDTH,RECT_HEIGHT);
}
//运气好时点到一个空白元素,可能打开挨着的一大片
void MainWindow::openEmptyItem(QPoint pt)
{
//对于空白元素,有上下左右4个方向挨着的空白元素,就打开并继续查找空白元素
QVector<QPoint> directions;
directions.push_back(QPoint(-1,0));
directions.push_back(QPoint(1,0));
directions.push_back(QPoint(0,-1));
directions.push_back(QPoint(0,1));
for (int i=0; i<directions.size(); i++)
{
QPoint ptNew = pt + directions[i];
if (!pointInGameArea(ptNew))
{
continue;
}
Item* pItem = items[ptNew.x()][ptNew.y()];
if (!pItem->isMine && !pItem->isOpen && !pItem->isMarked && pItem->number >= 0)
{
//若不是雷 未被打开 未被标记 且数为0
//则将其打开
pItem->isOpen = true;
//对于找到的空白元素,在它的8个方向上有数字元素就打开
QVector<QPoint> directions2 = directions;
directions2.push_back(QPoint(-1,-1));
directions2.push_back(QPoint(1,1));
directions2.push_back(QPoint(1,-1));
directions2.push_back(QPoint(-1,1));
for (int j=0; j<directions2.size(); j++)
{
//对四个方向进行递归查看
QPoint ptNew2 = ptNew + directions2[j];
if(!pointInGameArea(ptNew2))
{
continue;
}
Item* pItem2 = items[ptNew2.x()][ptNew2.y()];
if (!pItem2->isMine && !pItem2->isOpen && !pItem2->isMarked && pItem2->number > 0)
{
//若不是雷 未被打开 未被标记 且数大于0
//则将其打开
pItem2->isOpen = true;
}
}
//递归查找上下左右4个方向的空白元素
openEmptyItem(ptNew);
}
}
}
//判断鼠标是否在游戏区域内
bool MainWindow::pointInGameArea(QPoint pt)
{
if(pt.x()>=0 && pt.x()< cols && pt.y()>=0 && pt.y()< rows)
{
return true;
}
return false;
}
//定义新游戏函数
void MainWindow::slot_newGame()
{
qDebug()<<"slot_newGame()";
newGame();
}
//定义easy难度
void MainWindow::slot_level_easy()
{
rows = 9;
cols = 9;
mine = 10;
newGame();
}
//定义normal难度
void MainWindow::slot_level_normal()
{
rows = 16;
cols = 16;
mine = 40;
newGame();
}
//定义hard难度
void MainWindow::slot_level_hard()
{
rows = 16;
cols = 30;
mine = 99;
newGame();
}
//定义自定义难度 调用自定义窗口
void MainWindow::slot_level_self()
{
dialogSelf->show();
}
//定义自定义难度参数获取函数
void MainWindow::slot_level_self_get()
{
rows=dialogSelf->getRows();
cols=dialogSelf->getCols();
mine=dialogSelf->getMine();
// qDebug()<<rows;
// qDebug()<<cols;
// qDebug()<<mine;
//传入行数列数雷数之后开始新游戏
newGame();
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。