windows编程大作业jsl.docx

上传人:b****4 文档编号:4690326 上传时间:2023-05-07 格式:DOCX 页数:11 大小:184.55KB
下载 相关 举报
windows编程大作业jsl.docx_第1页
第1页 / 共11页
windows编程大作业jsl.docx_第2页
第2页 / 共11页
windows编程大作业jsl.docx_第3页
第3页 / 共11页
windows编程大作业jsl.docx_第4页
第4页 / 共11页
windows编程大作业jsl.docx_第5页
第5页 / 共11页
windows编程大作业jsl.docx_第6页
第6页 / 共11页
windows编程大作业jsl.docx_第7页
第7页 / 共11页
windows编程大作业jsl.docx_第8页
第8页 / 共11页
windows编程大作业jsl.docx_第9页
第9页 / 共11页
windows编程大作业jsl.docx_第10页
第10页 / 共11页
windows编程大作业jsl.docx_第11页
第11页 / 共11页
亲,该文档总共11页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

windows编程大作业jsl.docx

《windows编程大作业jsl.docx》由会员分享,可在线阅读,更多相关《windows编程大作业jsl.docx(11页珍藏版)》请在冰点文库上搜索。

windows编程大作业jsl.docx

windows编程大作业jsl

《Windows编程》大作业

题目:

基于MFC的小游戏实现(贪吃蛇小游戏)

姓名:

江师朗

学号:

1205110619

班级:

软工1202班

专业:

软件工程

院系:

数学与计算机学院

指导老师:

刘文涛

 

1、题目介绍

这是一款比较需要耐心的游戏,用游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关!

2、系统分析

一 、要解决的问题 我们设计的这个贪食蛇小游戏应该有以下几个功能:

 

  1、 要求有比较友好的界面,界面应该包括得分显示,游戏状态(运动,暂停,结束),游戏难易程度显示(容易,较难,困难),关于游戏(包括教初玩者如何操作,及游戏规则)。

 另外,在界面显示的效果应该简洁大方,尽量能够很快吸引玩者。

 

  2 、当游戏刚开始的时候,先应该产生一条蛇和随机产生一个食物。

当按某个键的时候,蛇就开始移动,按照按键的方向运动。

   

3 、蛇可以运动,随着难易程度的不同,蛇的速度也不同;在界面里可以随机产生一个食物,但应该注意不能和蛇身体一致,然后当蛇就移动然后吃掉这个食物(覆盖),然后蛇的身体应该相应地增加,同时界面中显示分数一栏应该相应地增加分值;当蛇在移动的过程中头部碰到墙壁,游戏结束。

 

二 、提出的要求 

  1 按键的时候可以控制蛇移按照设置的方向移动; 

  2 当选择游戏的难易程度不同时,蛇体的速度应该也是不同的;   

3 当游戏开始时候,应该有一个初始化,设置蛇身,食物等; 

  4 当游戏结束时,会有相应的处理,比如提示;    

三 可以实现的要求 

  1 简单友好的界面   

2 蛇的移动和控制 

  3 对蛇的状态的监听,及对得分的显示;   

4 蛇的状态的变化  

四 应该有的对象及其他们之间的关系 

  1 Game对象   

2 Wall对象   

3 Snake对象   

4 Food对象 

它们之间的关系:

Game对象中应该包括其他三个对象;Snake对象和Food对象应该有相同的形状。

这几个对象差不多可以反映上面的要求。

  

五 关键点 

  该游戏最关键的地方应该是:

 

 1 在监听蛇的状态的方法实现并处理;   

2 蛇的运动算法实现过程;

六开发工具

Visualc++

七开发环境

本系统开发平台采用Windows XP Professional, Windows XP Professional是美国微软公司纯32位客户机平台,适合对系统要求较高、运算量较大的应用软件运行。

而用户环境可以在起他平台上。

 

开发软件本系统选用Visual C++ 6.0/MFC作为系统开发工具。

开发系统底层的东西,需要极好的兼容性和稳定性,第一选择是visual c++。

同时Visual c++是开发Windows应用程序的主流开发工具,可以利用的资源多。

 Visual C++ 不仅仅是一个编译器。

它是一个全面的应用程序开发环境,使用它你充分利用具有面向对象特性的 C++ 来开发出专业级的 Windows 应用

程序。

Visual  C++作为一种程序设计语言,它同时也是一个集成开发工具,提供了软件代码自动生成和可视化的资源编辑功能。

在使用Visual  C++开发应用程序的过程中,系统为我们生成了大量的各种类型的文件。

 

Visual C++采用的框架是MFC。

MFC不仅仅是人们通常理解的一个类库。

你如果选择了MFC,也就选择了一种程序结构,一种编程风格。

