【功能和性能完善目标】
- 增加敌机的种类,包括其发射的子弹类型、血量和攻击方式等,每个敌机都有随机分配的独特属性,子弹也有不同的性质。
- 动态难度:在用户选择难度的基础上,随着得分的增长难度也不断提高。游戏的难度体现在敌机速度、血量、数量、种类,以及敌方子弹射速和移速等等。
- 增加我方飞机的血量、装甲和护盾,在受不同种类子弹攻击时有不同的反馈。
- 防止玩家的飞机飞出边界、穿过敌机等不合理操作。
- 将敌军的攻击波次分开,每次击毁一定敌机数量后游戏暂停,可以对己方飞船进行简单维修。
- 在控制台的基础上完善UI设计,增加图鉴界面以帮助新手玩家;完善开始、难度选择、暂停、维修、结束等界面间的切换逻辑;在战场下方显示我方飞机的状态面板、总得分和本轮攻击进度条。
- 使用面向对象程序设计改进代码。
【完善思路】
- 创建敌机类,将每一个敌机视作对象的好处是可以赋予其独特的属性,如种类、血量、飞行速度、武器种类、子弹发射速度等。
- 设定敌机种类、子弹种类的枚举,与它们的底层数字对应起来,使用时只需关注它们的名称,使代码具有较高的可读性和维护性能。
- 设定用户选择难度、自动难度以及它们组合出来的总体难度的枚举,创建敌机对象时,它们的血量、飞行速度、发射速度、武器种类等属性要根据难度数值进行调整。自动难度要根据当前得分进行切换。
- 以链表存储敌机对象,以提高在添加/删除敌机时的性能,优化占用的内存空间。
- 创建变量存储当前已摧毁的敌机数量,根据当前难度决定本轮需要摧毁的敌机数量。当摧毁足够多敌机时就暂停游戏,玩家此时可以维修自己的飞船,进而继续作战。
- 使用txt文档配合输出语句构建较为美观和易懂的UI界面。
【工程文件结构】
Enemy类,用于创建和操作敌机对象,包含头文件和源文件
enList类,以链表方式存储和管理已创建的敌机对象,包含头文件和源文件
difficulty头文件及源文件,存储和动态难度相关的函数和变量
gamerunning.cpp,存储游戏一次刷新时需要被更新的函数
utils.cpp,不再存储敌机相关函数,新增了一些操作我方飞机的函数。
define.h,声明全局变量和全局函数
ui.cpp,存储和UI界面有关的函数
main.cpp,主函数。
源代码目录的ui文件夹下存储的txt文件用于快速构建UI界面。
工程名:Plane-Advance
【程序实现的简要过程】
- 对Enemy类的编写
- 使用静态函数add创建敌机,并将构造新对象的所有步骤包装起来,最大程度简化调用时的代码。
- add函数中的setEnemy用于设定敌机的基本属性。应实现传入敌机种类后,在函数中(根据当前游戏难度)在一定范围内随机生成敌机的武器种类、血量、移动速度、子弹射速等属性,并存储在该对象中,返回指向该堆空间的指针。
- add函数中的setLocation用于设定当前敌机的位置,当这个位置有其它敌机或子弹(checkBoth)时,就再随机生成一次,直到生成成功。航空母舰的生成不进行这种判别,而是生成后将它覆盖的敌机对象全部删除。
- createEnemy用于把敌机对象的部件映射到二维数组中,这样就可以在下一次刷新时构建敌机的画面了。
- fire,move,hit,dispatchL/R等函数,用于执行敌机的各种动作。执行这些动作的频率是在对象内部写好的,调用时无需关心。
- 如果敌机在各种原因下可被删除了,则视其为可删除(deleteable)的。这个属性可被外界读取从而在链表中删掉这个对象。在敌机确认是被击毁后调用destroy,删除飞机在二维数组中的对应数字,这样一个敌机的销毁才完成。
- 敌机种类、敌方子弹(武器)种类多种多样,将它们设为不同整型值并设为枚举型,提高编程时的体验~
- 对enList类的编写
- 链表结点的创建、删除和清空是静态函数,在函数中包装构造和析构过程,调用时无需关注内部实现。添加结点采用最简单的头插法,删除函数会自动遍历所有对象,找到deleteable时完成整个析构过程,并自动连接剩余链表。清空则是逐个删除敌机对象和结点。
- 在对各个敌机执行动作时,要获得指向各个敌机对象的指针。用iterate函数实现链表的逐个遍历,用check函数获取敌机对象的指针,然后可以调用不同的函数实现功能。
- 对外开放链表的头指针,作为遍历操作的入口。
- 动态难度的实现
- 两个有关难度的文件负责的是全局难度的控制,以及在敌机类中无法控制的“受难度影响”的部分,同样使用枚举型使编码易读。
- setCurrentDifficulty根据当前分数、玩家选择的难度自动设定难度数值,在游戏运行过程中要频繁调用。
- 有关敌机:getType根据当前难度获取“允许出现的敌机种类”中的一个。getNum控制同屏敌机数量。setEnbFlyingSpeed控制敌方动能子弹移动速度。
- 原有代码部分的改动
- 涉及到敌机操作(增、删、毁、发射子弹、移动)的部分从updateWithoutInput的循环遍历中移除,改为遍历每个对象。
- 在遍历二维数组的环节,由于不同种类子弹的移动方式不同,所以增加了对这些子弹移动的判别;同时也有这些子弹和我方子弹坐标重合后相互穿过的判别(详见代码)。
- 使用从下到上的方式遍历二维数组,好处是不同种类的敌机子弹能够正常移动,而我方子弹会遇到移动多次的问题。由于我方子弹只有一种,只需创建一个数组记录它们所有的坐标,然后在遍历完二维数组后一次性全部移动即可。这种方式相比两次相反方向的遍历提高了一些性能。
- utils中删除了关于敌机的部分。特别地,我方飞机不应该自由地“撞”上敌方飞机。于是,在用户输入-移动我方飞机的部分,增加了对应方向是否存在敌方单位的判别。如果是敌机/航母,则我方飞机不向对应方向移动;如果是子弹,应该扣除船体生命。
- show函数中增加相应判断语句,构建更多样的画面。
- 新机制:波次攻击的实现
- 我方飞机的船体/装甲/护盾属性增加后,如果我方飞机受到攻击而得不到维修,将会很快被摧毁,致使游戏结束。这样,游戏难度将会大幅上升。为了进一步增加游戏可玩性,将敌机的攻击划分为了不同波次,两次攻击波之间可以维修我方飞机。
- 使用两个变量控制本次攻击波的总敌机数和已摧毁的敌机数,总敌机数是受到当前难度控制。添加两次攻击波之间的暂停界面,在该界面中可以选择护盾/装甲/船体中的一项进行修复。
- 每次中场暂停结束后,都重新初始化战场。
- 构建UI界面
- 所有较为复杂的静态页面,都通过读入txt文件实现。
- 进度条,组合使用”=” , ”-”实现,当前进度由当前攻击波已摧毁的的敌机决定。
【游戏设定文稿】
关于敌方飞机/子弹的更多设定,参见游戏当中的“图鉴”。
护盾 --防御-- 能量武器:激光束,损伤整条路径的目标
装甲 --防御-- 动能炮弹:普通的子弹,分为单发、散射和三联发方式
装甲 --防御-- 导弹:可被击落,不仅能损伤飞机,也能损伤基地而减少总分
当相对应的防御值为零,这些武器就对船体生命造成损伤。
【测试效果】
1.打开游戏,自动设定合适的窗口大小。按m键进入图鉴,了解游戏设定。

