Qt 扫雷小游戏学习分享(完结)

本文接着上篇的分享继续讲解。

1、实现格子翻转

鼠标左键点击格子,实现格子翻转——当格子不是地雷(0~8)的时候,格子会显示其周围的地雷数,并将其周围8个没有地雷的格子翻转;若发现某格子周围地雷数为0时,会递归“点击”其周围的8个格子。当格子是地雷(99)的时候,将会显示游戏结束的界面。实现过程如下——

在头文件mainscene.h添加如下代码

#include <QMouseEvent>
#include <QMessageBox>

在类中添加鼠标按键事件函数以及左键递归函数的定义

void mousePressEvent(QMouseEvent *event);
void LeftPress(int x, int y);
void gameOver();

在mainwindow.cpp实现它们

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    int x = event->x();
    int y = event->y();


    if(event->button() == Qt::LeftButton)   //判断是鼠标左键按下
    {
        if(y>24)    //格子的y坐标大于24
        {
            x /= 20;
            y = (y-40)/20;      //转换成二维格子的坐标
            if(grid[x][y] == 99)   //碰到地雷了
            {
                gameOver();
            }
            else
            {
                if(grid[x][y]<=8)
                {
                    LeftPress(x, y);
                }
            }
        }
    }
}
void MainWindow::LeftPress(int x, int y)    //递归点击周围八个格子
{
    for(int m=x-1; m<=x+1; m++)
    {
        for(int n=y-1; n<=y+1; n++)
        {
            if(m<0 || n<0 || m>=GRID_X || n>=GRID_Y) //越界
                continue;
            if(grid[m][n]<10)     //未被操作过的格子
            {
                grid[m][n] += 100;
                if(grid[m][n] == 100)
                    LeftPress(m, n);
            }
        }
    }
    int num = 0;
    for(int i=0; i<GRID_X; i++)
    {
        for(int j=0; j<GRID_Y; j++)
        {
            if(grid[i][j]>=100 && grid[i][j]<=108)
            {
                num++;
                if(num>=250)    //判断是否胜利  300个格子,50个地雷
                {
                    for(int x=0; x<GRID_X; x++)
                    {
                        for(int y=0; y<GRID_Y; y++)
                        {
                            if(grid[x][y] == 99)
                            {
                                grid[x][y] += 100+55;
                            }
                            else
                            {
                                grid[x][y] += 100;
                            }
                        }
                    }
                    nMine = 0;
                    m_timer.stop();
                    update();
                    QMessageBox::information(NULL, "提示", "恭喜,你赢了!!", QMessageBox::Yes, QMessageBox::Yes);
                    break;
                }
            }
        }
    }
    update();
}
void MainWindow::gameOver()
{
    for(int x=0; x<GRID_X; x++)
    {
        for(int y=0; y<GRID_Y; y++)
        {
            if(grid[x][y] == 99 || grid[x][y] == 145)
            {
                grid[x][y] += 100;   //将地雷和插旗的格子翻开
            }
        }
    }
    m_face = 0;
    m_timer.stop();
    update();
    QMessageBox::information(NULL, "提示", "完了,你被炸死了!!", QMessageBox::Yes, QMessageBox::Yes);
}

测试运行,效果如下

Qt扫雷小游戏学习分享(完结)

2、实现游戏重新开始

鼠标左键点击顶部的表情,便可实现游戏重新开始,实现过程如下——

在mousePressEvent函数里面的if(event->button() == Qt::LeftButton)判断后的代码代码修改如下——

if(event->button() == Qt::LeftButton)
    {
        if(x>=187 && x<=211 && y>0 && y<=24)   //顶部表情的位置
            restart();   //重新开始游戏,此函数已在前面实现(上一篇分享)
        else if(y>24)
        {
            x /= 20;
            y = (y-40)/20;
            if(grid[x][y] == 99)
            {
                gameOver();
            }
            else
            {
                if(grid[x][y]<=8)
                {
                    LeftPress(x, y);
                }
            }
        }
    }

测试运行,鼠标左键点击顶部表情,可以看到界面被恢复到最初的状态。

3、插红旗

当我们确定某一格子是地雷时,便可点击鼠标右键插上红旗。当插上50面后,游戏便会结束,并显示扫雷结果,实现过程如下——

在mousePressEvent函数最后添加如下代码

else if(event->button() == Qt::RightButton)  //鼠标右键点击,前面跟着的是鼠标左击判断
    {
        x /= 20;
        y = (y-40)/20;
        rightPress(x, y);
    }

接下来实现rightPress函数

void MainWindow::rightPress(int x, int y)
{
    if(grid[x][y] >=0 && grid[x][y] <= 8)  //红旗标记未被点击过的格子
    {
        nMine--;      //左上角的地雷数目显示减1
        grid[x][y] += 50;
    }
    else if(grid[x][y] >= 50 && grid[x][y] <= 58)  //已被插上红旗的格子(没有雷),再次点击,便会取消红旗
    {
        nMine++;  //左上角的地雷数目显示加1
        grid[x][y] -= 50;
    }
    else if(grid[x][y] == 99)  //红旗标记地雷
    {
        nMine--;
        grid[x][y] = 145;
    }
    else if(grid[x][y] == 145)  //取消红旗标记(该格子有雷)
    {
        if(nMine <50)  //地雷最多为50个
        {
            nMine++;
        }
        grid[x][y] = 99;
    }
    if(nMine==0)  //已插50面红旗,计算游戏结果
    {
        int num =0;
        for(int i; i<GRID_X; i++)
        {
            for(int j=0; j<GRID_Y; j++)
            {
                if(grid[i][j] == 145) //判断多少地雷被插上红旗
                {
                    num++;
                }
                grid[i][j] += 100;
            }
        }


        if(num < 50)  //没有标记50个地雷,游戏失败
        {
            m_face -= 1;  //伤心表情
            m_timer.stop();   //游戏计时定时器停止
            update();     //刷新画面
            QMessageBox::information(NULL, "提示", "完了,你被炸死了!!", QMessageBox::Yes, QMessageBox::Yes);
        }
        else   //游戏胜利
        {
            m_timer.stop();
            update();
            QMessageBox::information(NULL, "提示", "恭喜,你赢了!!", QMessageBox::Yes, QMessageBox::Yes);
        }
    }
    update();
}

测试运行,效果图如下

Qt扫雷小游戏学习分享(完结)

至此,本游戏的基本功能已基本完成,虽然有一些隐藏的bug,老码私下再修改,便不在这里讲述了。大家可编译自己的代码,好好地体验一下自己敲的游戏。下图是老码玩的一次结果——

Qt扫雷小游戏学习分享(完结)

若想要源码,可关注并私信老码!!!