使用Qt实现“扫雷”

10 篇文章 0 订阅
4 篇文章 0 订阅

实现了点击判断,插旗,存疑的功能,基本上抄袭自扫雷 = =,不过还有胜利提示,游戏计时,重置,难度没时间搞,上代码留着以后有空了再研究一下

1.数据结构

struct BoomIndex
{
    int row; // 雷行数
    int col; // 雷列数
};

enum BoomButtonState
{
    Logic = 0x00,  // 数字值
    BoomFlag,      // 地雷标记
    BoomFind       // 地雷存疑
};

2.窗格控件

也就是扫雷中的一个个小格子

#include <QWidget>
#include <QPushButton>
#include "public.h"

class BoomButton : public QPushButton // 窗格控件定义
{
    Q_OBJECT
public:
    BoomButton(QWidget *parent = 0);

    // 设置btn值为雷
    void setBoom();

    // 获取btn值
    bool getBoom();

    // 地雷计数器加1
    void addOnceCount();

    void showData();

protected:
    void mouseDoubleClickEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);

signals:
    void sig_GameOver();

private slots:
private:
    BoomButtonState m_boomBtnState;
    int m_boomCount;
    bool m_isBoom;
};
#include <QMessageBox>
#include <QMouseEvent>
#include "boombutton.h"

BoomButton::BoomButton(QWidget *parent)
    : QPushButton(parent)
    , m_boomBtnState(Logic)
    , m_boomCount(0)
    , m_isBoom(false)
{
    setFixedSize(50,50);
    this->setText("");
}

void BoomButton::setBoom()
{
    m_isBoom = true;
}

bool BoomButton::getBoom()
{
    return m_isBoom;
}

void BoomButton::addOnceCount()
{
    m_boomCount++;
}

void BoomButton::mouseDoubleClickEvent(QMouseEvent *event)
{

}

void BoomButton::mouseReleaseEvent(QMouseEvent *event)
{
    if (Qt::LeftButton == event->button())
    {
        this->setEnabled(false);
        if (m_boomBtnState == BoomFlag)
        {
            this->setEnabled(true);
        }
        else if (m_isBoom)
        {
            this->setText("雷");
            emit sig_GameOver();
            QMessageBox::information(NULL, "提示", "游戏结束");
        }
        else if (m_boomBtnState == Logic)
        {
            this->setText(QString::number(m_boomCount));
        }
        else if (m_boomBtnState == BoomFind)
        {
            this->setText(QString::number(m_boomCount));
        }
    }
    else if (Qt::RightButton == event->button())
    {
        if (m_boomBtnState == Logic)
        {
            m_boomBtnState = BoomFlag;
            this->setText("↓");
        }
        else if (m_boomBtnState == BoomFlag)
        {
            m_boomBtnState = BoomFind;
            this->setText("?");
        }
        else if(m_boomBtnState == BoomFind)
        {
            m_boomBtnState = Logic;
            this->setText("");
        }
    }
    this->update();
}

void BoomButton::showData()
{
    this->setEnabled(false);
    if (m_isBoom)
    {
        this->setText("雷");
    }
    else if (m_boomCount == 0)
    {
        this->setText("");
    }
    else
    {
        this->setText(QString::number(m_boomCount));
    }
}

3.主窗体

#include <QWidget>
#include "boombutton.h"
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = 0);
    ~Widget();
private:
    // 初始化布局
    void initBoomButtonLayout();
    // 初始化炸弹分布
    void initBoom();
private slots:
    void gameOver();
private:
    BoomButton *m_BoomButtons[9][9];
    BoomIndex m_BoomIndex[9];
};
#include "widget.h"
#include <QGridLayout>
#include <QTime>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    initBoomButtonLayout();
    initBoom();
}

Widget::~Widget()
{

}

void Widget::initBoomButtonLayout()
{
    QGridLayout *layout = new QGridLayout();
    for (int i = 0; i < 9; i++)
    {
        for(int j = 0; j < 9; j++)
        {
            m_BoomButtons[i][j] = new BoomButton(this);
            layout->setMargin(1);
            layout->setSpacing(1);
            layout->addWidget(m_BoomButtons[i][j], i, j);
            connect(m_BoomButtons[i][j], SIGNAL(sig_GameOver()), this, SLOT(gameOver()));
        }
    }
    this->setLayout(layout);
}

