为什么是車和炮呢?因为我比较喜欢車和炮直来直去的样子!
本节要介绍的就是整个象棋项目最为重点的地方了——会涉及一些棋子可走路径的搜索算法。以車为例,它的可走路径是四个方向上空位置和异色棋子位置,即单方向遇到的空位置则加入搜索点、遇到同色棋子或异色则停止搜索。
我们先想一下走棋的过程:先用鼠标选中一个棋子,之后再选一个要走的位置,当然,这个位置可能是空位置也可能是对方棋子的位置(吃子);或者是选中一个棋子后,不想走这个棋子,改选其他的棋子。上述的这些动作我们都在鼠标事件中完成。
流程分解:
1.获取鼠标所选棋子
在鼠标事件中,我们使用的功能是当有鼠标点击的事件时,我们获取被点击的位置(不论是左键还是右键)的像素坐标,通过该坐标算出被选中的棋子。
//获得鼠标点击位置所对应的棋子,也可能没有棋子 QPoint pt; pt.setX( (e->pos().x() - START_X ) / RECT_WIDTH); pt.setY( (e->pos().y() - START_Y ) / RECT_HEIGHT);
2.有被选中棋子的几种情况
①再次点击所选棋子,则什么也不做
②走到空位置(重新绘制棋子位置)
③选择其他棋子
1>点击同色棋子,则是改选棋子
2>点击异色棋子时,吃掉(重新绘制棋子位置)
这里我们先搜索出当前棋子的可走路径,然后再判断该异色棋子是否在可走路径之内,如果在,则可吃掉(当吃掉的是老将时,需再做处理);
结合程序说明上述过程:
//再次点击已经选择的棋子,什么也不做 if (pt == m_selectedItem.m_pt) { return; }
//点击其它棋子 Item clickedItem; if (findItemAtLogicPoint(pt,clickedItem)) { //点击的同色的另外一个棋子,改选 if ( (m_bIsRedTurn && clickedItem.m_color == COLOR_RED) || (!m_bIsRedTurn && clickedItem.m_color != COLOR_RED)) { m_selectedItem = clickedItem; return; } }
//点击的异色棋子,判断是否能走能吃QVector<QPoint> moveableArea;//获取已选择棋子的可移动区域getMoveableArea(m_selectedItem,moveableArea);
if(moveableArea.contains(pt)) { //包含当前鼠标点中的棋子,则能吃 bool bDeleteSHUAI = false; deleteItemAtLogicPoint(pt,bDeleteSHUAI); //吃掉//绘制新的棋子位置 changeItemLogicPoint(m_selectedItem.m_pt,pt); update(); //重新绘图生效 }
車的可走路径搜索实现:
炮的搜索路径就不贴程序了~
void MainWindow::getMoveableAreaJU(Item item, QVector<QPoint> &moveableArea){ //棋子“车”的计算可移动区域算法简介: //向4个方向上依次遍历点,把空点都加入。 //当碰到棋子时停止,如果是同色棋子,不加入; //是异色棋子,则加入(该处认为可走,因为可以吃子)
//左边 int x = item.m_pt.x() - 1; while(x >= 0) { QPoint newPoint = QPoint(x,item.m_pt.y()); Item newItem;
if(findItemAtLogicPoint(newPoint,newItem)) { if(newItem.m_color != item.m_color) { moveableArea.append(newPoint); break; } }
moveableArea.append(newPoint); //如果是空点,直接追加 x--;
}
//上边 int y = item.m_pt.y() - 1; while(y >= 0) { QPoint newPoint = QPoint(item.m_pt.x(),y); Item newItem;
if(findItemAtLogicPoint(newPoint,newItem)) { if(newItem.m_color != item.m_color) { moveableArea.append(newPoint); break; } }
moveableArea.append(newPoint); //如果是空点,直接追加 y--; }}
最后来几张效果图片:
棋子、棋盘效果图
車向上移动
炮的隔山打
后记总结:
虽然用到的鼠标事件是相对简单的,但是可以很好的理解事件的应用。Qt框架是以事件来驱动的,鼠标事件、绘图事件、键盘事件、窗体事件、语言改变事件等 等等。