Qt中国象棋之棋子的移动

通过鼠标事件实现棋子移动(还没实现每个棋子的移动规则,所以可以随便移动,随便吃棋子,只要轮到走棋的话)

1、判断鼠标左键点击的位置是否为棋盘合法位置

2、只有在棋盘的行、列交叉点为中心的圆圈(刚好是处于圆形棋子范围内)内才合法

3、如果已经选中了棋子,点击的位置也合法则考虑移动棋子

4、如果没有选中棋子,点击的位置也合法则考虑选择棋子

chessboard.h头文件

#ifndef CHESSBOARD_H
#define CHESSBOARD_H
 
#include <QWidget>
#include <QPaintEvent>
#include <QMouseEvent>
#include <QPainter>
#include <QPoint>
#include <QRect>
#include <QPen>
 
#include "chesspieces.h"
 
class ChessBoard : public QWidget
{
    Q_OBJECT
public:
    QPoint origin;  /*棋盘原点坐标*/
    int sideLen;    /*棋盘格子边长*/
    int selectID;   /*被选中的棋子*/
    bool redGo;     /*是否轮到红方走*/
    ChessPieces pieces[32]; /*32颗棋子*/
 
    explicit ChessBoard(QWidget *parent = nullptr); /*构造函数*/
    void paintEvent(QPaintEvent *); /*重绘事件,绘制棋盘、棋子等*/
    void drawRightAngle(QPainter &pt, QPoint c);    /*绘制棋子炮的停靠点(绘制几个直角)*/
    void drawPieces(QPainter &pt, int id);  /*绘制棋子*/
    void mouseReleaseEvent(QMouseEvent *);  /*鼠标事件,选中棋子,移动棋子等*/
    bool onChessBoard(QPoint c, int &row, int &col); /*判断点击的位置是否合法(是否在棋盘坐标的棋子范围内),同时计算出对应的棋盘行列坐标*/
    int getPiecesID(int row, int col);  /*获取棋盘行列位置上的棋子*/
    void toSelectPieces(int id);    /*选择棋子*/
    void toMovePieces(int targetid, int row, int col);  /*将选中的棋子移动到目标位置*/
    bool canSelect(int id); /*棋子是否能被选中*/
    bool isSameColor(int id1, int id2); /*判断两个棋子是否为同一方(颜色相同)*/
 
    QPoint center(int row, int col);    /*将棋盘行、列坐标转换成像素坐标*/

    bool canMove(int moveid, int targetid, int row, int col);   /*判断选中的棋子能否移动到目标位置*/
 
signals:
 
public slots:
};
 
#endif // CHESSBOARD_H

chessboard.cpp实现文件

#include "chessboard.h"
 
ChessBoard::ChessBoard(QWidget *parent) : QWidget(parent)
{
    setWindowTitle(tr("中国象棋"));
    origin = QPoint(60,60);  /*棋盘原点坐标*/
    sideLen = 60;    /*棋盘格子边长*/
    selectID = -1;
    redGo = true;
    resize(origin.x()*3+sideLen*8, origin.y()*2+sideLen*9);
 
    /*初始化32颗棋子*/
    for(int i=0; i<32; i++) {
        pieces[i].init(i);
    }
}
 
 
/*重绘事件*/
void ChessBoard::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    QPen pen;
    pen.setWidth(3);
    painter.setPen(pen);
 
    /*绘制棋盘外廊框*/
    painter.drawRect(QRect(origin.x()-5,origin.y()-5, sideLen*8+10, sideLen*9+10));
    /*绘制棋盘外围*/
    pen.setWidth(1);
    painter.setPen(pen);
    painter.drawRect(QRect(origin, center(9,8)));
    /*绘制剩下的8横7竖*/
    for(int i=1; i<=8; i++) {
        painter.drawLine(center(i,0), center(i,8));
        if(i<8) {
            painter.drawLine(center(0,i), center(4,i));
            painter.drawLine(center(5,i), center(9,i));
        }
    }
    /*绘制九宫斜线*/
    painter.drawLine(center(0,3), center(2,5));
    painter.drawLine(center(2,3), center(0,5));
    painter.drawLine(center(7,3), center(9, 5));
    painter.drawLine(center(9,3), center(7,5));
    /*绘制楚河、汉界*/
    painter.setPen(Qt::gray);
    painter.setFont(QFont("system", 24, sideLen/2));
    painter.drawText(QRect(center(4,1), center(5,3)), "楚河", QTextOption(Qt::AlignCenter));
    painter.drawText(QRect(center(4,5), center(5,7)), "汉界", QTextOption(Qt::AlignCenter));
    /*绘制直角(棋子炮的停靠点)*/
    drawRightAngle(painter, center(2,1));
    drawRightAngle(painter, center(2,7));
    drawRightAngle(painter, center(7,1));
    drawRightAngle(painter, center(7,7));
    /*绘制32颗棋子到棋盘*/
    for(int i=0; i<32; i++) {
        drawPieces(painter, i);
    }
}
 
/*绘制棋子炮的停靠点(绘制几个直角)*/
void ChessBoard::drawRightAngle(QPainter &pt, QPoint c)
{
    int x = c.x();
    int y = c.y();
    int r = sideLen/10;
    pt.drawLine(x-2*r, y-r, x-r, y-r);
    pt.drawLine(x-2*r, y+r, x-r, y+r);
    pt.drawLine(x+r, y-r, x+2*r, y-r);
    pt.drawLine(x+r, y+r, x+2*r, y+r);
 
    pt.drawLine(x-r, y-2*r, x-r, y-r);
    pt.drawLine(x-r, y+r, x-r, y+2*r);
    pt.drawLine(x+r, y-2*r, x+r, y-r);
    pt.drawLine(x+r, y+r, x+r, y+2*r);
}
 
