MFC贪吃蛇

2023-08-24 13:01:28 浏览数 (2)

1多人贪吃蛇项目描述

1.1功能描述

实现多人对战贪吃蛇,具体实现功能:A.可以选择游戏人数,最多设置4人同时游戏;B.显示玩家得到的分数;C.可以设置游戏的速度;D.能实现最高分的记录

1.2所需技术

1.在对话框中创建窗口;2.双缓冲绘图;3.蛇身移动处理;4.碰撞检测;5.Ini文件操作

2多人贪吃蛇运行流程

3多人贪吃蛇详细设计

3.1贪吃蛇个体类设计

把贪吃蛇单独的设为一个类,其中包含成员变量如下

代码语言:javascript复制
	BOOL m_bAliveFlg; //蛇当前存活标志
	int	m_iDirect;	//当前蛇先进方向
	int m_iScore;	//分数
	CArray<CPoint,CPoint> m_bufBody;	//蛇身向量

3.2最高分对话框类设计

游戏要记录玩家所玩的最高得分和玩家的姓名。使用ini文件进行记录。最高分对话框分为两种情况,一种是显示当前的最高分,另一种是写入当前的最高分,所以用标志位m_bWriteFlg来区分。

对配置文件的操作用GetPrivateProfileString函数和WritePrivateProfileString函数完成。 具体用法如下所示。

代码语言:javascript复制
GetPrivateProfileString("HERO","NAME","0",bufTmp,MAX_PATH,".\HERO.ini");WritePrivateProfileString("HERO","SCORE",strScore,".\HERO.ini");

3.3贪吃蛇游戏类的设计

3.3.1对话框中创建一个窗体

贪吃蛇游戏类是继承自CWnd类,所以主对话框中OnInitDialog初始化消息时创建一个贪吃蛇游戏类的窗体,如下所示。

代码语言:javascript复制
m_CSnake.CreateEx( WS_EX_CLIENTEDGE, _T("SNAKEMAP"), NULL, WS_VISIBLE| WS_BORDER | WS_CHILD,CRect( 0, 0, 405, 405 ), this, 256 );//新建一个窗口出来

CWinApp这个类有三个virtual成员函数InitApplication、InitInstance和Run。其中InitInstance是为程序创建和显示窗口所设置的。因此在设计程序时,必须在CWinApp类的基础上派生自己的应用程序类,并对函数InitInstance进行重写。所以在应用程序类注册窗口类。

3.3.2双缓冲绘图

绘图可能需要几秒钟甚至更长的时间,而且有时还会出现闪烁现象,为了解决这些问题,可采用双缓冲技术来绘图。双缓冲即在内存中创建一个与屏幕绘图区域一致的对象,先将图形绘制到内存中的这个对象上,再一次性将这个对象上的图形拷贝到屏幕上,这样能大大加快绘图的速度。双缓冲实现过程如下:

1、在内存中创建与画布一致的缓冲区

2、在缓冲区画图

3、将缓冲区位图拷贝到当前画布上

4、释放内存缓冲区

代码语言:javascript复制
CPaintDC dc( this );
    CDC MemDC;//创建与画布一致的缓冲区
MemDC.CreateCompatibleDC( &dc );
CBitmap bmp;
MemDC.SelectObject( &bmp );// 装载背景
MemDC.Rectangle(
					CRect(ysPoint.y*SNAKE_SIZE,
					ysPoint.x*SNAKE_SIZE,
					(ysPoint.y 1)*SNAKE_SIZE,
					(ysPoint.x 1)*SNAKE_SIZE)
					);//在内存中绘图
dc.BitBlt( 0, 0, MAP_RIGHT, MAP_BUTTON, &MemDC,0, 0, SRCCOPY );//将缓冲区位图拷贝到当前画布上

因为游戏类是基于窗口类的,所以所有的绘图消息都可以在OnPaint消息中处理。在OnPaint中,只需要描绘蛇身和食物,后面的逻辑处理与碰撞检测会使用Invalidate()或局部矩形重绘InvalidateRect来产生重绘消息。

3.3.3游戏碰撞检测

只需要判断蛇头的坐标与待判定的坐标是否重合,重合就发生了碰撞,说明该蛇死亡了。

3.3.4蛇身移动处理

方法一:1.得到蛇身数组第一个点的坐标,即蛇头的坐标;2.使蛇头后面的开始的每一个点的坐标等于上一个点的坐标,例如:蛇头下一个点的坐标等于蛇头的坐标。然后重绘。

这里提供另一种方案二:1.首先获得蛇身向量的第一个点的坐标,这里说明下蛇身向量的坐标是与真实绘图相差10倍的。

代码语言:javascript复制
CPoint ysPoint=m_CSnakeIndv[iCnt].m_bufBody.GetAt(0);     //获取蛇身的第一个点坐标

2.根据蛇的方向,使这个坐标值发生变动。改变的是蛇头的坐标值。

3.判断ysPoint这个坐标是否发生过界或碰撞,如果蛇死亡。

代码语言:javascript复制
int iSnakeLen = m_CSnakeIndv[iCnt].m_bufBody.GetUpperBound();
				for ( ; iSnakeLen >= 0; iSnakeLen--)
				{
					CPoint pt=m_CSnakeIndv[iCnt].m_bufBody.GetAt(iSnakeLen);//将最后一个赋给pt
					m_CSnakeIndv[iCnt].m_bufBody.RemoveAt(iSnakeLen);       //将移出最后一个
					ReDrawBody(pt);                                //重新绘制pt这点
				}
				m_CSnakeIndv[iCnt].m_bAliveFlg = FALSE;

说明:重绘整个蛇身,这里是取出蛇身的动态数组的最后一个元素,重绘这个点,并把这个点从蛇身数组中移除,以此类推,直到重绘整个蛇身,使死亡了的蛇不在屏幕中显示出来。

如果这个新点没有发生越界或是碰撞,说明游戏可以继续进行下去。

代码语言:javascript复制
m_CSnakeIndv[iCnt].m_bufBody.InsertAt(0,ysPoint);    //将新点添加到蛇的身体中
				ReDrawBody(ysPoint);           //重绘蛇的身体

说明:把这个新点添加到蛇身向量中,是插入到第0个位置,原来的蛇身数组里元素每位向后移动一位。

如果新点的位置与食物的位置是重合的。主要进行如下处理。

代码语言:javascript复制
CPoint pt=m_CSnakeIndv[iCnt].m_bufBody.GetAt(m_CSnakeIndv[iCnt].m_bufBody.GetUpperBound());//将最后一个赋给pt
					m_CSnakeIndv[iCnt].m_bufBody.RemoveAt(m_CSnakeIndv[iCnt].m_bufBody.GetUpperBound());       //将移出最后一个
					ReDrawBody(pt);                                //重新绘制pt这点

说明:得到蛇身数组的最后一个点坐标,把这个点从蛇身数组移除出去,重绘该点。这样,就说明绘图中会移除蛇尾,就是视觉上蛇的移动是蛇头前插入一个元素,蛇尾去除一个元素,这样造成蛇移动的效果。

4.多人贪吃蛇运行结果

源码下载

点击打开链接

0 人点赞