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_X 和 Max_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_X 和 Max_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.变量定义和初始化

nLeftnLeftUpnUpnRightnRightUpnRightDownnDownnLeftDown 这些变量通过调用 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 

#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

#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

#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

#include "chessitem.h"

ChessItem::ChessItem(void) {}

ChessItem::ChessItem(QPoint point, bool isBluck)
{
    _pt = point;
    _black = isBluck;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/687673.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

部署kubesphere报错

安装kubesphere报错命名空间terminted [rootk8smaster ~]# kubectl apply -f kubesphere-installer.yaml Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16, unavailable in v1.22; use apiextensions.k8s.io/v1 CustomResourceDefini…

【Oracle篇】rman全库异机恢复:从单机环境到RAC测试环境的转移(第五篇,总共八篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

车载以太网测试要测些什么呢?

车载以太网测试大致可以分成两块&#xff1a;TC8测试和以太网通信测试。 TC8测试全称TC8一致性测试&#xff0c;其规范由OPEN联盟制定&#xff0c;包括车载以太网ECU从物理层到应用层的各层互操作性以及常规基础功能服务。目的在于提高不同ECU之间的兼容性。 TC8测试规范可以…

C++STL---stack queue知识汇总

前言 C将stack和queue划归到了Containers中&#xff0c;但严格的说这并不准确&#xff0c;stack和queue实际上已经不再是容器了&#xff0c;而是属于容器适配器&#xff0c;适配器做的功能是转换&#xff0c;即&#xff1a;它不是直接实现的&#xff0c;而是由其他容器封装转换…

ruoyi若依二次开发怎么添加扫描自己的controller和mapper,配置三个地方即可。

概要 首先&#xff0c;添加在com.ruoyi外的类&#xff0c;项目启动后&#xff0c;调用接口&#xff0c;是会返回404找不到的。 必须要对这以外的接口类进行配置。目录结构如下&#xff1a; 解决步骤 一、添加 com.ruoyi.framework.config 下&#xff1a; // 指定要扫描的M…

深度学习革命-AI发展详解

深度学习革命 《深度学习革命》是一部引人深思的作品&#xff0c;详细讲述了深度学习技术的发展历程及其对各个行业的深远影响。由杰出的计算机科学家、深度学习专家撰写&#xff0c;这本书不仅适合科技领域的专业人士阅读&#xff0c;也为普通读者提供了一个理解人工智能革命…

LeetCode322.零钱兑换

文章目录 题目描述解题思路递归记忆化搜索动态规划另一种实现 题目描述 https://leetcode.cn/problems/coin-change/description/?envTypestudy-plan-v2&envIdtop-interview-150 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount …

考研规划,这么学上岸率比985的学霸还高!

我觉得985考研上岸率低是可以理解的 因为大家本科能考上985&#xff0c;那研究生大概率会报考和本学校差不多或者更高水平的院校&#xff0c;甚至清华北大都有人敢报&#xff0c;去实现自己本科没有实现的梦想。 而且985其实保研的比例很高&#xff0c;一般有30%的保研比例了…

亚马逊测评自养号技术全攻略:一站式解决方案

在跨境电商这行&#xff0c;产品测评可是个大问题。如果你的商品销量少&#xff0c;评价也不多&#xff0c;那买家就很难注意到你的产品&#xff0c;更别提下单购买了。毕竟&#xff0c;大家都喜欢跟风买那些已经有很多人好评的产品&#xff0c;而不是冒险尝试一个全新的。 我们…

基于JSP技术的社区疫情防控管理信息系统

你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果有相关需求&#xff0c;文末可以找到我的联系方式。 开发语言&#xff1a;JSP 数据库&#xff1a;MySQL 技术&#xff1a;JSPJavaBeans 工具&#xff1a;MyEclipse、Tomcat、Navicat 系统展示 首页 用户注册与登录界…

《大宅门》特别活动走进李良济,开启探寻中医药文化之旅!

《大宅门》话剧将于6月14-16日在苏州湾大剧院上演&#xff0c;为了让大家了解到中医药知识&#xff0c;6月2日&#xff0c;李良济携手苏州湾大剧院举办《大宅门》特别活动“探寻中医药文化之旅”&#xff01; 6月2日下午&#xff0c;大家一起走进李良济&#xff0c;深度了解传统…

Django框架中级

Django框架中级 – 潘登同学的WEB框架 文章目录 Django框架中级 -- 潘登同学的WEB框架 中间件自定义中间件常用中间件process_view() 使用中间件进行URL过滤 Django生命周期生命周期分析 Django日志日志配置filter过滤器自定义filter 日志格式化formatter Django信号内置信号定…

51单片机STC89C52RC——1.1点亮一个LED

目录 STC单片机模块 LED模块 创建Keil项目 代码 效果 STC单片机模块 我们程序中要点亮的LED灯的位置如下图。 我们程序要用到的针脚如下图 LED模块 电路图如下 8个LED&#xff0c;全部点亮 每一bit位 都需要设置为0 二进制是0000 0000 。如果只点亮D1一个&#xff…

进口电动低温调节阀的作用-美国NOTON

进口电动低温调节阀在低温环境下的精确控制、广泛的工业应用、高效能设计、耐低温性和密封性、稳定性及可靠性以及安全性等方面发挥着重要作用。 进口电动低温调节阀的作用主要体现在以下几个方面&#xff1a; 低温环境下的精确控制&#xff1a; 进口电动低温调节阀是一种专为…

jenkins插件之Jdepend

JDepend插件是一个为构建生成JDepend报告的插件。 安装插件 JDepend Dashboard -->> 系统管理 -->> 插件管理 -->> Available plugins 搜索 Jdepend, 点击安装构建步骤新增执行shell #执行pdepend if docker exec phpfpm82 /tmp/composer/vendor/bin/pdepe…

怎么把wmv格式转换成mp4?四种将wmv转成MP4格式的方法

怎么把wmv格式转换成mp4&#xff1f;在微软操作系统中&#xff0c;我们经常会遇到wmv格式的视频文件。这种由微软开发的视频格式在微软平台上有很好的兼容性&#xff0c;但它也存在一些被忽视的缺点。首先&#xff0c;wmv格式支持数字版权管理&#xff0c;这意味着某些视频可能…

期权有用吗?期权都有哪些用途?

今天带你了解期权有用吗&#xff1f;期权都有哪些用途&#xff1f;期权和期货作为衍生工具,都有风险管理、资产配置和价格发现等功能。 期权有用吗&#xff1f; 期权作为一种衍生金融工具&#xff0c;具有多种用途和好处&#xff0c;对不同类型的投资者和市场参与者来说&#…

Ubuntu编译指定版本NVMe Cli工具

1.克隆nvme-cli的存储库&#xff08;repository&#xff09;&#xff1a; git clone https://github.com/linux-nvme/nvme-cli.git2. 进入nvme-cli目录&#xff0c;并切换到指定版本&#xff1a; cd nvme-cli git checkout v1.93. 编译nvme-cli&#xff1a; make4. 安装nvme…

剪画小程序:图片去除文字,我用它只要10秒!

Hello&#xff0c;大家好呀&#xff01;我是不会画画的小画~ 图片上的文字该如何去除&#xff1f; 在工作或者学习中&#xff0c;我们常常需要处理一些图片文件&#xff0c;比如扫描的文件、 电子文档等。有时候&#xff0c;图片上可能会有文字&#xff0c;这时候需要将图片…

鸿蒙开发:从入门到实战!

一&#xff0c;默认模版中是容器Row或者Column中添加一个Text文本&#xff0c;我们可以尝试一下修改它的内容和样式&#xff0c;对UI语法有一个初体验&#xff1a; // 文本内容 Text("沉默的闪客") // 字体大小 .fontSize(50) //背…
最新文章