MFC 是一个很大的、扩展了的 C++ 类层次结构,它能使开发 Windows 应用程序变得更加容易。

MFC 是在整个 Windows 家族中都是兼容的,也就是说,无论是 Windows3.x、Windows95 还是 Windows NT,所使用的 MFC 是兼容的。

每当新的 Windows 版本出现时,MFC 也会得到修改以便使旧的编译器和代码能在新的系统中工作。

MFC 也回得到扩展,添加新的特性、变得更加容易建立应用程序。

 使用 MFC 的最大优点是它为你做了所有最难做的事。

MFC 中包含了上成千上万行正确、优化和功能强大的 Windows 代码。

你所调用的很多成员函数完成了你自己可能很难完成的工作。

从这点上将,MFC 极大地加快了你的程序开发速度 

由于MFC编程方法充分利用了面向对象技术的优点,它使得我们编程时极少需要关心对象方法的实现细节,同时类库中的各种对象的强大功能足以完成我们程序中的绝大部分所需功能,这使得应用程序中程序员所需要编写的代码大为减少,有力地保证了程序的良好的可调试性。

 

最后要指出的是MFC类库在提供的对象的各种属性和方法都是经过谨慎的编写和严格的测试,可靠性很高,这就保证了使用MFC类库不会影响程序的可靠性和正确性。

 

在系统开发过程中,不仅用到了MFC编程技术,还用到了GDI编程。

GDI中画笔对象能与用于提供绘制方法的图形对象分开创建于维护,Graphics绘图方法直接将Pen对象作为自己的参数,从而避免了在GDI使用SelectObject进行繁琐的切换,类似的还有Brush、Path、Image和Font等。

 

二、功能实现

游戏中存在多个可见性物体(对象),但是并不需要给所有对象都设计一个类。

当某个对象具备若干属性和行为动作(方法),并需要这些方法表现该对象的特殊性时,应该将该物体归结为一个类的对象。

如果物体只用单一的属性就可以描述它在外界的存在,就不必归纳为一个类对象。

 

对于游戏中所有可见性物体进行分析,只有蛇和屏幕可以划分为对象。

蛇不同于水果、墙等物体,蛇除了有一系列的属性,如位置、长度、当前状态等,还有一些表现方法,如移动、吃果子、变长。

所以蛇应该划分为一个类。

 

提供蛇、果子等这些物件的展现的是屏幕。

这里可以将屏幕划分为很多细小的方块,而其他物件只是摆放在其中罢了。

所以屏幕也要划分为对象。

把屏幕归结为背景类,其属性为蛇,水果,墙;方法为令蛇在背景上移动,放置水果和虫子,当水果被吃掉时清楚水果,当水果被清楚时放置虫子。

于是整个游戏就归纳出蛇和桌子两个类对象。

在前期的设计中,有时候归纳的对象并不完善,在细化过程中,可能会发现新的对象,对于这中情况,对新抽象出来的对象逐一添加即可。

 

对象确定以后的问题是确定对象的方法和属性。

每个对象都有一定的方法和属性,可以通过对象访问或者改变其属性,从而表现该对象实体的当前实质状态。

所以方法是根据该对象有什么特性动作而设计构造出来的。

而属性可以代表该对象的内部结构,对象应该有什么样的数据结构,完全取决与它所展现的形式。

CSnake类的细化 

(1) 蛇的数据结构以及属性的设计:

首先考虑的是如何表示整条蛇的变量,该变量的特征是一系列有序点的集合,所以在蛇的数据结构中应定义CPoint pos 表示蛇的坐标。

蛇身的数据结构是点的集合。

所以应该设置一个结构体,方便于存储一个节点的信息。

为了便于程序的实现,该结构体中不仅存储了屏幕坐标信息,而且存储了相对应的二维表坐标信息。

有了单个点的结构以后就可以用它来定义蛇头和蛇身。

在这里,蛇身使用数组结构体表示。

用snakeSize表示蛇的长度。

在游戏中,蛇头的朝向有四个方向,对于不用方向的处理在程序中解决,这里不再单独作为一个属性。

 

(2) 蛇的移动操作:

蛇身的移动,也就是蛇的数据结构点集的移动。

蛇移动的过程中,蛇头的移动的每个方向对应的结构也不相同,需要单独处理。

蛇身上任意点的位置,在下一时刻会改变为其前一个点的位置。

移动蛇所需要的操作是把整个数组的点集的位置整体前移一位,把蛇头的位置赋值给点集的第一个节点。

 

算法总体流程如下:

 

void CSnake:

:

snakeMove(int direct) { 

 初始化变量;  选择方向; 

 如果方向向上,数组的点集的位置整体前移一位; 

蛇身第一个节点,它的位置是蛇头的位置,应该单独赋值;*/ 

  利用convertPos(&head,head.xx,head.yy-1)函数对蛇头赋值;  

„„ } 