/*绘制棋子到棋盘*/
void ChessBoard::drawPieces(QPainter &pt, int id)
{
    /*假如棋子已死,就不绘制*/
    if(pieces[id].isDead) {
        return;
    }
    int r = sideLen/2;   /*棋子半径*/
    /*获取棋子中心点的像素坐标,根据中心点坐标绘制棋子*/
    QPoint c = center(pieces[id].row, pieces[id].col);
    /*根据棋子中心点的像素坐标,计算出棋子上面的文字所在的矩形*/
    QRect rect = QRect(c.x()-r, c.y()-r, sideLen, sideLen);
    /*红方棋子设置文字为红色*/
    if(pieces[id].isRed) {
        pt.setPen(Qt::red);
    } else {
        pt.setPen(Qt::black);
    }
    /*设置棋子背景颜色为黄色,被鼠标选中的设为绿色*/
    if(selectID == id) {
        pt.setBrush(QBrush(Qt::green));
    } else {
        pt.setBrush(QBrush(Qt::yellow));
    }
    /*绘制棋子为圆形*/
    pt.drawEllipse(c, r, r);
    /*绘制棋子文字*/
    pt.drawText(rect, pieces[id].name(),QTextOption(Qt::AlignCenter));
}

/*鼠标事件,选中棋子,移动棋子等*/
void ChessBoard::mouseReleaseEvent(QMouseEvent *ev)
{
    /*判断是否为鼠标左键*/
    if(ev->button() != Qt::LeftButton) {
        return;
    }
    /*判断点击的位置是否合法(是否在棋盘坐标的棋子范围内),同时计算出对应的棋盘行列坐标*/
    int row, col;
    if(!onChessBoard(ev->pos(), row, col)) {
        return;
    }
    /*获取当前坐标上的棋子*/
    int id = getPiecesID(row, col);
    if(selectID == -1) {
        /*选择棋子*/
        toSelectPieces(id);
    } else {
        /*移动棋子*/
        toMovePieces(id, row, col);
    }
}

/*将选中的棋子移动到目标位置*/
void ChessBoard::toMovePieces(int targetid, int row, int col)
{
    /*如果目标棋子和被选中的棋子为同一方则重写选中目标棋子*/
    if(targetid != -1 && isSameColor(selectID, targetid)) {
        toSelectPieces(targetid);
        return;
    }
    /*判断选中的棋子能否移动到目标位置*/
    if(!canMove(selectID, targetid, row, col)) {
        return;
    }
    if(targetid != -1) {
        pieces[targetid].isDead = true;
    }
    pieces[selectID].row = row;
    pieces[selectID].col = col;
    /*棋子移动后切换到另一方走棋*/
    selectID = -1;
    redGo = !redGo;
    update();
}

/*判断两个棋子是否为同一方(颜色相同)*/
bool ChessBoard::isSameColor(int id1, int id2)
{
    if(id1 == -1 || id2 == -1) {
        return false;
    }
    return pieces[id1].isRed == pieces[id2].isRed;
}

/*选择棋子*/
void ChessBoard::toSelectPieces(int id)
{
    /*判断棋子是否存在*/
    if(id == -1) {
        return;
    }
    /*判断棋子是否能够被选中*/
    if(!canSelect(id)) {
        return;
    }
    selectID = id;
    update();
}

/*棋子是否能被选中*/
bool ChessBoard::canSelect(int id)
{
    return redGo == pieces[id].isRed;
}

/*获取棋盘行列位置上的棋子*/
int ChessBoard::getPiecesID(int row, int col)
{
    for(int i=0; i<32; i++) {
        if(!pieces[i].isDead && pieces[i].row==row && pieces[i].col==col) {
            return i;
        }
    }
    return -1;
}

/*判断点击的位置是否合法(是否在棋盘坐标的棋子范围内),同时计算出对应的棋盘行列坐标*/
bool ChessBoard::onChessBoard(QPoint c, int &row, int &col)
{
    int r = sideLen/2;
    int x = c.x() - origin.x();
    int y = c.y() - origin.y();
    row = y/sideLen;    /*计算当前点击位置在棋盘上所处的行坐标*/
    col = x/sideLen;    /*计算当前点击位置在棋盘上所处的列坐标*/

    /*四舍五入*/
    if(y%sideLen > r) {
        row++;
    }
    if(x%sideLen > r) {
        col++;
    }

    int dx = center(row,col).x()-c.x();
    int dy = center(row,col).y()-c.y();

    /*计算当前点击的位置到棋盘行列交点(也就是棋子圆心)位置的距离是否小于棋子半径*/
    /*通过直角三角形勾股定理a^2+b^2=c^2计算是否在棋子圆形范围内*/
    if(dx*dx + dy*dy < r*r) {
        return true;
    }
    return false;
}
 
/*将棋盘行、列坐标转换成像素坐标*/
QPoint ChessBoard::center(int row, int col)
{
    return QPoint(origin.x()+sideLen*col, origin.y()+sideLen*row);
}

/*判断选中的棋子能否移动到目标位置*/
bool ChessBoard::canMove(int moveid, int targetid, int row, int col)
{
    return true;
}

效果图

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值