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++;
		else
			break; //碰到一个不是当前颜色的就停止
	}
	for (i = 1; i <= 4; i++)
	{
		if(m_Qp[m_H][m_L + i] == m_Color) //以(m_H,m_L)为中心,向右找,注意是列在增大,而不是行!
			right++;
		else
			break;
	}
//=================================================================================================================
	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++;
		else
			break; //碰到一个不是当前颜色的就停止
	}
	for (i = 1; i <= 4; i++)
	{
		if(m_Qp[m_H + i][m_L] == m_Color) //以(m_H,m_L)为中心,向下找,注意是行在增大,而不是列!
			down++;
		else
			break;
	}
//=================================================================================================================
	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++;
		else
			break; //碰到一个不是当前颜色的就停止
	}
	for (i = 1; i <= 4; i++)
	{
		if(m_Qp[m_H + i][m_L + i] == m_Color) //以(m_H,m_L)为中心,向右下找,行列均在增大
			rightdown++;
		else
			break;
	}
//=================================================================================================================
	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++;
		else
			break; //碰到一个不是当前颜色的就停止
	}
	for (i = 1; i <= 4; i++)
	{
		if(m_Qp[m_H - i][m_L + i] == m_Color) //以(m_H,m_L)为中心,向右上找,行在减小,列在增大
			rightup++;
		else
			break;
	}
//=================================================================================================================
	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 default
	WZQ.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 default
	if (nHitTest == HTCLIENT)
	{
		//黑子下,显示黑棋鼠标
		if(WZQ.m_Color == 1)
			SetCursor(m_csrblack);
		//白子下,显示白棋鼠标
		else
			SetCursor(m_csrwhite);
		return 1;
	}
	return CView::OnSetCursor(pWnd, nHitTest, message);
}

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

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

  • 26
    点赞
  • 150
    收藏
    觉得还不错? 一键收藏
  • 24
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值