QT项目实战: 五子棋小游戏

目录

内容介绍

一.添加头文件

二.画棋盘

1.宏定义

2.棋盘

三.画棋子

四.获取棋子摆放位置

五.判断棋子存在

六.判断胜利

1.变量定义和初始化

2.检查获胜条件

3.游戏结束处理

七.重绘

八.效果展示

九.代码

1.mainwindow.h

2.mainwindow.cpp

3.chessitem.h

4.chessitem.cpp


内容介绍

简单的五子棋游戏

  • MainWindow 类继承自 QMainWindow,用于创建游戏窗口。
  • DrawChessBoard 函数使用 QPainter 绘制棋盘的网格线。
  • DrawHandChess 函数根据当前的棋子颜色在鼠标位置绘制一个棋子。
  • DrawChessItem 函数遍历所有已经放置的棋子并绘制它们。
  • DrawChessAtPoint 函数在指定的位置绘制一个棋子。
  • mousePressEvent 函数处理鼠标点击事件,判断点击位置是否已经有棋子,如果没有,则放置一个新棋子并检查是否胜利。
  • CountNearItem 函数用于计算在特定方向上连续相同颜色的棋子数量。
  • paintEvent 函数是重绘事件,它调用其他函数来绘制整个棋盘和棋子。

一.添加头文件

#include <QKeyEvent> 是 C++ 源代码文件中包含 Qt 库的头文件,用于处理键盘事件。在应用程序中,可以通过重写 QWidget::keyPressEvent() 或 QWidget::keyReleaseEvent() 函数来处理键盘事件。这两个函数的参数都是 QKeyEvent 对象,可以用它来获取键盘事件的详细信息,例如按下或释放的键、键的序号、修饰键等。

#include <QTimer> 是 C++ 源代码文件中包含 Qt 库的头文件,用于创建定时器。QTimer 是 Qt 中用于定时操作的类,可以用来触发特定时间间隔后的操作。通过 QTimer,可以实现定时执行某些任务、定时更新界面等功能。

#include <QPainter> 是 C++ 源代码文件中包含 Qt 库的头文件,用于绘制图形和图像。QPainter 是 Qt 中用于绘制图形和图像的类,可以用来绘制各种形状、文本、图像等。通过 QPainter,可以实现自定义绘制、图形界面美化等功能。

#include <QMouseEvent> 是用于包含 QMouseEvent 类的头文件的指令。在Qt框架中,QMouseEvent 类用于表示鼠标事件,例如鼠标的按下、释放、移动和双击等动作。

二.画棋盘

1.宏定义

  • #define ChessR 12:定义了棋盘的行数,这里是12行。
  • #define ChessC 12:定义了棋盘的列数,这里是12列。
  • #define MaxX 35:定义了棋盘上每个方格的宽度,这里是35个单位。
  • #define MaxY 35:定义了棋盘上每个方格的高度,这里是35个单位。

2.棋盘

  • painter.setPen(QPen(QColor(Qt::black), 2));:设置画笔的颜色为黑色,线宽为2个像素。

  • painter.setBrush(Qt::white);:设置画刷的颜色为白色,用于填充图形。

  • 接下来的双重 for 循环遍历棋盘的列(i)和行(j):painter.drawRect((i+0.5)*Max_X, (j+0.5)*Max_Y, Max_X, Max_Y);:在这个循环中,drawRect 函数被用来绘制一个矩形。矩形的左上角坐标是 (i+0.5)*Max_X(j+0.5)*Max_Y,这样可以确保矩形是从每个方格的中心开始绘制的。矩形的宽度和高度被设置为 Max_XMax_Y

三.画棋子

  • painter.setPen(QPen(QColor(Qt::black), 1));:设置画笔的颜色为黑色,线宽为1个像素。这通常用于绘制棋子的轮廓。

  • 接下来的 for 循环遍历 p_ChessItem 容器中的所有棋子:ChessItem item = p_ChessItem[i];:从 p_ChessItem 容器中获取第 i 个棋子。ChessItem 是一个自定义的结构体或类,包含棋子的位置 _pt 和颜色信息 _blackif(item._black){ painter.setBrush(Qt::black); } else { painter.setBrush(Qt::white); }:根据棋子的颜色属性 _black 设置画刷的颜色。如果 _black 为真,则画刷颜色为黑色,否则为白色。DrawChessAtPoint(painter, item._pt);:调用 DrawChessAtPoint 函数在指定的位置 item._pt 绘制棋子。这个函数需要被定义,它应该接受一个 QPainter 对象和一个 QPoint 对象,并在该点绘制一个圆形或其他形状来表示棋子。

