目 录
链接: https://pan.baidu.com/s/12mi6UmHFvIoUnuDysFWGpA 提取码: 3hk4 复制这段内容后打开百度网盘手机App,操作更方便哦
1. 概述
1.1简介
本次实训项目是做一个飞机大战游戏。
该飞机大战项目主要使用的是c++语言和MFC框架编程,运用MFC中的类和函数以及自己创建的类和函数,设计好各个类之间的继承关系,实现飞机大战游戏的简单功能。
1.2基本功能
1.通过键盘的方向键和WASD键可控制战机的位置移动
2.空格键和鼠标左键发射子弹。
3.A键进入无敌模式
4.Z键暂停,S键取消暂停
5.发射的子弹可自动运行,遇到敌机,敌机死亡,产生爆炸,子弹消失,得分增加
6.敌机在窗口上下方随机生成,并自行上下移动
7.敌机随机发射子弹,子弹自行移动,敌机子弹遇到战机消失,战机生命值减小
8.设置5个关卡,随着关卡数增多,难度逐渐增大,敌机数量和子弹速度增加
9.对于产生的敌机和敌机子弹,若超过窗口区域,则释放对应对象内存
10.窗口左上方显示游戏当前信息,包括当前得分、当前关卡、生命值以及boss生命值
11.添加背景图片
1.3附加功能
1.从第4关开始,可以使用ctrl键发射3排子弹,从第5关开始,可以使用shift键发射5排子弹
2.窗口左上方显示游戏当前信息时,通过条带可视化显示当前生命值,得分
3.添加爆炸声音和背景音乐
4.可以通过窗口菜单栏设置难度(跳过关卡)
5.可以通过窗口菜单栏查看游戏说明和重新开始
6.从第3关开始敌机开始发射追踪弹
7.从第4关开始战机可以使用X键发射追踪弹
2. 相关技术
2.1 Windows定时器技术
由于敌机和敌机的子弹、boss等是随机出现的,所以在new这些对象时要设置定时器,每隔xxxms执行一次创建或刷新函数。
Windows定时器是一种输入设备,它周期性地在每经过一个指定的时间间隔后就通知应用程序一次。程序将时间间隔告诉Windows,然后Windows给程序发送周期性发生的WM_TIMER消息以表示时间到了。本程序中使用多个定时器,分别控制不同的功能。
在MFC的API函数中使用SetTimer()函数设置定时器,设置系统间隔时间,在OnTimer()函数中实现响应定时器的程序。在程序结束时调用OnDestory()函数用KillTimer()函数删除定时器。
(介绍)(技术一的名称)【二级标题,楷体,小四,加粗,顶头】
2.2CObList链表
MFC类库中提供了丰富的CObList类的成员函数,此程序用到的几个重要的成员函数如下:
(1) GetHead(),访问链表首部,返回列表中的首元素(列表不能为空)。
(2) AddTail(),在列表尾增加一个元素或另一个列表的所有元素。
(3) RemoveAll(),删除列表中所有的元素。
(4) GetNext(),返回列表中尾元素的位置,并将Pos设置为列表下一个入口的POS值。
(5) GetHeadPosition(),返回列表中首元素的位置。
(6) RemoveAt(),从列表中删除指定位置的元素。
(7) GetCount(),返回列表中的元素数。
2.3获取矩形区域和判断是否相交
在产生爆炸效果时,需要获取两个对象所在位置的矩形区域,然后判断两个矩形区域是否相交,相交则产生爆炸,否则不产生爆炸。
首先,使用CRect定义一个对象,然后使用类的成员函数GetRect()函数,获取对象所在位置的矩形区域。然后使用IntersectRect(&,&))函数来判断两个矩形是否有重合的部分。如果有不为空,则返回非零值;否则,返回0。
2.4按键消息处理
在这个程序中,需要根据键盘按键的按下决定游戏中各种位置的改变和一些变量的内容。
利用战机发射子弹或者进行移动时,需要按下键盘的空格键或者方向WASD键等,如果利用MFC中提供的默认消息处理函数进行按键消息的处理,处理频率会很快,导致子弹发射频率过快,子弹出现重叠,战机移动过快等问题,所以应将按键消息处理放在OnTimer函数中,利用GetKeyState函数,每隔xxxms处理一次按键消息,以达到平滑的移动和发射子弹效果。
2.5弹出对话框函数
AfxMessageBox函数,可以在屏幕上显示一个对话框,可以展示给用户一些信息,用户也可以通过选择YES或者NO,进行一些功能的选择,比如选择进入下一关,查看说明,是否重新开始等
2.6真实DC定时重绘
Invalidate函数,通过在OnTimer函数中定时调用Invalidate函数,使窗口无效。
,让Windows知道这个窗口应重新绘制,由此调用OnDraw函数,实现真实DC的重绘。
2.7 CDC的透明贴图
在项目中需要将很多的bmp位图贴到DC上,结合逻辑处理完成对整个游戏的设计,为了实现更好的显示效果,使移动元素所用的图像更加贴合背景,则需要利用透明贴图技术,将bmp图像中的无关颜色做透明处理。
实现方式为调用CDC中的TransparentBlt函数,将源DC的位图资源拷贝到目标DC,并且利用函数的最后一个参数填写RGB(0,0,0)(黑色)信息,实现对对应颜色的透明处理。
2.8CDC的双缓冲技术
在最终的OnDraw函数和在OnTimer函数中调用的敌机战机boss等的draw函数中都应用了双缓冲技术。利用普通的绘制函数对项目中DC进行绘图时,由于绘图时机不一定连续,绘图效率不一定统一,会造成重影和闪屏的不良效果。
为了解决这一问题,可以利用双缓冲技术,先将绘制的每部分内容存储到内存中的一个虚拟绘图设备DC中,当所有部分的内容都绘制完毕后,在一次性的将虚拟绘图设备DC中的内容拷贝到屏幕DC上。
在程序定义一个虚拟绘图设备DC的CDC指针变量实现,在构造函数中为指针分配内存空间,在虚拟绘图设备DC中将所有的图像绘制完毕后,再利用OnDraw函数取得真实窗口CDC指针,在其中通过Bltblt函数将虚拟绘图设备DC中的内容完整的拷贝到真实屏幕上。
2.9CDC的字符串,血量条等条带输出技术
在OnDraw函数中,需要在主窗口的左上角输出当前的游戏信息,包括当前得分、当前关卡、生命值以及boss生命值。
通过创建一个CString对象,另创建wchar_t字符串,先将需要输出的字符串通过wsprintf输出到wchar_t缓冲区,在通过SetString将其选入CString。
然后调用CDC的TextOut函数,将 CString显示在虚拟绘图设备DC中。
条带的输出是通过CDC的Rectangle函数。
2.10通过窗口菜单栏设置难度(跳关)、查看游戏说明和重新开始
通过在CWinApp中的ID,IDR_MAINFRAME,编辑该菜单栏,在viewcpp文件中设置command消息,并写出相应的消息处理函数。
其中用到DDX_Text函数处理CDialog对话框中输入的难度数字,进行数据交换。
2.11背景音乐播放
通过在OnInitialUpdate函数中调用mciSendString,达到播放背景音乐的效果
3. 总体设计与详细设计
3.1 系统模块划分
定义的类:
Cball:敌机子弹类
CBomb:战机子弹类
Cboss:boss类
Cenemy:敌机类
CPlane:战机类
CPlaneObject:基类
explosion:爆炸类
Clevles:设置难度用的对话框处理类
CPlaneGameApp:进入mfc程序的类
CPlaneGameDoc:定义链表的类
CPlaneGameView:主要视图,图像输出功能实现的类
3.2 主要功能模块
3.2.1敌机和子弹的移动
敌机从上方和下方两个不同的方向随机出现,然后移动和发射子弹。
首先,在OnTimer()创建一个敌机链表,new出两个不同方向的敌机,并将敌机添加到敌机链表中,再在OnDraw()函数中遍历的将敌机draw出来,再在OnTimer()函数中调用敌机对象中的move函数,使得敌机在游戏界面上移动起来Doc。子弹的设计与敌机相似,但是必须在遍历敌机队列使其移动时,得到一个敌机对象后,就创建一个子弹对象,并将其初始位置设置为敌机的当前位置,然后将其添加到子弹队列中,再在OnDraw()函数中遍历的将子弹draw出来,再在OnTimer()函数中调用子弹对象中的move函数,使得子弹在游戏界面上移动起来。
3.2.2追踪弹
追踪弹既有战机按X键追踪敌机的追踪弹,也有敌机和boss追踪战机的追踪弹,在设计战机追中敌机的追踪弹时。设计这个追踪弹的主要思路是,在子弹move时,不再是直上直下的飞,而是将当前你要追踪的位置作为参数传给move,move函数计算你的位置和要追踪的位置的x轴y轴正负偏向,沿着这个正负偏向移动子弹,子弹就实现了追踪的功能。
3.2.3发射三排和五排子弹
战机和boss也可以发射三列和五列的散弹,分别朝着三个和五个不同的方向发射子弹,在子弹参数中加了一个type参数,通过重写子弹的构造函数,在OnTimer函数中响应定时器时,向链表中添加子弹,此时向构造函数中传了一个参数type,如果type是单数则向左偏,type是双数则向右偏,type等于0则沿竖直方向发射,在偏转时向左和右方向偏转的速度与type有关,因此产生了分散发射的效果。
4. 编码实现
5. 实训中遇到的主要问题及解决方法
5.1. 主要问题及解决方法
(1)遇到了很多mfc类和函数的功能不清楚,查找起来比较麻烦,在查找过程中,在多个途径中进行搜索,像pdf书,百度,csdn等途径,有时候找到的东西不是很系统,看起来很费力。
(2)对mfc的运行体系不是很清楚,一开始找不到如何将rc文件中的资源在cpp文件中使用,后来发现的对应的ID。
(3)对于背景音乐,刚开始使用的PlaySound可以简单的实现音频的输出,但是该函数只支持单个音轨的播放,不支持背景音乐和爆炸音效的同时播放,后来经过查找搜索,找到了使用mciSendString进行背景音乐的播放,而使用原来的PlaySound播放爆炸音效,达到了背景音乐和操作音效的同时播放的目的。
5.2.调试过程中出现的错误
修改过程中经常遇到这个地方修改了以后,要修改其它很多的地方,来适应这个变化的情况。
比如在OnTimer函数中的生成敌机时,修改敌机出现位置时,move函数,draw函数都要改。
修改定时器的按键响应的设置时间,设置时间一开始过快,导致飞机移动和子弹反射太快和重叠。
在写代码时类之间的关系设置的比较乱,有时候要思考自己需要的功能要在哪个类里面修改和添加。
(详细记录调试过程中出现的错误,记录该错误的原因,记录查找问题和解决问题的过程并进行总结和分析,这项非常重要,以列表形似列出作为考核的关键因素)
6. 实训体会
在这次C++的实训中,了解了MFC的一些类库和函数,以及mfc消息传递机制,了解了如何在屏幕中绘制需要向用户展示的图形信息,也了解了Windows的屏幕定时刷新的机制,对VS的使用的熟悉程度也进行了提高,使我的编程能力有了很大的提高,同时提高了自学能力,熟悉了在遇到一个不懂的知识后,通过哪些途径搜索能够快速找到所需的知识解释的能力。
刚开始时遇到了很多mfc类和函数的功能不清楚,对于VS的rc文件处理机制也不是很清苦,查找起来比较麻烦,在查找资料的过程中走了许多弯路,在查找过程中,在多个途径中进行搜索,像pdf书,百度,csdn,msdn等途径,有时候找到的东西不是很系统,看起来很费力。
通过这次的实训,我了解到课堂上的c++知识只是属于基础的部分,想要熟练的运用框架类库进行编程,实现一些复杂的功能,还有许多东西要学,在项目进行过程中,进一步理解和运用结构化程设计的思想和方法。初步掌握了开发系统应用程序的基本方法和步骤。