void Widget::initBoom()
{
    int currentIndex = 0;
    for (int i = 0; i < 9; i++)
    {
        m_BoomIndex[i].col = 0;
        m_BoomIndex[i].row = 0;
    }
    // 初始化随机数的种子
    QTime time = QTime::currentTime();
    qsrand(time.msec());
    // 生成9个地雷
    while (true)
    {
        bool isAdd = true;
        int xRand = qrand() % 9;
        int yRand = qrand() % 9;
        for (int i = 0; i < 9; i++)
        {
            if (m_BoomIndex[i].col == yRand && m_BoomIndex[i].row == xRand)
            {
                isAdd = false;
                break;
            }
        }

        if (isAdd)
        {
            m_BoomIndex[currentIndex].row = xRand;
            m_BoomIndex[currentIndex].col = yRand;
            currentIndex ++;
            if (currentIndex == 9)
            {
                break;
            }
        }
    }

    // 生成数字
    for (int i = 0; i < 9; i++)
    {
        int row = m_BoomIndex[i].row;
        int col = m_BoomIndex[i].col;
        m_BoomButtons[m_BoomIndex[i].row][m_BoomIndex[i].col]->setBoom();

        if (row + 1 < 9)
        {
            if (!m_BoomButtons[row + 1][col]->getBoom())
            {
                m_BoomButtons[row + 1][col]->addOnceCount();
            }

            if (col + 1 < 9)
            {
                if (!m_BoomButtons[row + 1][col + 1]->getBoom())
                {
                    m_BoomButtons[row + 1][col + 1]->addOnceCount();
                }
            }

            if (col - 1 > 0)
            {
                if (!m_BoomButtons[row + 1][col - 1]->getBoom())
                {
                    m_BoomButtons[row + 1][col - 1]->addOnceCount();
                }
            }
        }

        if (row - 1 > 0)
        {
            if (!m_BoomButtons[row - 1][col]->getBoom())
            {
                m_BoomButtons[row - 1][col]->addOnceCount();
            }

            if (col + 1 < 9)
            {
                if (!m_BoomButtons[row - 1][col + 1]->getBoom())
                {
                    m_BoomButtons[row - 1][col + 1]->addOnceCount();
                }
            }

            if (col - 1 > 0)
            {
                if (!m_BoomButtons[row - 1][col - 1]->getBoom())
                {
                    m_BoomButtons[row - 1][col - 1]->addOnceCount();
                }
            }
        }

        if (row == row)
        {
            if (col + 1 < 9)
            {
                if (!m_BoomButtons[row][col + 1]->getBoom())
                {
                    m_BoomButtons[row][col + 1]->addOnceCount();
                }
            }

            if (col - 1 > 0)
            {
                if (!m_BoomButtons[row][col - 1]->getBoom())
                {
                    m_BoomButtons[row][col - 1]->addOnceCount();
                }
            }
        }
    }
}

void Widget::gameOver()
{
    for (int i = 0; i < 9; i++)
    {
        for(int j = 0; j < 9; j++)
        {
            m_BoomButtons[i][j]->showData();
        }
    }
}

4.调用与实现

#include <QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}
QTQt)是一个跨平台的C++应用程序开发框架,它提供了一套丰富的图形用户界面组件。要在QT实现16x16的扫雷游戏,你需要按照以下步骤: 1. **设置项目**: - 创建一个新的QT Widgets Application项目。 - 导入必要的库,如QGraphicsScene、QGraphicsView、QPushButton等。 2. **设计游戏界面**: - 使用QGraphicsView展示游戏区域,背景可以使用QPixmap。 - 在棋盘上画出每个格子作为QPushButton,并标记为未开挖状态。 3. **数据结构**: - 定义一个数组表示雷区,每个元素表示一个格子是否包含地雷以及周围已知的地雷数。 4. **逻辑实现**: - 为每个按钮添加点击事件处理器,检查当前位置周围的地雷情况。 - 如果触雷或达到安全范围,更新按钮的状态并显示相应提示。 - 实现“翻开”、“标记”等功能,可能需要递归遍历邻居节点。 5. **UI交互**: - 提供开始游戏、结束游戏、标记地雷等控制功能,可能需要自定义菜单或工具栏。 ```cpp // 示例代码片段 class MineCell : public QPushButton { public: explicit MineCell(QWidget *parent = nullptr) : QPushButton(parent) {} void setMineStatus(int mineCount, bool isMine) { if (isMine) { // 画地雷图标 setFixedSize(16, 16); setAutoDefault(false); // 阻止默认点击行为 } else { // 标记安全或包含的矿石数量 setText(QString::number(mineCount)); } } private slots: void onClicked() { // 检查地雷状态并处理 } }; QVector<int> mineField; // 存储雷区信息 void startGame() { for (int i = 0; i < 16; ++i) { // 16x16的棋盘 MineCell* cell = new MineCell(&mainWindow); // 设置位置... cell->setMineStatus(...); gameBoard.addWidget(cell); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值