C3—Qt实现五子棋小游戏(一)2021.11.07

Qt实现五子棋小游戏

qt实现五子棋(二)

目标:

打开游戏,单击开始按钮游戏开始,按照事先选好的下棋顺序,将显示当前棋手的执子颜色与步数,并且允许当前棋色落子,同时伴随落子音效,也在检测是否选手获得胜利,一旦胜利,立马提示胜利方。棋盘大小可以根据窗口大小改变。

步骤:

**第一个大步骤是构建棋盘。**将棋盘的逻辑(即棋盘)与下棋的逻辑(主界面)分开,棋盘可以响应鼠标事件发出当前坐标信号,主界面接收坐标信号,并利用棋盘提供的刷新棋盘的方法,刷新棋盘。每下一步棋,刷新棋盘,判断是否胜利,切换角色方等。
这个小项目里面有前面基础篇讲到东西的应用,也有没出现的类的简单应用,同时更应看重,程序模块化解耦的设计能力,这种能力能让大型项目瞬间”土崩瓦解“,让你的编程、调试、测试井井有条,游刃有余。
由于本人电脑加密的原因,无法将工程上传,所以请各位结合下面的步骤说明和代码注释理解并创建自己的工程。

1.创建不带ui界面的棋盘类

创建chessplate类,继承自QWidget,虽然不带ui界面,但在main中实例化该对象并调用show方法,会显示出界面,这是因为它继承自widget。

2.做好准备工作

.pro中添加多媒体模块以便于读QSound的使用,如下:

QT  +=  multimedia

在chessplate.h文件中添加用到类的头文件,如下:

#include 
#include 
#include 
#include 
#include 

3.QPainter画棋盘

①画背景图(末尾一起贴代码)
②画棋盘线。将棋盘格子、起始、结束点定义成成员变量, 当窗口发生改变的时候,触发resize事件,在resize事件中改变上述三个变量的大小,同时resize又将触发QPainter事件,进行界面重绘,那么将实现棋盘会随着窗口大小的改变而改变。
③画定位点,可以使用brush在四个点画圆,也可以在固定位置画图片。
④画棋子,使用二维数组存储当前棋盘的状态,例如1代表黑色。使用鼠标点击事件,点击生成坐标,坐标信息结合当前角色刷新存储阵列,调用update()重绘图片,将根据最新的存储阵列刷新棋盘状态。为了能与其他模块交互,进行如下设计,在鼠标点击的时候,将坐标信息(不是真实的坐标,而是经过转换的格子的坐标)当成信号发出,其他类(主要指主界面)收到这个信息,刷新主界面中的存储阵列p,将p作为参数传递给棋盘类提供的刷新棋盘的方法中,完成模块之间的交互,完成界面的刷新。除此之外,还应注意,棋子应该画到棋盘横竖线的交叉点上。

4.鼠标事件

单击鼠标,记录当前的坐标信息,将其划分到格子中,即获取用户是想在哪个位置落子的信息,将这个格子的坐标当作信号发出。如果想做细致,应该考虑约束鼠标点击事件的响应方位,例如应限制在交叉点的多少半径范围之内才进行响应,避免用户不小心点错。

5.resizeEvent

每次resize会自动触发QPainter重绘,那么在resize的事件中只需要,重新回去当前的界面大小信息,随后计算在这个界面大小的情况下,棋盘格子应该为多大,将这些计算好之后QPainter将依据这个数据重新绘制,确保棋盘大小随着界面大小动态变化。但是考虑到棋盘的美观性,应该对界面能拉大缩小的范围有所限制,当然这个限制是在调用它的主界面中做的。

6.对外提供方法

提供修改背景图片的方法,提供修改棋盘线粗、线风格、线颜色的方法,提供刷新棋盘状态的方法。当一个类想对外提供修改某些东西的方法时,应该添加类成员变量,然后利用对外方法函数的参数来改变类成员变量的值,而这些个成员变量同时被”要修改的内容“当作参数使用。这就使得,外部类通过提供新的参数来改变这个类的东西。

    //提供修改背景图片的方法
    void setBackGroundPic(const QString filename);
    //修改棋盘线风格
    void setPlateLine(const QColor color,const Qt::PenStyle style,const int width);
    //刷新棋盘
    void setChessStatus(void *p);

效果

在main中实例化并调用棋盘类的show方法,可以看到如下效果。
在这里插入图片描述
C3—Qt实现五子棋小游戏(一)2021.11.07_第1张图片

代码

贴出代码如下:
chessPlate.h代码

#ifndef CHESSPLATE_H
#define CHESSPLATE_H

#include 
#include 
#include 
#include 
#include 
#define  GRIDCOUNT   16

class chessPlate : public QWidget
{
    Q_OBJECT

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