四.获取棋子摆放位置

  • QPoint ptCenter((point.x() + 0.5) * Max_X, (point.y() + 0.5) * Max_Y);:计算棋子的中心点位置。Max_XMax_Y 是棋盘上每个格子宽度和高度的常量。(point.x() + 0.5) * Max_X(point.y() + 0.5) * Max_Y 的计算是为了将棋子的位置从棋盘的离散格子坐标转换为中心点坐标。

  • painter.drawEllipse(ptCenter, Max_X / 3, Max_Y / 3);:在计算出的中心点位置 ptCenter 绘制一个椭圆。椭圆的宽度是 Max_X / 3,高度是 Max_Y / 3。这表示椭圆的尺寸是棋盘格尺寸的三分之一,从而在棋盘上绘制一个大小合适的棋子。

五.判断棋子存在

  • for 循环遍历 p_ChessItem 容器中的所有棋子。
  • if 语句检查当前棋子的位置 _pt 是否与给定的点 pt 相等。
  • 如果位置相等,函数立即返回 true,表示棋子存在。
  • 如果 for 循环完成后没有找到相等的点,函数返回 false,表示棋子不存在。

六.判断胜利

1.变量定义和初始化

nLeft, nLeftUp, nUp, nRight, nRightUp, nRightDown, nDown, nLeftDown 这些变量通过调用 CountNearItem 函数来计算,该函数接受一个棋子对象 item 和一个表示方向的 QPoint 对象,返回该方向上相邻的棋子数量。

2.检查获胜条件

代码检查四个方向上的棋子数量组合

  • (nRightUp + nLeftDown) >= 4:检查右上到左下对角线方向上是否有至少四个连续的棋子。
  • (nUp + nDown) >= 4:检查垂直方向上是否有至少四个连续的棋子。
  • (nLeftUp + nRightDown) >= 4:检查左上到右下对角线方向上是否有至少四个连续的棋子。
  • (nLeft + nRight) >= 4:检查水平方向上是否有至少四个连续的棋子。

3.游戏结束处理

  • 如果上述任一条件满足,即有一方玩家形成了至少四个连续棋子的组合,游戏结束。
  • 根据 b_black 变量的值(如果为真,表示黑棋赢;否则,表示白棋赢),构建一个字符串 str 来显示获胜信息。
  • 使用 QMessageBox::information 函数显示一个消息框,通知玩家游戏结束,并显示获胜信息。
  • 清除棋盘上的所有棋子(通过 p_ChessItem.clear();)。
  • 函数返回,结束游戏。

七.重绘

八.效果展示

九.代码

1.mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPainter>
#include <QPaintEvent>
#include <QMouseEvent>
#include <QVector>
#include <QDebug>
#include "chessitem.h"
#include <QMessageBox>

#define ChessR 12
#define ChessC 12
#define MaxX 35
#define MaxY 35

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void paintEvent(QPaintEvent *event);

    void mousePressEvent(QMouseEvent *event); //鼠标变形

    int CountNearItem(ChessItem item , QPoint pt); //判断棋子连接

private:
    Ui::MainWindow *ui;
    void InitUI();
    void DrawChessBoard();//画棋盘
    void DrawChessItem();//绘制棋盘上的棋子
    void DrawChessAtPoint(QPainter &painter , QPoint &point); //画棋子的样式和位置

    bool b_black; //定义棋子的颜色

    QVector<ChessItem> p_ChessItem;//存储棋子

};
#endif // MAINWINDOW_H

2.mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"
#include "./ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    InitUI();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::InitUI()
{
     //定义棋盘的大小
    this->resize((ChessC + 1) * MaxX, (ChessR + 1) * MaxX);

    b_black = false;
}

void MainWindow::DrawChessBoard()
{
    QPainter painter(this);
    painter.setPen(QPen(QColor(Qt::black),2));
    painter.setBrush(Qt::white);
    //棋盘格子
    for(int i=0; i <ChessC; i++){
        for(int j =0; j<ChessR;j++){
            painter.drawRect((i+0.5)*MaxX,(j+0.5)*MaxY,MaxX,MaxY);
        }
    }
}



