贪吃蛇大家肯定都玩过,这里我就暂时不给出做好的DEMO了,我们一起来一步一步实现贪吃蛇

在此之前一定要说明的是,这是基于MFC的贪吃蛇,所以你必须的掌握MFC和C++的基础(后期会出一个基于C语言控制台的),其次,里面的代码一定要自己练习,掌握,复制粘贴是学不会的!


我们这里实现的只是一些基本的功能,如果大家想添加一些比如关卡,分数金钱等等可以完成之后自行添加,不懂的可以来提问,我们会尽量帮大家解决。
如果大家觉得有什么不妥的地方或者有什么疑问可以向我说

首先我们拿VS建立一个MFC的工程,工程名叫Snake,选择对话框工程。(这一步不会的,可以先去看MFC基础教程了)

工程建好后,我们会得到这样的对话框

我们把上面的控件全部删了,然后规划下游戏窗口区域

上图中,我画了一个绿色的框框,绿色框框里面,表示是游戏区域。也就是蛇运动的区域,当蛇碰到这个绿色边框,或者出了边框,游戏就结束,就得重新来过。

也就是说,我们得在对话框上画一个边框出来,为了好看,最好在里面加上别的颜色,比如,把对话框涂黑,然后画一条绿色边框

比如像这个样子

(这个图是我用微软自带的画图工具画的)

好的,既然我们有了目标,那我们来简单的规划下,

首先,我们得有办法把窗口涂黑,我们知道,在对话框重绘的时候 会调用OnPaint,那就是说,我们只有在OnPaint里面调对应的画图函数,就能把窗口涂黑了,

然后,窗口不能盲目的涂黑,我们得在边框留成绿色,让玩家知道 什么时候是要出边界了,

所以,我们得窗口应该得改成这样子

111111111111111
100000000000001
100000000000001
100000000000001
100000000000001
111111111111111

我们把上面的一串数字想象成我们的窗口,1表示边框,0表示游戏区域,也就是说,我们只要能把窗口和上面的数字对应起来,我们就能按数字的内容给软件染色,这就简单了,我们可以定义一个二维数据,把它初始化成上面那样

既然有了思路,那我们开始写代码吧~

首先我们打开SnakeDlg.cpp(如果你们的工程名不叫Snake的话,就不叫这个名字,比如你的工程叫dbgpro的话,文件就叫dbgproDlg.cpp)

我们找到OnPaint函数,OnPaint函数代码如下

void CSnakeDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

我们把里面的代码全部删了,只留下 CPaintDC dc(this); 和CDialogEx::OnPaint();

当然,这一步不是必要了,只是为了代码更少,我们看起来方便,如果你懒得删的话,把我们要添加代码写到esle分支就行了

精简后的代码如下

void CSnakeDlg::OnPaint()
{
	CPaintDC dc(this); // 用于绘制的设备上下文

	CDialogEx::OnPaint();
}

我们先去头文件,定义一个int数组

private:
int m_arrGameRange[18][20];
这里,我们定义了一个18行,20列的数组来表示游戏区域,当然,在实际项目中,这种“魔数”最好用宏定义,比较方便改,我们这里也改成宏好了

数组定义好以后,我们定义一个初始化函数,专门用来初始化游戏的数据,void InitGameData();因为这个函数不会在外部调用,我把它设为私有函数好了,

那么,我们根据上面的那一堆数字来思考下,我们要怎么初始化数据

111111111111111
100000000000001
100000000000001
100000000000001
100000000000001
111111111111111

我们看到第1行(下标是0)和最后一行(下标是GAME_ROW-1)

第1列(下标是0)和最后一列(下标是GAME_COL-1)

要设置1,其他的是0,那么代码如下

void CSnakeDlg::InitGameData()
{
	for (int i=0; i<GAME_COL; i++)
	{
		for (int j=0; j<GAME_ROW;j++)
		{
			if ((i==0||i==GAME_COL-1)||(j==0||j==GAME_ROW-1))
			{
				m_arrGameRange[i][j] = 1;
			}
			else
			{
				m_arrGameRange[i][j] = 0;
			}
		}
	}
}

我们知道,对话框创建好了调用的第一个函数是OnInitDialog(),我们在OnInitDialog()函数的return之前调用我们得初始化函数,

然后调试看看对不对

结果是对的,现在我们就在对话框重绘的时候,也就是OnPaint来调用画图的函数,把颜色涂上去,

我们先把对话框涂黑,然后再涂边框

编写后 OnPaint的代码如下

void CSnakeDlg::OnPaint()
{
	CPaintDC dc(this); // 用于绘制的设备上下文

	CBrush brushGame(RGB(255,255,255));//创建黑色画刷 用来画游戏区域
	CBrush brushBorder(RGB(34,176,76));//创建绿色画刷 用来画边框

	//遍历行、列来画不同的颜色
	for (int i = 0; i < GAME_COL; i++)
	{
		for (int j = 0; j < GAME_ROW; j++)
		{
			//根据行列来计算一个矩形大小,每个矩形占20个像素
			CRect rt;
			rt.left = i*20;
			rt.top = j*20;
			rt.right = rt.left + 20;
			rt.bottom = rt.top + 20;
			if (m_arrGameRange[i][j] == 1)//需要画边框
			{
				dc.SelectObject(brushBorder);//把我们得画刷选入DC
				dc.Rectangle(rt);//填充矩形,参数表示要填充的矩形区域
			}
			else
			{
				dc.SelectObject(brushGame);//把我们得画刷选入DC
				dc.Rectangle(rt);//填充矩形,参数表示要填充的矩形区域
			}
		}
	}
	CDialogEx::OnPaint();
}

效果如下

我们发现,我们画的列太少了,得加几个(哈哈, 定义成宏的优势出来了),然后每个格子有黑线,

我们先把列的宏改大点。我改成28刚刚好

#define GAME_COL 28 //游戏区域的列

每个格子有黑线,是因为我们用的Rectangle这个函数画的,它帮我们画了边框,我是为了方便调试,故意用的它现在我们把红酒的颜色换成黑色,然后顺便把黑框框去掉,去掉黑框框简单,只要把

dc.SelectObject(brushBorder);//把我们得画刷选入DC
dc.Rectangle(rt);//填充矩形,参数表示要填充的矩形区域

换成dc.FillRect(rt, &brushGame);

最终的代码如下

void CSnakeDlg::OnPaint()
{
	CPaintDC dc(this); // 用于绘制的设备上下文

	CBrush brushGame(RGB(0,0,0));//创建黑色画刷 用来画游戏区域
	CBrush brushBorder(RGB(34,176,76));//创建绿色画刷 用来画边框

	//遍历行、列来画不同的颜色
	for (int i = 0; i < GAME_COL; i++)
	{
		for (int j = 0; j < GAME_ROW; j++)
		{
			//根据行列来计算一个矩形大小,每个矩形占20个像素
			CRect rt;
			rt.left = i*20;
			rt.top = j*20;
			rt.right = rt.left + 20;
			rt.bottom = rt.top + 20;
			if (m_arrGameRange[i][j] == 1)//需要画边框
			{
				//填充矩形的函数,
				//第一个参数是要填充的矩形
				//第二个参数是什么什么画刷填充矩形
				dc.FillRect(rt, &brushBorder);
			}
			else
			{
				dc.FillRect(rt, &brushGame);
			}
		}
	}
	CDialogEx::OnPaint();
}

最终效果如下

好了,今天就到这里,下次我们要在这条代码上实现一条蛇~

打赏