convertPos()函数实现了坐标的转换。

由于是引用传值,会改变对象。

这个函数传入的参数是二维表坐标信息,在函数中会根据二维表信息,对相应屏幕坐标信息赋值并保存,这样的好处在于,在游戏代码中可以直接对二维表坐标进行操作,移动只需要加一或者减一,不用考虑实际的图片位置的移动,函数已经把两个坐标对应,不需要在进行其他计算。

 

void CSnake:

:

convertPos(struct dataSnake *data, int x_pos, int y_pos) {   二维表坐标的赋值; 

  将二维表坐标转化为相应的屏幕坐标; 

(3) 蛇的增长:

蛇的增长根据蛇的存储方式不同,也有不同的方法。

动态分配空间方式可以按照需求分配实际大小空间,可以节约空间。

但是在蛇身增长的时候需要对增长的部分重新分配,增加了实现的复杂度。

如果用静态分配空间的方式,在程序的实现上要简单的多。

不足之处在于分配的空间是

固定的,也就是说的蛇的长度有一个限制。

蛇的增长需要特别对蛇身的第一个节点进行处理,蛇在增长过程中蛇身第一个节点的位置是蛇头前一时刻的位置,因此要对其单独处理,而其他节点可以通过对蛇身数组的整体移动进行赋值。

 

(4) 游戏结束判定:

当蛇头触及墙壁或者蛇身的时候游戏结束,游戏的结束于蛇头的位置先关,所以把游戏结束的判定作为CSnake对象的一个方法。

对于游戏结束的判定,要借助于BackGround类中Table结构体。

BackGround类把整个屏幕绘制成一张大表格,存储了所有游戏中相关的信息,包括蛇本身。

游戏输赢判定,即蛇头下一时刻的位置判定。

如果蛇头下一时刻的位置在墙上或者在蛇身上,游戏结束。

对于位置的判定,首先要把蛇头的实际坐标转化为表格坐标(表格是一个二位数组,在BackGround类中在详细介绍)。

坐标转化过后,检测蛇头下个位置的状态,如果该位置为虫子或者墙就判定游戏结束,结束游戏,并返回一个游戏结束的值。

通知应用程序游戏结束,等待其他操作。

 

在游戏判断时,经过坐标转化,蛇的位置信息和桌面二维表下标一一对应,判断蛇是否触及墙壁只需要判断蛇头所对应下标是否在二维表下标之外。

在程序设计中之所以判断蛇头坐标是因为蛇身下一时刻位置是当前蛇头的位置,当且仅当蛇头触及墙壁的时候,游戏才会结束。

只需要判断蛇头的位置所对应的下标在不在二维表所对应下标范围内,如果在则游戏没结束,不在则游戏结束。

 

算法总体流程如下:

 

bool CSnake:

:

GameOver()  //如果蛇头触碰墙壁则游戏结束 { 

如果蛇头坐标在在二维表坐标范围内,函数返回真; 否则返回假;  

bool CSnake:

:

headTouchBody()//如果蛇头触碰蛇身则游戏结束  { 

循环比较蛇头的位置和蛇身每个点的位置,一旦有位置相同函数返回真; 

 

 

否则返回假; 

(5) 蛇的显示:

游戏中蛇的显示是把位图打印到屏幕上。

在显示位图的时候如果直接打印到屏幕,会在蛇的周围产生一个白色框架。

这是需要进行透明处理。

 

(6) CSnake类的定义:

BackGround类的细化 

(1) BackGround类的数据结构与属性设计:

BackGround对象的主要工作是产生水果和虫子,提供蛇移动的环境。

因此它的主要作用是提供带有位置性质的桌面平台。

对这个桌子的数据结构进行分析和设计,采用一张二维表表示桌面。

设计一个方法,将屏幕坐标转化为二维表对应的下标。

二维表设计完成以后,然后设计数组元素中的内容。

桌子上面有水果与毒果,蛇在上面移动,当蛇移动到有水果的地方就会将水果吃掉,以增长身体;移动到有虫子或者碰到墙壁的时候就会违反游戏规则而结束游戏。

这样,在这个桌子里面,不同的位置应该有不同的属性标记。

因此首先定义一个结构体Table,该结构中包含屏幕坐标信息,和属性标记,然后在用Table定义一个结构体数组Table table[20][30],其中该数组下标就是二维表坐标。

因为两个坐标系的坐标是不同的,所以还需要设计一个方法,这个方法应该完成坐标系之间的对应。

 

(2) 水果的安放与清除:

对于BackGround对象来说,水果在桌面上的安放与清除是两个相对比较重要的函数。

但是这两个函数的实现相对简单。

安放函数只需要判断属性标记为空则置属性标记为食物。

清除的时候则判断属性标记为食物,然后置属性标记为空。

食物的显示和背景的刷新在另一个函数中。

 

(3) 背景的刷新:

在背景刷新函数的中,其中难点是墙壁的绘制。

墙是由一个20*20像素的位图拼接而成。

而墙所占的区域明显大于20*20,因此要用该位图对强所在区域进行填充。

重复贴图显然会影响游戏速度并且增加内存开销,在这里本设计采用Windows自带的API函数 PatBlt。

下面对该函数该函数的特性做个介绍:

 BOOL PatBlt ( HDC hdc,   //目标设备环境句柄 

int nXLeft,   //目标设备环境的矩形区域的左上角x坐标 int nYLeft,   //目标设备环境的矩形区域的左上角y坐标 int nWidth,   //目标设备环境的矩形区域宽度值 int nHeight,  

 //目标设备环境的矩形区域高度值 

DWORD dwrop, //光栅操作符 

 所谓光栅操作,其实就是指原位图与目标位图以及图案刷的颜色值进行

 

 

布尔运算的方式,游戏中用到的光栅操作代码是PATCOPY,可以将指定的图案刷复制的目标矩形上。

 

绘制墙 { 

 定义位图资源并载入; 

 创建位图画刷,其中调用墙的位图; 画刷和设备相关联 ; 

把“墙”贴在屏幕上pDC->PatBlt(0,0,715,585,PATCOPY); }

3、功能测试

在测试过程中遇到和多问题,如下:

 

(1) 游戏中蛇刚刚接触墙壁的时候可能不会立即死掉,还能往前面走一步。

才会提示游戏结束。

在程序的调试中,这种随机的错误是最难调试的,因为程序员很难定位错误发生的地点,因为是错误是随机发生的。

这类的错误是在程序运行中出现的。

这也给debug增加了难度。

 

的墙壁。

加快蛇的速度,增加蛇的长度后在进行测试。

经过对多次错误出现情况的分析,发现当游戏速度快的时候这种错误出现次数多,当游戏速度慢的时候出现错误少。

因此断定错误原因出现在定时器函数中,并且在调用游戏结束函数附近。

错误产生原因可能是当游戏结束函数判断为真然后返回一个游戏结束的标记,此时定时器并没有关掉,程序还在执行。

如果定时器时间设置的快的情况下,可能在游戏结束提示信息前,蛇还可以在屏幕上移动一步。

因为时间间隔比较短,所以这种错误不是每次都发生。

找到了错误的原因,在游戏结束函数中设置断点。

这里不在定时器函数中设置断点的原因是,定时器函数是按时间一直运行。

如果设置断点,在每次执行都进入程序内部,无法调试。

最后,在游戏结束函数中添加KillTimer函数,一旦游戏结束,立刻关掉定时器。

问题解决。

 

(2) 双缓冲处理刷新的过程中,不仅不能去掉闪烁,而且也不会刷新屏幕。

所有的位图会在屏幕上重叠。

经过调试发现,所创建的内存位图没有和屏幕dc关联,内存中没有地方绘图。

关联以后贼游戏正常。

 

经过调试程序中所有问题都已经解决。

运行截图如下:

4、总结

贪食蛇游戏的设计,涉及到了图像处理的各种方法,如双缓冲处理闪屏、光栅操作代码、图片透明处理等,面向对象的类设计,游戏算法设计。

通过本次毕业设计我学到了不少新的东西,并且独立的设计了自己的算法,如蛇的移动算法和游戏结束判定算法。

在毕业设计中有很多的收获,这对我以后的工作有很大的帮助。

 

在设计中遇到了很多问题,如图片不能透明显示、类的设计不完善、游戏结束后蛇还可以移动,蛇可以穿越虫子和墙,吃掉的水果不会消失,但是经过耐心的调试,都最终得到了解决。

 

本设计仍然存在一些问题,在方向改变过程中假如蛇的当前方向是向上,如果直接按下方向键下,程序会屏蔽掉消息。

如果按下方向键左或者右,然后迅速按下方向键下,如果时间间隔足够小,蛇头会翻转向下撞在蛇身上,游戏结束。

 

由于这个时间间隔很小,在正常游戏中不会影响游戏的运行和玩家操作,对于游戏的实际影响可以忽略不计,所以不再更正。

这个问题可以通过在定时器中添加大量的判断解决。

六参考文献

[1]  求是科技:

《 Visual C++数字图像处理典型算法及实现[M]》,人民邮电出版社 

[2] 陆宗骐:

《Visual C++.net图像处理编程[M]》清华大学出版社 [3] 朱志刚:

《数字图像处理[M]》电子工业出版社

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2