> 文档中心 > VC6.0 MFC 单文档 五子棋游戏 基础入门

VC6.0 MFC 单文档 五子棋游戏 基础入门


五子棋游戏

一、整体思路

1、目的:通过五子棋,掌握面向对象的思想,这是我们的目的。提升分析问题、解决问题的能力,在做项目之前要有一个系统的思路,第一步干什么,第二步干什么……

2、思路:拿到这个问题,我们首先要设计一个类(CWuZiQi),设计一个类首先要想到它有哪些成员变量,有哪些属性。最核心的一个成员变量是棋盘(用二维数组m_QP[19][19]表示,数组是该程序的核心)。用0表示棋盘上没有棋子,用1表示黑子,2表示白子。我们还需要行(m_H)、列(m_L),以及当前棋子的颜色(m_Color)。

3、核心的三个函数:一个Draw函数;一个下棋(XiaQi)函数,下棋函数在按下鼠标时调用(传过来一个点的坐标);一个判断输赢(PanDuan)的函数。

二、最终实现效果图
在这里插入图片描述

三、实现步骤(前期)

1、新建一个MFC单文档应用程序,如下图所示。
在这里插入图片描述
在这里插入图片描述
2、设计一个类(CWuZiQi),添加一些成员变量并初始化,如下图所示。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3、先从简单的入手,把棋盘画出来。为了让界面更加美观,我们还可以画棋盘的背景(放大后整个屏幕的背景以及棋盘游戏区域背景)以及棋盘上面的九个星位,如下图所示。

①画棋盘背景
在这里插入图片描述

画棋盘背景代码如下:

//画屏幕背景和棋盘背景void CWuZiQi::DrawBackground(CDC *pDC){CBrush brush1,*pOldBrush1;brush1.CreateSolidBrush(RGB(255,222,173));pOldBrush1 = pDC->SelectObject(&brush1);pDC->Rectangle(0,0,1920,960); //整个屏幕大小brush1.DeleteObject();pDC->SelectObject(pOldBrush1);//==============================================int x,y,r;x = ydx;y = ydy;r = 18 * lenbl;CBrush brush2,*pOldBrush2;brush2.CreateSolidBrush(RGB(244,164,96));pOldBrush2 = pDC->SelectObject(&brush2);pDC->Rectangle(x,y,x + r,y + r); //棋盘大小brush2.DeleteObject();pDC->SelectObject(pOldBrush2);}

②画棋盘九个星位
在这里插入图片描述
画棋盘九个星位代码如下:

//画棋盘上的九个星位void CWuZiQi::DrawXingWei(CDC *pDC){int x,y,r; for (int i = 4; i < 19; i+=5){for (int j = 4; j < 19; j+=5){x = ydx + i * lenbl;y = ydy + j * lenbl;r = lenbl/8;CBrush brush,*pOldBrush;brush.CreateSolidBrush(RGB(0,0,0)); //画星位pOldBrush = pDC->SelectObject(&brush);pDC->Ellipse(x - r, y - r, x + r, y + r);brush.DeleteObject();pDC->SelectObject(pOldBrush);}}}

③画棋盘
在这里插入图片描述
画棋盘代码如下:

//画棋盘void CWuZiQi::DrawQiPan(CDC *pDC){DrawBackground(pDC); //调用背景要放在画棋盘前面,若放在后面棋盘会被覆盖int x,y;for (int i = 0; i < 19; i++){x = ydx;y =  ydy + i * lenbl;pDC->MoveTo(x,y);x += 18 * lenbl;pDC->LineTo(x,y); //画行数x = ydx + i * lenbl;y = ydy;pDC->MoveTo(x,y);x += 18 * lenbl;pDC->LineTo(x,y); //画列数}DrawXingWei(pDC); //调用画的九个星位}

4、紧接着就是画棋子喽,用黑色画刷画黑子,白色画刷画白子,如下图所示。
在这里插入图片描述
画棋子代码如下:

