目录
内容介绍
简单的五子棋游戏
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
和颜色信息_black
。if(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.变量定义和初始化
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;
}