基于80x86的导弹打飞机游戏
一、软件背景介绍
1.1 背景知识
飞机射击游戏最早的追溯应该是FC上的简单《小蜜蜂》了吧,那不断变换阵型的蜜蜂们和时不时来个俯冲攻击的蜜蜂,让这款游戏耐玩性十足。随后《小蜜蜂》也诞生了很多衍生产品包括大量的效仿和山寨的游戏,玩法多样化,包括有防御塔的、可以升级飞机的、彩色版本的。不得不说《小蜜蜂》是开创了打飞机游戏的鼻祖之一。
在FC上,沙罗曼蛇、魂斗罗、赤色要塞、绿色兵团并誉为“四强”,风靡整个八十年代,为诸多80前玩家们所津津乐道。在FC上沙罗曼蛇首次采用横版的射击方式,一改以往的竖版射击,也算是开创横版射击的鼻祖游戏。对于初上手的玩家来讲,这个游戏的难度偏大。游戏中玩家控制一架飞机与敌人战斗,通过得取能量箱可改变自己的武器。在游戏设定上是其他同类游戏远远比不上的佳作。
打飞机游戏其实有着很悠久的历史了,从开始的开发到现在的行业蓬勃发展。从最初简单的小程序到现在有的大型游戏设计,可谓是发展的也越来越好、与时俱进。而我们团队也正式此类游戏的爱好者,并愿意用己所学去开发这么一个项目。
此游戏上手也及其简单,仅仅需要控制飞机的移动,若击中目标即可得分。这也是这么多年来它经久不衰的原因了。
1.2 基本功能
游戏的主体部分既然是打飞机,那么飞机是什么呢?飞机就是我们程序中在靠近上方的图样。飞机有两架都由三格组成,它会缓慢的移动。下面是我们的发射器。我们可以操控发射器来使他左右移动。接下来若发射器的子弹打中飞机的一部分,飞机相应的那一格就会消失,然后我们会得分。打中一次得两分。总分记录在左上角。按退出键则游戏结束。
1.3 运行截图
二、核心算法思想
游戏区域主要由五个部分组成,分别是得分,两只飞机,导弹以及导弹射出的子弹构成。此处要注意布局,另外要注意飞机与导弹移动时的边界检测。还有数据的擦除。
游戏开始时要先进入欢迎界面,并提示玩家如何操作导弹来打飞机,进入到游戏界面后,应该有两只飞机在屏幕上方移动,玩家可以操纵屏幕下方的导弹发射子弹,若是击中飞机则会使飞机被击中的那一部分消失,同时分数增加,分数记录在屏幕的左上角。导弹和飞机的移动以及导弹子弹的发射要通过图像的擦出来实现。
由于两只飞机的外形相同,以及飞机和导弹的擦除;两只飞机的移动轨迹相同,所以这些问题都可以之解决一遍,另一只飞机可以看为是第一支飞机的复制体。导弹的擦除与飞机的擦除也可以看为一类问题。
两只飞机以及导弹的外形主要由ASCII码值来确定,同时设定导弹及飞机的字符属性及行偏移以及列偏移。设定两只飞机以及导弹的起始行以及起始列。分数的数值用ASCII码显示,用二进制码来运算。设定游戏的开始界面。利用10号中断,从键盘接收字符,显示刚开始导弹及两个飞机的初始行列坐标以及外观。使用21H号中断的显示输出功能,设置分数的行列坐标,并显示分数。
设置检测按键,此处需要自己来定义导弹的按键功能,这个游戏是将左右键设定为导弹的移动以及将空格键定义为发射子弹,通过擦除图像以及在新的位置显示图像来达到两个飞机以及导弹移动的效果。导弹发射子弹,判断是否射中飞机,若是射中飞机,则得分。显示导弹时,要先保存CPU现场,同时显示行列,设置缓冲区,设置光标,显示CPU现场,一个进程结束后跳转到下一进程,然后恢复缓冲区和CPU现场。擦除时,与画图相差无几的思想,只是将字符属性设置为黑底黑字,以实现擦除效果,
发射子弹时,要通过保存CPU现场,以及循环、清除原来痕迹、重新设置行列坐标。子弹射出会有延迟,要保存CPU现场,设置行长度、子弹飞行距离、两个子弹的距离差,当第一个子弹飞行结束才可发射第二颗子弹,要记录子弹的发射,最后要返回函数的调用处,此时代表子弹的飞行延迟结束。同时飞机的飞行也要有延迟,以保证第一支飞机出现后第二只飞机才可以出,同样,要设置行长度,飞机飞行长度,结束时要返回调用处。
令飞机移动时,要先保存CPU现场,通过擦除原来的飞机以及在新位置画图来实行飞机的移动。飞机移动时,要设置飞机的行列坐标以及飞机指针的缓冲区,同样通过将字符属性设置为黑底黑字来是的飞机的擦出效果实现,记录开始飞机的位置,然后飞机的所有光标均向后移动一位,此时在画出飞机,循环整个过程,记录飞机的位置,可以得出飞机整个的移动过程。
无论飞机的移动以及导弹的移动甚至是导弹子弹的发射都用到了擦除,那么擦除的具体是如何实现的,以飞机为例来说明:先要记录飞机此时的位置,然后显示飞机的缓冲区,记录飞机的行列,移动飞机光标,调用擦除功能(即将字符属性设置为黑底黑字),之后占用缓冲区,记录移动位置,循环,缓冲区向后移动四格,循环擦除直至擦除结束,最后返回调用处。
此游戏中一个重要组成部分就是判断子弹是否击中飞机,集中得分。这个部分首先要记录此时位置,显示列的位置,子弹的列值在飞机的列值范围内时,集中得分。然后要计算现在得分,返回分数。得到分数,跳转程序,计数器归零,存储分数,将分数的二进制码转化为ASCII码,显示分数,弹出分数到屏幕上(此处用到了栈,此处即为出栈)。此处有个需要注意的点,即二进制码转化为ASCII码,需要先找出二进制数,进行码的转换循环,若转换成功,则跳至下一步,循环此过程,结束时返回调用处。
游戏的欢迎界面转换为游戏的游戏界面时,需要进行清屏操作,开始时要先保存CPU现场,然后使用向上滚屏功能,设置滚动行数为零,清窗口,设置左上角和右下角行列号,然后恢复CPU现场,结束清屏。
三、核心算法流程图
游戏开始时先进入显示开始菜单界面,当按下Enter键时进入游戏界面,可以开始游戏,当按Esc时,游戏结束,如图4所示。
此游戏中,一个重要部分即为子弹击中飞机时分数增加,并且分数显示在屏幕上,此流程图显示了分数计算及显示的算法。
四、开发中遇到的问题
4.1 如何让导弹及飞机动起来
解决:因为两只飞机外观相同,其移动轨迹也可以看做大致相同,所以两只飞机的移动可以大体看为一个问题,而导弹的移动由于受到键盘的按键控制,所以其可以看为另一个问题,因此这个问题就可以拆分成了两个小问题,即飞机的移动和导弹的移动。
飞机的移动:首先先要显示出飞机的图形,先要设置出飞机的初始行列坐标,然后通过ASCII码值给定飞机的外观,通过擦除和画图来实现飞机的移动,擦除和画图的思想一样,都是通过设置新的字符属性来完成,只不过擦除是通过设置成黑底黑字的字符属性来实现的,其在新的位置显示图像来达到移动的效果,擦除后设置新的行列,然后循环 ,再次设置新的行列,往复循环,最终达到飞机的移动效果。
导弹的移动:导弹的显示与两只飞机一样,同样是通过ASCII码来进行显示,此处就不再做过多的叙述。而导弹的移动需要受到键盘的按键控制,首先需要先检测是否有按键按下,如果有的话要检测按下什么键,并进行判断,此处设定通过左右方向键来控制导弹的移动,没有的话要循环检测,导弹移动时还要注意其会有边界的问题,要循环检测其是不是到达了边界,抵达了边界则不可再移动。导弹的移动显现也是通过擦除图像和再次画图来实现的,此处和飞机的移动相差无几,也是通过改变行列坐标和设置新的字符属性来完成的,所以不再详细叙述。
4.2 敌方飞机与我方子弹的碰撞时该怎么办?
解决:此游戏的主要部分就是导弹发射子弹击中飞机,然后得分,当导弹的子弹击中飞机时,飞机被击中的那一部分消失,那么又如何实现这个想法呢?
在这个项目中,我是给每一个对象都创建了一个精灵层和Layer层的。方便自己管理所有的对象。所有在检测碰撞的时候。需要进行类与类之间的传值。所有就用到了之前的点击事件。先在敌方飞机的精灵的层里面抛出一个自定义事件。在我方子弹层里面接收。抛出的对象是敌方飞机。所有在我方子弹层中就可以运用传过来的敌方飞机对象。获取敌方飞机的框体。在子弹层也可以获取子弹的框体。然后运用碰撞检测就可以实现碰撞的效果。
4.3 当子弹飞出屏幕怎么办?
解决:子弹击中飞机之后,子弹并不会消失,而会继续向上飞翔,直至飞出屏幕,这是要如何实现导弹子弹的清除呢?
我们的想法是这样:创建schedule,每隔一秒钟在自己飞机的位置创建一个向上直线飞行的子弹,当子弹超出屏幕的时候给子弹进行清除。
先创建一个子弹移动的行为。使得子弹向y轴向上运行一个屏幕的高度。最后再在行为的后面写一个算法。就是移除父类的方法。再在运行行为的地方添加一个顺序执行的apicc.sequence(),使的程序先执行移动效果。当移动到目的位置调用移除父类的方法,给子弹进行移除。
4.4 如何计算并显示分数
解决:当子弹击中飞机之后,分数会增加,那么如何计算并将分数显示到屏幕上呢?我的想法是用二进制码来用于分数的计算,用ASCII码来用于分数的表示,这样要将二进制码转换为ASCII码。
首先要判断子弹是否击中飞机,若是击中,则得分,记录此时位置,显示列位置,如果子弹的列值在飞机的列值范围内,则表示击中,得分,计算现在得分,返回所得的分数,得到分数之后跳转程序,将分数保存,分数的二进制码转化为ASCII码,显示出具体分数,计数器归零,记录分数,显示分数,弹出分数到屏幕上(此处用了栈,此处即为出栈),结束后要返回调用处。
五、心得体会
纸上谈来终觉浅,绝知此事要躬行。从开始得知做项目时的茫然失措,到中途研究问题时的信心渐明,再到最后做出的成就满怀。一路走来,不仅仅是我和我的队友做出了什么,更重要的而是我的心智的成熟以及专业知识技能的提高。在我感觉甚是开心喜悦与有成就感的同时,我也有了更大的自信去再接再厉、刻苦奋发。总的来说,汇编语言是一门历史悠久且值得学习的学科。在学习的过程中,我们从基础的结构了解的学习,再到语言代码的研究,最后是对整个程序的观看或审视,我也收益良多。但是往往对于我来说,把所学的汇编语言的知识与此次游戏程序的开发,也就是说把所学与实践相结合其实是有难度的。这就需要集思广益、深度思考、刻苦钻研,只有这样才能圆满的完成对自己的历练,而此次经历也培养了我的这些精神或者说态度。邓小平同志也曾说:实践是检验真理的唯一标准。通过此次的锻炼,我对这句话更是深有体会。而在此次锻炼的同时,我的各方面能力也得到了提高,我更有兴趣与信心去完成未来更多的项目。
在这次通过汇编语言编写陆地导弹打飞机游戏过程中,通过查阅资料,向老师、同学请教,我收获了知识,同时,还增长了阅历,变得更加成熟。在学习汇编语言的过程中,我深刻地意识到相较于曾经学过的C语言,电脑等于在迁就人的思维方式,但汇编却是接近机器语言的一门语言,我们学习和编写程序时必须要去迁就电脑的思维方式,有时候还要设身处地地用电脑的角度去思考问题。在编程序的过程中,我也深刻认识到知道运行过程是一回事,根据这个过程编写出这段程序又是另外一回事,要编写出这段程序首先要对汇编语言熟悉,对编译环境熟悉,在编写过程中,最苦恼的就是:知道每条指令什么意思是一回事,如何把这堆指令整合成自己得到的程序又是另外一回事。这个过程需要我们去慢慢调试自己程序,完善自己的逻辑思想。在编写过程中我加深了对8086汇编语言的理解,学习一门语言必须经常使用,否则不能很好的体会其中的奥义。在不断探索过程中我也知道了自身的不足。