//绘制棋盘上的所有棋子
void MainWindow::DrawChessItem()
{
    QPainter painter(this);
    painter.setPen(QPen(QColor(Qt::black),1));
    //遍历棋子,有就绘制,没有就不绘制
    for(int i = 0; i < p_ChessItem.size() ; i++){
        ChessItem item = p_ChessItem[i]; //当前棋子的样式和位置复制给棋子这个类
        if(item._black){
            painter.setBrush(Qt::black);
        }else {
            painter.setBrush(Qt::white);
        }
        DrawChessAtPoint(painter,item._pt);
    }
}

void MainWindow::DrawChessAtPoint(QPainter &painter , QPoint &point)
{
    //获取棋子的摆放位置
    QPoint ptCenter((point.x() + 0.5) * MaxX , (point.y() + 0.5) * MaxY);
    painter.drawEllipse(ptCenter,MaxX/3,MaxY/3);
}


void MainWindow::mousePressEvent(QMouseEvent *event)
{

    QPoint pt;  //定义点位
    pt.setX((event->pos().x())/MaxX);
    pt.setY((event->pos().y())/MaxY);

    //判断棋子是否存在
    for(int i = 0 ; i<p_ChessItem.size(); i++){
        ChessItem item = p_ChessItem[i];
        if(item._pt == pt){
            return ;
        }
    }

    //如果不存在,进行绘制和判断五子链接
    ChessItem item(pt,b_black);
    p_ChessItem.append(item);

    //统计四个点位是否连接
    int nLeft       = CountNearItem(item,QPoint(-1,0));
    int nLeftUp     = CountNearItem(item,QPoint(-1,-1));;
    int nUp         = CountNearItem(item,QPoint(0,-1));;
    int nRight      = CountNearItem(item,QPoint(1,0));;
    int nRightUp    = CountNearItem(item,QPoint(1,-1));;
    int nRightDown = CountNearItem(item,QPoint(1,1));;
    int nDown       = CountNearItem(item,QPoint(0,1));;
    int nLeftDown   = CountNearItem(item,QPoint(-1,1));;

    if( (nLeft + nRight) >= 4 || (nLeftUp + nRightDown) >=4
        || (nUp + nDown) >=4 || (nRightUp + nLeftDown) >= 4)
    {
        QString str = b_black ? "black win" : "white win";
        QMessageBox::information(NULL,"GAME OVER",str,QMessageBox::Yes);
        p_ChessItem.clear();
        return;
    }

    //换人下棋
    b_black = !b_black;
}

int MainWindow::CountNearItem(ChessItem item, QPoint pt)
{
    int nCount = 0;

    item._pt += pt;
    while (p_ChessItem.contains(item)) {
        nCount++;
        item._pt += pt;
    }

    return nCount;
}


void MainWindow::paintEvent(QPaintEvent *event)
{
    DrawChessBoard();
    DrawChessItem();
    update();
}

3.chessitem.h

cpp 复制代码
#ifndef CHESSITEM_H
#define CHESSITEM_H

#include <QObject>
#include <QPoint>

class ChessItem
{
public:
    ChessItem();
    ChessItem(QPoint point,bool isBluck);  //位置和颜色

    bool operator==(const ChessItem &t1)const{
        return ((_pt==t1._pt) && (_black==t1._black));
    }

    QPoint _pt;  //棋子的位置
    bool _black; //棋子的颜色
};

#endif // CHESSITEM_H

4.chessitem.cpp

cpp 复制代码
#include "chessitem.h"

ChessItem::ChessItem(void) {}

ChessItem::ChessItem(QPoint point, bool isBluck)
{
    _pt = point;
    _black = isBluck;
}
相关推荐
FF在路上1 分钟前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
码农君莫笑28 分钟前
使用blazor开发信息管理系统的应用场景
数据库·信息可视化·c#·.net·visual studio
众拾达人40 分钟前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.42 分钟前
Mybatis-Plus
java·开发语言
不良人天码星42 分钟前
lombok插件不生效
java·开发语言·intellij-idea
終不似少年遊*1 小时前
美国加州房价数据分析01
人工智能·python·机器学习·数据挖掘·数据分析·回归算法
源码哥_博纳软云1 小时前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
学会沉淀。1 小时前
Docker学习
java·开发语言·学习
西猫雷婶2 小时前
python学opencv|读取图像(二十一)使用cv2.circle()绘制圆形进阶
开发语言·python·opencv
kiiila2 小时前
【Qt】对象树(生命周期管理)和字符集(cout打印乱码问题)
开发语言·qt