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.多人贪吃蛇运行结果
源码下载
点击打开链接