|
这是我的CSDN博客专栏《Qt实战小项目》的系列文章第3篇。专栏地址:https://blog.csdn.net/dpsying/category_9267660.html 目前专栏内有这些文章:QT项目一:俄罗斯方块游戏QT项目二:五子棋游戏QT项目三:中国象棋QT项目四:扫雷游戏QT项目五--计算器QT项目六:简易客户信息管理系统 1,简介 QT实现中国象棋单机版,本来以为会花费不少时间的。由于之前2个游戏项目的练手,这个主要只在走棋算法部分花了些时间研究,最后一共2个晚上完成。由于只是QT学习,没有考虑更多复杂功能,比如人机对战等,那个可能算法就得花很长时间。 2,效果 3,设计思路 准备2个棋盘棋子图片: 棋子类: [cpp] view plain copy
- #pragma once
- #include "qpainter.h"
-
-
- enum ITEM_TYPE{
- ITEM_SHUAI = 0, //帅
- ITEM_SHI, //士
- ITEM_XIANG, //象
- ITEM_JU, //车
- ITEM_MA, //马
- ITEM_PAO, //炮
- ITEM_BING, //兵
- ITEM_MAX,
- };
-
- enum ITEM_COLOR{
- COLOR_RED = 0, //红方
- COLOR_BLACK, //黑方
- COLOR_MAX,
- };
-
- class Item
- {
- public:
- Item(){}
- Item(ITEM_TYPE t,ITEM_COLOR c,QPoint pt);
- ~Item(void);
-
- public:
- ITEM_TYPE m_type; //棋子类型
- ITEM_COLOR m_color; //红方黑方
-
- QPoint m_pt; //位置
- bool m_bShow; //是否显示,实现选中时闪烁效果
- };
可以看到,棋子类型的定义和图片中棋子顺序一致,是为了直接以此枚举值计算棋子在图片中的位置。 MainWindow.h: [cpp] view plain copy
- #ifndef MAINWINDOW_H
- #define MAINWINDOW_H
-
- #include <QMainWindow>
- #include "Item.h"
- #include "qmap.h"
-
- namespace Ui {
- class MainWindow;
- }
-
- class MainWindow : public QMainWindow
- {
- Q_OBJECT
-
- public:
- explicit MainWindow(QWidget *parent = 0);
- ~MainWindow();
-
- void InitItems(); <span style="white-space:pre;"> </span>//初始化所有棋子位置
- void NewGame(); <span style="white-space:pre;"> </span>//新游戏
-
- bool FindItemAtPoint(QPoint pt,Item& item); //给定一个棋盘上的点,查找是否存在棋子
- bool DeleteItemAtPoint(QPoint pt,bool& bDeleteSHUAI); <span style="white-space:pre;"> </span>//bDeleteSHUAI:是否打掉的是“帅”或“将”
- void SetItemShow(Item item,bool bShow); //设置棋子显隐
- bool MoveItem(Item item,QPoint ptMoveTo); //走棋逻辑
- void ChangeItemPoint(QPoint ptItem,QPoint pt); <span style="white-space:pre;"> </span>//改变棋子位置属性
-
- void DrawItem(QPainter& painter,Item item); //绘制棋子
-
- //获取棋子能移动的区域
- void GetMoveArea(Item item,QVector<QPoint>& area);
- void GetMoveArea_JU(Item item,QVector<QPoint>& area);
- void GetMoveArea_MA(Item item,QVector<QPoint>& area);
- void GetMoveArea_XIANG(Item item,QVector<QPoint>& area);
- void GetMoveArea_SHI(Item item,QVector<QPoint>& area);
- void GetMoveArea_SHUAI(Item item,QVector<QPoint>& area);
- void GetMoveArea_PAO(Item item,QVector<QPoint>& area);
- void GetMoveArea_BING(Item item,QVector<QPoint>& area);
- protected:
- void paintEvent(QPaintEvent *);
- void mousePressEvent(QMouseEvent *);
- void timerEvent(QTimerEvent *);
-
- private:
- Ui::MainWindow *ui;
-
- int m_nItemWidth;
- int m_nItemHeight;
- QPixmap m_ItemsImage; //棋子图片
-
- QVector<Item> m_items; <span style="white-space:pre;"> </span>//所有棋子
- Item m_SelectedItem;
- bool m_bExistSelectedItem; //是否已存在选中的棋子
- bool m_bIsRedTurn; //当前该红方下
- };
-
- #endif // MAINWINDOW_H
其中主要逻辑都在mousePressEvent 鼠标响应: [cpp] view plain copy
- //鼠标点击,走棋、吃棋等逻辑
- void MainWindow::mousePressEvent(QMouseEvent * e)
- {
- //获得鼠标点所对应的棋盘点pt
- QPoint pt;
- pt.setX( (e->pos().x() - START_X ) / RECT_WIDTH);
- pt.setY( (e->pos().y() - START_Y ) / RECT_HEIGHT);
-
- //是否有选中的棋子
- if(m_bExistSelectedItem)
- {
- //已存在棋子,判断鼠标点击的是否是选中棋子
- if (pt == m_SelectedItem.m_pt)
- {
- //再次点击已经选择的棋子,什么也不做
- return;
- }
- //点击其它棋子
- Item ClickedItem;
- if (FindItemAtPoint(pt,ClickedItem))
- {
- //点击的同色的另外一个棋子,改选
- if ( (m_bIsRedTurn && ClickedItem.m_color == COLOR_RED) ||
- (!m_bIsRedTurn && ClickedItem.m_color != COLOR_RED))
- {
- SetItemShow(m_SelectedItem,true);
- m_SelectedItem = ClickedItem;
- return;
- }
- }
- //点击的异色棋子,判断是否能走能吃
- QVector<QPoint> moveArea;
- GetMoveArea(m_SelectedItem,moveArea); //获取已选择棋子的可移动区域
- if (moveArea.contains(pt))
- {
- //包含当前鼠标点中的棋子,则能吃
- bool bDeleteSHUAI = false;
- DeleteItemAtPoint(pt,bDeleteSHUAI);
- ChangeItemPoint(m_SelectedItem.m_pt,pt);
- if (bDeleteSHUAI)
- {
- QString str = m_bIsRedTurn?QStringLiteral("红方胜利!"):QStringLiteral("黑方胜利!");
- QMessageBox::information(NULL, "GAME OVER ",str, QMessageBox::Yes , QMessageBox::Yes);
- NewGame();
- return ;
- }
- m_bExistSelectedItem = false;
- m_bIsRedTurn = !m_bIsRedTurn;
- update();
- return ;
- }
- else
- {
- //不能走到该位置
- return ;
- }
- }
- else
- {
- //当前没有选中棋子
- Item ClickedItem;
- if (FindItemAtPoint(pt,ClickedItem))
- {
- //如果点中一个棋子,是当前走棋方的颜色,就选中了
- if ( (m_bIsRedTurn && ClickedItem.m_color == COLOR_RED) ||
- (!m_bIsRedTurn && ClickedItem.m_color == COLOR_BLACK))
- {
- m_SelectedItem = ClickedItem;
- m_bExistSelectedItem = true;
- return;
- }
- }
- }
- }
里面最重要的就是这个GetMoveArea 函数,用来获取每个棋子的可走动的区域: [cpp] view plain copy
- void MainWindow::GetMoveArea(Item item,QVector<QPoint>& moveArea)
- {
- switch (item.m_type)
- {
- case ITEM_JU:
- {
- GetMoveArea_JU(item,moveArea);
- break;
- }
- case ITEM_MA:
- {
- GetMoveArea_MA(item,moveArea);
- break;
- }
- case ITEM_XIANG:
- {
- GetMoveArea_XIANG(item,moveArea);
- break;
- }
- case ITEM_SHI:
- {
- GetMoveArea_SHI(item,moveArea);
- break;
- }
- case ITEM_SHUAI:
- {
- GetMoveArea_SHUAI(item,moveArea);
- break;
- }
- case ITEM_PAO:
- {
- GetMoveArea_PAO(item,moveArea);
- break;
- }
- case ITEM_BING:
- {
- GetMoveArea_BING(item,moveArea);
- break;
- }
- }
- }
比如对于棋子“马”,求可以走到的位置: [cpp] view plain copy
- void MainWindow::GetMoveArea_MA( Item item,QVector<QPoint>& moveArea )
- {
- //棋子“马”的计算可移动区域算法简介:
- //1,求出8个待选位置,8个位置的偏移是(-2,-1)(-2,1)(2,-1)(2,1)(1,-2)(1,2)(-1,-2)(-1,2)存在关系:|x|+|y|=3
- //2,判断待选位置是否在棋盘内
- //3,判断中间是否有卡位的棋子
- //4,位置上是否已存在同色棋子
- Item item2;
- for (int i = -2; i<=2; i++)
- {
- for(int j = -2; j<=2; j++)
- {
- if (qAbs(i) + qAbs(j) == 3)
- {
- QPoint ptNew = item.m_pt + QPoint(i,j);
- if (ptNew.x() >= 0 && ptNew.x() <= 8 && ptNew.y()>=0 && ptNew.y() <= 9)
- {
-
- }
- else
- {
- continue;
- }
-
- //求该方向行走路线的 卡位元素位置
- QPoint ptDirect(0,0);
- if (qAbs(i) > qAbs(j))
- {
- if (i>0)
- {
- ptDirect = QPoint(1,0);
- }
- else
- {
- ptDirect = QPoint(-1,0);
- }
- }
- else
- {
- if (j>0)
- {
- ptDirect = QPoint(0,1);
- }
- else
- {
- ptDirect = QPoint(0,-1);
- }
- }
- QPoint ptHit = item.m_pt + ptDirect; //马的卡位元素位置
- if (FindItemAtPoint(ptHit,item2))
- {
- //卡位
- continue;
- }
- if (FindItemAtPoint(ptNew ,item2) && item.m_color == item2.m_color)
- {
- //有本组item
- continue;
- }
- moveArea.append(ptNew);
- }
- }
- }
- }
其它棋子类似,就是仔细处理下就OK了。 4,源码 源码可在学习群免费下载!群号码:1149411109群名称:Qt实战派学习群
|