void CWuZiQi::DrawQiZi(CDC *pDC){int i,j; int x,y;int r = lenbl/3;//棋子半径for (i = 0; i < 19; i++){for (j = 0; j < 19; j++){if (m_Qp[i][j] != 0) //如果棋盘上有子{if (m_Qp[i][j] == 1) //并且是黑子{CBrush brush,*pOldBrush;brush.CreateSolidBrush(RGB(0,0,0)); //画黑子pOldBrush = pDC->SelectObject(&brush);x = ydx + i * lenbl;y = ydy + j * lenbl;pDC->Ellipse(x - r, y - r, x + r, y + r);brush.DeleteObject();pDC->SelectObject(pOldBrush);}else if (m_Qp[i][j] == 2) //并且是白子{CBrush brush,*pOldBrush;brush.CreateSolidBrush(RGB(255,255,255)); //画白子pOldBrush = pDC->SelectObject(&brush);x = ydx + i * lenbl;y = ydy + j * lenbl;pDC->Ellipse(x - r, y - r, x + r, y + r);brush.DeleteObject();pDC->SelectObject(pOldBrush);}}}}}

5、再添加一个成员函数Draw(CDC *pDC),调用上面画好的棋盘、棋子,如下图所示。
在这里插入图片描述
调用代码如下:

void CWuZiQi::Draw(CDC *pDC){DrawQiPan(pDC);DrawQiZi(pDC);}

6、步步为营,我们可以先在CGobangGameView里将#include “WuZiQi.h”头文件嵌入进来,并引入成员变量,如下图所示。
在这里插入图片描述
在这里插入图片描述
7、编译运行就能看见前期的效果了,由于还没有添加鼠标响应函数,所以棋子暂时没法显示。如下图所示。
在这里插入图片描述

四、实现步骤(中期)

中期主要就是两个工作,一个下棋函数,一个判断函数。

1、添加下棋成员函数,并编写代码(下棋函数在按下鼠标时调用(传过来一个点的坐标)),如下图所示。
在这里插入图片描述
下棋代码:

void CWuZiQi::XiaQi(CPoint pt){//确定下棋边界if (pt.x > (ydx - lenbl/3) && pt.x < (ydx + 18 * lenbl + (lenbl/3)) &&\pt.y > (ydy - lenbl/3) && pt.y < (ydy + 18 * lenbl + (lenbl/3)))//注:lenbl/3是棋子半径,当棋子边缘碰到棋盘线时,也默认在棋盘内。{m_H = (pt.x - ydx + lenbl/4)/lenbl; //用当前点击位置减去原点距离,加上1/4小格的结果,整除小方格,确定在哪一行m_L = (pt.y - ydy + lenbl/4)/lenbl; //获取落子位置}if (m_Qp[m_H][m_L] == 0 && m_Color == 1) //落子位置没有棋子,并且是黑子下{m_Qp[m_H][m_L] = 1; //将当前点击的位置设置为黑子PanDuan(); //判断添加棋子后是否有五子if (m_Qp[m_H][m_L] == 1) //如果当前点击位置显示的是黑子,即黑子刚刚下过{m_Color = 2; //立即换白子下棋}else if (m_Qp[m_H][m_L] == 2) //如果当前点击位置显示的是白子,即白子刚刚下过{m_Color = 1; //立即换黑子下棋}}else if (m_Qp[m_H][m_L] == 0 && m_Color == 2) //落子位置没有棋子,并且是白子下{m_Qp[m_H][m_L] = 2; //将当前点击的位置设置为白子PanDuan(); //判断添加棋子后是否有五子if (m_Qp[m_H][m_L] == 1) //如果当前点击位置显示的是黑子,即黑子刚刚下过{m_Color = 2; //立即换白子下棋}else if (m_Qp[m_H][m_L] == 2) //如果当前点击位置显示的是白子,即白子刚刚下过{m_Color = 1; //立即换黑子下棋}}}

2、添加判断函数,并编写代码,如下图所示。
在这里插入图片描述
判断代码:

void CWuZiQi::PanDuan(){int i; //用来循环遍历的int left = 0,right = 0; //左右下棋for (i = 1; i <= 4; i++){if (m_Qp[m_H][m_L - i] == m_Color) //以(m_H,m_L)为中心,向左找,注意是列在减小,而不是行!left++;elsebreak; //碰到一个不是当前颜色的就停止}for (i = 1; i <= 4; i++){if(m_Qp[m_H][m_L + i] == m_Color) //以(m_H,m_L)为中心,向右找,注意是列在增大,而不是行!right++;elsebreak;}//=================================================================================================================int up = 0,down = 0; //上下下棋for (i = 1; i <= 4; i++){if (m_Qp[m_H - i][m_L] == m_Color) //以(m_H,m_L)为中心,向上找,注意是行在减小,而不是列!(竖直向下为正)up++;elsebreak; //碰到一个不是当前颜色的就停止}for (i = 1; i <= 4; i++){if(m_Qp[m_H + i][m_L] == m_Color) //以(m_H,m_L)为中心,向下找,注意是行在增大,而不是列!down++;elsebreak;}//=================================================================================================================int leftup = 0,rightdown = 0; //左上、右下,“\”下棋for (i = 1; i <= 4; i++){if (m_Qp[m_H - i][m_L - i] == m_Color) //以(m_H,m_L)为中心,向左上找,行列均在减小leftup++;elsebreak; //碰到一个不是当前颜色的就停止}for (i = 1; i <= 4; i++){if(m_Qp[m_H + i][m_L + i] == m_Color) //以(m_H,m_L)为中心,向右下找,行列均在增大rightdown++;elsebreak;}//=================================================================================================================int leftdown = 0,rightup = 0; //左下、右上,“/”下棋for (i = 1; i <= 4; i++){if (m_Qp[m_H + i][m_L - i] == m_Color) //以(m_H,m_L)为中心,向左下找,行在增大,列在减小leftdown++;elsebreak; //碰到一个不是当前颜色的就停止}for (i = 1; i <= 4; i++){if(m_Qp[m_H - i][m_L + i] == m_Color) //以(m_H,m_L)为中心,向右上找,行在减小,列在增大rightup++;elsebreak;}//=================================================================================================================if (left + right >= 4 || up + down >= 4 || leftup + rightdown >= 4 || leftdown + rightup >= 4){if(m_Color == 1)AfxMessageBox("黑棋获胜!");if(m_Color == 2)AfxMessageBox("白棋获胜!");}}

五、实现步骤(后期)

1、在CGobangGameView里添加WM_LBUTTONDOWN
句柄,实现下棋时的消息响应,如下图所示。
在这里插入图片描述
在这里插入图片描述
代码如下:

void CGobangGameView::OnLButtonDown(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultWZQ.XiaQi(point); //下棋响应Invalidate(TRUE);CView::OnLButtonDown(nFlags, point);}

2、为了更方便的显示当前是谁正在下棋,我们还可以定义两个鼠标(黑、白),若是黑子正在下,则显示黑棋鼠标;若是白子正在下,则显示白棋鼠标。如下图所示。
在这里插入图片描述
在这里插入图片描述
3、在CGobangGameView里添加WM_SETCURSOR
句柄,实现下棋时的消息响应,如下图所示。
在这里插入图片描述
在这里插入图片描述
4、在CGobangGameView里定义黑白鼠标的成员变量,并在构造函数里加载刚刚画的黑白棋子图像,如下图所示。
在这里插入图片描述
在这里插入图片描述
代码如下:

BOOL CGobangGameView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) {// TODO: Add your message handler code here and/or call defaultif (nHitTest == HTCLIENT){//黑子下,显示黑棋鼠标if(WZQ.m_Color == 1)SetCursor(m_csrblack);//白子下,显示白棋鼠标elseSetCursor(m_csrwhite);return 1;}return CView::OnSetCursor(pWnd, nHitTest, message);}

六、运行结果
在这里插入图片描述
在这里插入图片描述

七、总结
本设计基本实现了一个简单的人人对战五子棋游戏,整体设计难度偏小,对刚刚接触MFC的初学者来说是很好的一篇参考素材。
通过该游戏的设计,对面向对象的程序设计思想有了更加深刻的认识,也渐渐明白在做项目之前形成系统思路的重要性。
本文最满意的地方是对成员变量的巧妙运用,只需在构造函数里改变原点坐标位置(ydx,ydy)和棋盘上每个小方格的大小比例(lenbl)就能改变与之相关的内容,比如棋盘大小,游戏边界,棋子大小,游戏背景大小,等等,更加方便了程序的后期运行和维护。