    enum ChessType{Empty=0,White,Black};
    //提供修改背景图片的方法
    void setBackGroundPic(const QString filename);
    //修改棋盘线风格
    void setPlateLine(const QColor color,const Qt::PenStyle style,const int width);
    //刷新棋盘
    void setChessStatus(void *p);
protected:
    void paintEvent(QPaintEvent *);
    void resizeEvent(QResizeEvent *);
    void mousePressEvent(QMouseEvent *);
private:
    QString bgFileName;
    QColor lineColor;
    Qt::PenStyle lineStyle;
    int lineWidth;
    //格子宽高,画线起始点
    int gridWidth, gridHeight,startX,startY;
    int chessData[15][15];
    void Init();

signals:
    void mousePosSend(int i,int j);
};
#endif // CHESSPLATE_H

chessPlate.cpp

#include "chessplate.h"

chessPlate::chessPlate(QWidget *parent)
    : QWidget(parent)
{
    Init();
}

chessPlate::~chessPlate()
{
}

void chessPlate::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    //画背景
    QRect rect(QPoint(0,0),QSize(this->width(),this->height()));
    QPixmap pix(bgFileName);
    painter.drawPixmap(rect,pix);
//    QPixmap pix2(":/res/black.png");
//    painter.drawPixmap(QPoint(100,30),pix2);

    //画线
    QPen pen;
    pen.setColor(lineColor);
    pen.setStyle(lineStyle);
    pen.setWidth(lineWidth);
    painter.setPen(pen);

    for (int i = 0;i<15 ;i++ ) {
        //画线
        painter.drawLine(startX,startY+i*gridHeight,startX+14*gridWidth,startY+i*gridHeight);//x
        painter.drawLine(startX+i*gridWidth,startY,startX+i*gridWidth,startY+14*gridHeight);//y

    }
    //画上四个圆点
    QBrush brs;
    brs.setColor(Qt::black);
    brs.setStyle(Qt::SolidPattern);
    painter.setRenderHint(QPainter::SmoothPixmapTransform);
    painter.setBrush(brs);
    painter.drawEllipse(QPoint(4*gridWidth,4*gridHeight),6,6);
    painter.drawEllipse(QPoint(12*gridWidth,4*gridHeight),6,6);
    painter.drawEllipse(QPoint(8*gridWidth,8*gridHeight),6,6);
    painter.drawEllipse(QPoint(12*gridWidth,12*gridHeight),6,6);
    painter.drawEllipse(QPoint(4*gridWidth,12*gridHeight),6,6);
    painter.setPen(pen);

    //落子展示
    QString chessFilename;
    for (int i= 0;i<15 ;i++ ) {
        for (int j = 0;j<15 ;j++ ) {
            if(chessData[i][j]==White){
                chessFilename = ":/res/white.png";
            }
            else if(chessData[i][j]==Black){
                chessFilename = ":/res/black.png";
            }
            else
            {
                chessFilename.clear();
                continue;
            }
            painter.drawPixmap(startX/2+i*gridWidth,startY/2+j*gridHeight,gridWidth,gridHeight,QPixmap(chessFilename));
        }
    }
}
void chessPlate::resizeEvent(QResizeEvent *event)
{
    this->gridWidth = event->size().width()/GRIDCOUNT;
    this->gridHeight = event->size().height()/GRIDCOUNT;
    startX = gridWidth;
    startY = gridHeight;
}
void chessPlate::mousePressEvent(QMouseEvent *event)
{
    int x=event->x();
    int y=event->y();
    //x
    if(x>=startX/2 &&(x<=startX/2+15*gridWidth)){
        //y
        if(y>=startY/2&&(y<=startY/2+15*gridHeight))
        {
            //得出当前坐标属于哪个格子 格子与实际格子并未对应,是因为,把他放在对角线上
            int i = 0,j =0;
            i = (x-startX/2)/gridWidth;
            j = (y-startY/2)/gridHeight;
//            chessData[i][j]=Black;
//            this->update();
            mousePosSend(i,j);
        }
    }
}
void chessPlate::Init()
{
    //初始化函数:设置成员变量初始值(默认值);设置界面的标题与图标等初始状态


    bgFileName.clear();
    bgFileName = ":/res/chess_back.jpg";
    lineColor = Qt::black;
    lineStyle = Qt::SolidLine;
    lineWidth = 3;

    for (int i=0;i<15 ;i++ ) {
        for (int j = 0;j<15 ;j++ ) {
            chessData[i][j]=Empty;
        }
    }
//    chessData[3][3] = White;
//    chessData[4][4] = Black;

}

void chessPlate::setBackGroundPic(const QString filename)
{
    this->bgFileName = filename;
    this->update();
}
void chessPlate::setPlateLine(const QColor color, const Qt::PenStyle style, const int width)
{
    this->lineColor = color;
    this->lineStyle = style;
    this->lineWidth = width;
    this->update();
}
void chessPlate::setChessStatus(void *p)
{
    memcpy(chessData,p,sizeof(int)*15*15);
    this->update();
}

未完待续……

你可能感兴趣的:(Qt积累——小项目,qt,ui,开发语言)