2.在主界面按Enter进入选择难度的界面,按下对应按键后进入游戏。
(随着难度的增加,同屏飞机数增多,飞机移速加快,敌机子弹射速加快,子弹移速加快,飞机的血量变多,更高难度的飞机种类更早出现。)

右图是简单难度开局情况。战场下方是信息栏,可以动态显示我方飞机目前的状态、总得分和当前攻击波的进度。
下面是选择了不同难度后的开局情况。可以看到敌机的种类变得更加丰富,敌机的数量也变多了。

普通难度 困难难度
3.随着本轮击落的敌机数量增多,进度条随之上涨。

4.多种多样的敌机。
散射式动能战斗机能对我放飞机造成较大威胁。
轰炸机发射的导弹能被击落,如果未被击落,则会对基地造成损伤。
能量战斗机发射的激光束对整条路径上的目标进行攻击。
航空母舰定期派遣随机样式的飞机,且无视场上飞机数量的限制。

5.中场休息:当击退一波攻击后,飞船返回基地检修。
每次可以选择一项防御值进行填充。这里按a键填充了飞船的装甲值。

6.分数增高到一定值,我方子弹会在基地检修后得到升级,以应对越来越多的敌机。敌机的生命值也会变得更高,被击中数次后才会被击落。

补充装甲值 我方子弹升级
7.暂停功能与简单版本保持相同。选择退出后能显示最终得分。

我方子弹再次升级 暂停
8.退出到主界面后,可以重新开始一局游戏。

【代码】
直接打开Visual Studio工程即可调试代码。
文章详细描述了一个飞机射击游戏的完善过程,包括增加敌机种类和动态难度调整,使用面向对象编程优化代码结构,设计敌机类和链表管理,实现动态难度、波次攻击和UI界面改进,以及游戏测试效果。同时,文章提出了敌机和子弹的属性设定,以及游戏中的防御机制和中场维修功能。
1179

被折叠的 条评论
为什么被折叠?



