坦克大战设计报告Word下载.docx
- 文档编号:17629338
- 上传时间:2022-12-07
- 格式:DOCX
- 页数:22
- 大小:306.23KB
坦克大战设计报告Word下载.docx
《坦克大战设计报告Word下载.docx》由会员分享,可在线阅读,更多相关《坦克大战设计报告Word下载.docx(22页珍藏版)》请在冰豆网上搜索。
4.6子弹的运行和控制19
4.7记分系统21
5.测试与实现22
6程序的总结和展望23
1绪论
1.1开发背景
在信息社会中,手机及其他无线设备越来越多的走进普通百姓的工作和生活,随着信息网络化的不断进展,手机及其他无线设备上网络势在必行。
但是传统手机存在以下弊端:
1.传统手机出厂时均由硬件厂商固化程序,程序不能增加、删除,有了错误也不能更新、修改,若要增加新功能必须另换一部手机。
2.传统手机访问互联网是通过WAP(WirelessApplicationProtocal),所有网络资源必须接通网络才能在线访问,非常耗时、费用亦很高。
而Java技术在无线应用方面的优势非常明显:
1.应用程序可按需下载,而不是购买由硬件商提供的套件,可升级空间大。
2.Java技术提供了一个类库,它使的应用开发商可以创建更为直觉、丰富的用户界面(GUI);
3.Java技术使网络带宽的应用更为有效,因为应用程序可以下载到器件上,并在本地运行,仅仅是在连接到服务器时才会占用网络带宽。
基于以上分析,Java手机将是未来手机的发展方向,是业界的热点。
1.2开发工具
操作系统:
MicrosoftWindowsXP
程序语言:
Java2
开发包:
Java(TM)2StandardEdition(build1.4.1_02-b06)SunMicro.J2MEWirelessToolKit2.1
IDE:
Borlandeclipse
1.3开发意义
虽然Java已经被用到许多企业级软体上,可是其实骨子里面还是非常适合用在嵌入式系统之中。
Java平台演进到Java2后,Java平台分别针对不同领域的需求被分成四个版本,亦即J2EE、J2SE、J2ME以及JavaCard(其结构示意图见图1.1)。
其中J2ME定位在消费性电子产品的应用上。
这个版本针对资源有限的电子消费产品的需求精简核心类库,并提供了模块化的架构让不同类型产品能够随时增加支持的能力。
这个版本的应用层面相当广泛,会是未来Java平台发展的重点项目。
J2ME在设计其规格的时候,遵循着“对各种不同的装置而造出一个单一的开发系统是没有意义的事”这个基本原则。
于是J2ME先将所有的嵌入式装置大体上区分为两种:
一种是运算功能有限、电力供应也有限的嵌入式装置(比方说PDA、手机);
另外一种则是运算能力相对较佳、在电力供应上相对比较充足的嵌入式装置(比方说冷气机、电冰箱、电视机上盒(set-topbox))。
因为这两种型态的嵌入式装置,所以Java引入了一个叫做Configuration的概念,把上述运算功能有限、电力有限的嵌入式装置定义在ConnectedLimitedDeviceConfiguration(CLDC)规格之中;
而另外一种装置则规范为ConnectedDeviceConfiguration(CDC)规格。
也就是说,J2ME先把所有的嵌入式装置利用Configuration的概念区隔成两种抽象的型态。
J2ME平台被认为是最杰出的手机游戏平台,它为开发者、设备制造商、网络通信公司和消费者广泛接受。
它有一些非常重要的特征对所有组织都有益。
因为J2ME应用在不同设备上都是便携式的,他们常常可在网络上下载和执行。
如果没有正确的防范,它则为用户和无线通信公司冒着无数个安全的风险。
幸运的是,Java被设计成一种安全的语言。
所有字节码应用在执行之前都要校验;
JVM在执行过程中监督应用的安全性和存储违反问题。
MIDPv2运行时间包括一个完全特征化的、基于域的安全管理员,它在应用的数字签名者鉴别的基础上赋予应用API级许可。
手机游戏的盈利主要是由于它们的涉及面很广。
手机已经与现代生活方式紧紧地结合在一起。
他们是最普遍携带的个人用品中仅次于钥匙和钱包的东西。
传统的台式机游戏将目标锁定在低级趣味的人和青少年身上,而手机游戏则每个人都可以访问的到——随时,随地。
尽管每个手机游戏都不贵,但是巨大的使用量(如:
每人每星期一个新游戏)将使得这个市场商机无限。
但是,对于开发者来说,将控制台游戏迁移到手机游戏工程很大。
因为他们所面向的对象、生活方式和分布式模型都有着极大的区别。
一个成功的手机游戏大多具有以下特征:
·
易于学习:
既然手机游戏面向的是普通消费者而不是计算机专家,那么他们不可能深入的学习游戏技巧。
消费者不会花几个小时去研究一个3元的手动操作的游戏。
保持游戏的简单是最基本的要求。
可中断性:
多任务处理是手机生活方式的基本特征。
手机用户常常在任务(如等一个电子邮件或者等车)之间有一小段时间。
而游戏、日历管理、通讯和工作数据访问使用的是同一个设备。
所以一个好的手机游戏应该提供短时间的娱乐功能,并且允许用户在游戏和工作模式之间顺利切换。
基于订阅:
手机游戏的盈利成功取决于他们巨大的使用量。
一开始开发和设计每个游戏都是昂贵的。
如果一个手机游戏开发者要赢利的话,重要的是:
同一个游戏引擎,多个标题,基本的故事情节类似。
基于订阅的游戏是不断产生收入的最好方法。
丰富的社会交互:
不管一个游戏设计得多好,只要玩家找到了它的根本模式或者玩完了所有的游戏路径很快就会厌烦这个游戏。
对于一个基于订阅的游戏,重要的是与别的玩家合作以增强所玩游戏的智力和随机性。
在今天纷繁复杂的多玩家游戏中具有丰富社会交互的游戏证明是成功的。
利用手机技术的优点:
巨额的手机技术研发费用都花在提高设备和网络的可用性和可靠性上面。
因此,手机设备硬件和网络协议与桌面/控制台世界(如全球定位系统(GPS)扩展、条形码扫描仪、和短消息服务(SMS)/多媒体信息服务(MMS)通讯)有着非常大的差别。
好的手机游戏应该利用那些更新的设备特征和网络基础设备的优点。
无违法内容:
既然所有年龄/性别的人群都玩手机游戏并且常常在公共/工作场合,就应该避免明显的暴力或者色情内容。
2需求分析
J2ME非常适合开发手机上的应用程序,尤其是手机游戏开发。
手机坦克大战游戏就是个非常有趣的手机应用。
涉及到动画显示、按键检测、数据读写、Sprite、图层管理、多线程和双缓冲等多项J2ME关键技术,充分发挥了J2ME用于嵌入式开发的大部分功能和特性,并引入了人工智能控制。
2.1功能需求分析
游戏支持2名玩家同时进行战斗,并附加有任务编辑器,可以任意创建关卡。
每关需要在复杂的地形上摧毁20辆敌人坦克车辆才能通过,如果玩家的坦克被摧毁多次或己方基地被毁即算任务失败。
游戏中可以获取有多种功能的宝物,敌人种类则包括装甲车、轻型坦克、反坦克炮、重型坦克4种,且存在炮弹互相抵消和友军火力误伤的设定。
2.2界面需求分析
游戏中为了美观,适用性强,可能需要采用外部文件引入的图片贴图。
坦克大战(BattleCity)地形包括砖墙、海水、钢板、森林、地板5种。
游戏的结束、开始、动态信息画面作为构成一个完美程序都是必不可少的重要部分。
良好的用户界面更是吸引用户的硬指标,相关的美术构图也需要有一定的考虑。
3总体设计
3.1主要功能
GameCanvas中提供了与以往MIDP1.0不同的键盘采样功能。
Canvas类中采取响应键盘事件的方法,每次执行周期时会读取keyPressed函数中需执行的代码。
这样的机制并不适合某些游戏场合。
在某些不支持keyRepeat功能的设备上,反复执行的按键,比如发射子弹,将不能因为长时间按压而自动重复,这样就需要用户高频率的手动击键,这在操纵空间非常有限的移动设备上是非常困难的。
同时,事件的执行周期也并不一定适合游戏的场合,也许需要更高频率执行的按键却只能在指定的周期内规律的响应。
对此,针对游戏的开发,Game包提供的键盘状态功能将显得十分有效。
GameCanvas提供getKeyStates函数可获取当前键盘上的信息。
将以位的形式返回键盘上所有键的按与释放的状态,当bit为1时,键就是被按下的状态,为0时则为释放状态。
只需要此一个函数的返回值就可以返回所有键的状态。
这保证了快速的按键和释放也会被循环所捕捉。
同时,这样的机制也可检测到几个键同时按下的状态,从而提供斜向运行等相应功能。
敌方按照规则不能和用户坦克重合,则它每行走一步就需要把用户坦克扫描一次,判断其是否碰撞到了用户的坦克。
Sprite类中提供了collidesWith函数,用于判断是否与某个TiledLayer、Sprite、Image的对象有图象上的重合(即游戏中的碰撞)。
然而不能仅仅将用户坦克作为其Sprite参数传递给敌人的类进行判断。
因为如果发生碰撞,collidesWith成立,则两辆坦克已经发生了图象重合,违反了规则,甚至若再进行collidesWith判断的话,其结果将永为真。
为了提前预知碰撞,可以将所有坦克的碰撞范围设定为一个比坦克图片稍大一些的矩形,此矩形仅在坦克前方比坦克图形多出一个象素。
在多出的11个象素中,按照每个象素依次检查此象素是否于外界发生碰撞,如果不是按照象素检查,则当坦克与障碍物错位并同时与两种物体接触时将有可能忽略检测其中的一样物体。
这样,就可以提前一步判断。
如果发生碰撞,则坦克应当选择掉转方向,此时,两辆碰撞的坦克又因为其矩形区域不重合而不符合collidesWith的条件,就可以继续正常运行了。
敌方坦克由于需要具有一定的智能性,以便对玩家攻击,使之具有一定的可玩性。
敌人可以自动行走,但是应当在以下适当的情况下转向:
首先是是否超出界面的边界,其次是是否与地图障碍物发生了碰撞,再次是是否与用户坦克发生了碰撞。
需要指出的是,当发生阻碍不能在不变方向的情况下继续行走时,并不一定立即需要采取转向的对策。
如果一定发生转向,试想,当敌方碰到玩家时,如果它立即转向,将不会对玩家发射射向他的子弹,就不构成任何威胁,当然,也不能永远不转向。
本程序设置为:
当碰撞到障碍物或边界时立即转向,但碰到玩家坦克时需要有一个等待的时间,这个时间由碰撞前随机取得的在某方向上的持续行走步数决定,当发生坦克间碰撞时,此随机数将在下一次循环前减少为原来的2/3,这样就实现了加快转向的时间,避免死锁在一个方向上静止的停留过长的时间。
另外,坦克的发炮间隔和转后的具体方向都由随机数决定。
坦克之间由以上道理也不会发生重叠,但当某坦克正从上方生成而正巧有另一辆阻碍在其生成点处,这将导致不可避免的重合。
这是允许的,但需要对他们标注状态,即当坦克刚出现时暂时允许重合,一旦在某个时间他们脱离了重合状态,就不能在允许重合,如果不设置这样的判断,刚出现的坦克将会因为受到阻塞而永远不能前进,坦克将混成一团。
本程序中并未使用过多复杂的人工智能算法,如有时间,将可能再此方面加以完善。
3.2程序流程
本程序采用面向对象的设计模式,对游戏中的所有物体赋予对象的概念和属
性。
用户控制的坦克运行在主线程中,随屏幕刷新的频率而步进。
敌方坦克将在游戏开始时逐渐新增线程,每增加一个敌方对象就新增加一条线程,一旦线程数满到最大值(本程序暂设置为6),就不允许敌人再继续出现。
用户坦克自诞生之时起将拥有一发子弹,子弹虽然开在单独的线程中,但运行结束后(比如撞到相关物体或敌方坦克时)并不结束子弹对象,只是将其线程终止。
用户再次发射子弹时只是将终止的线程再次激活。
在屏幕重绘的主程序中,将在每次的循环中判断若干事件。
如:
用户坦克的生命是否已完全用尽,敌方坦克数是否已经为零,屏幕上的坦克数量是否少于仍剩下的坦克数量等。
以便程序进入相关的分支执行相关的反应代码,结束游戏或统计分数等。
主程序流程如图3.2所示:
程序为需要完成独立功能的需显示的模块设置了单独的类。
TankMain类是继承自MIDlet的控制主程序启动的首先被载入系统的部分。
载入程序后首先启动的是程序介绍的信息画面。
闪过后载入StartChoice类,为用户提供可选择的选项。
在选择开始后,将运行BattleCanvas类中的总流程控制。
它决定了游戏何时该结束,何时分配敌人数量,GameOver字样的闪现规则,地图的绘制及整个游戏的调度。
4详细设计和具体实现
4.1游戏进入前的选择
每个MIDlet程序都必须有一个主类,该类必须继承自MIDlet。
它控制着整个程序的运行,并且可以通过相应函数从程序描述文件中获取相关的信息。
该类中拥有可以管理程序的创建、开始、暂停(手机中很可能有正在运行程序却突然来电的情况,这时应进入暂停状态。
结束的函数。
进入时,首先载入画面的不是游戏运行状态,而是提供选项,当再次选择StartGame时才正式运行。
运行画面如图4.1所示。
因此,在TankMain的构造函数中分配了StartChoice类,即选项画面的内存空间。
在startApp()函数中,随即调用了Displable的setCurrent()函数将当前屏幕设置为startChoice。
startChoice继承了接口commandListener,这样,就可以使用高级界面的Command按钮。
继承了commandListener的类必须拥有commandAction(),以决定对按键采取什么样的行为。
即按钮事件触发后需执行的函数。
在设置好commandlistener后,需要调用setCommandListener()以将按钮事件激活。
键盘事件中,可用getCommandType()返回的Command类型来确定选择的是什么按钮。
startChoice继承了List类,用于显示列表选项,使用其append()函数可将选项加入到列表中。
getSelectIndex()可检测到选择的项目的序号,序号从0开始递增。
其中,当选择第一项时将载入正式游戏画面BattleCanvas类,第二项将显示帮助信息(效果如图4.2),第三项则是重新显示与作品和作者相关的logo画面。
4.2主游戏逻辑及其涉及到的若干类
BattleCanvas主管着所有类之间的协调,决定何时死亡,何时分配新的敌人,及控制敌人出现处的闪光图标、游戏结束后的动态Gameover字样。
它运行在独立的线程中,以恒定的频率刷新画面。
刷新速度需大于30/秒才能使画面显示因人眼的暂时停留效应流畅运行。
本程序设置为20毫秒。
其主逻辑如图4-4所示。
程序中建立了另外的两个类,分别表述了敌人坦克和玩家坦克的功能。
它们分别为:
EnemySprite和UserSprite。
这两个类均在BattleCanvas中建立了对象,以便进行统一调度。
BattleCanvas包括了LayerManager,这样所有静态和动态的图象都不需要手动刷新,只需要在LayerManager中加入所有的需控制的元素,再统一由LayerManager刷新即可。
因此,有必要在其中创立一个LayerManager的对象。
其他,如Sprite类的gameover字样、记分统计画面也都需在此主逻辑中建立相应对象。
还需保存的变量有,游戏开始时间、结束时间(用于统计分数)、敌人的总数、屏幕上敌人的数量、下一个敌人需要出现的位置(总共允许在三个不同的位置出现,分别位于屏幕的左、中、右方)、游戏是否已成功结束或是否已死亡。
构造函数中,需初始化地图。
地图实际即为TiledLayer的一个对象,可调用setCell设置其具体的图象格内容。
地图由外部文件读入。
外部文件分别命名为level*.png,利用MIDP中唯一获取外部文件为程序内资源的getResourceAsStream()函数将地图文件读入程序。
在创建了InputStream类的map对象后,使用read()函数可将流中的下一个字节读出,并返回此字节代表的整数。
每个整数代表一种障碍物。
用二维循环将读出的每个整数,通过setCell()将整幅地图画出即可。
地图文件可用十六进制的文本编辑器生成,如本程序使用的Ultraedit。
绘出地图后,可用LayerManager的append()将地图放置在第一层。
这是很有必要的。
因为地图上的障碍物之一——草,在坦克运行中时是必须处于坦克的上层的,否则将失去真实性。
为此,地图必须首先载入。
由于敌人将依次出现在屏幕上,同时出现的数量应当受到控制。
本程序设置为6。
所以在构造函数中,也应当分配6个EnemySprite对象的内存空间。
构造坦克时,将把坦克的png图片作为参数传递给EnemySprite和UserSprite,BattleCanvas中创建坦克仅调用createEnemy()和createUser()实现。
在构造函数自己调用了线程的start后,程序将开始循环运行,直至跳出while的循环。
每次循环中将检测是否死亡,屏幕上坦克的数量,是否该过关统计分数,检测用户输入的按键、重绘整个屏幕及回收垃圾内存(GarbageCollection)。
当敌人坦克完全死亡时(enemyNum为0),需调用System类的currentTimeMillis()赋值给结果的时间。
接着调用setCurrent()显示统计分数的画面,为了进入下一关,统计画面只是停留四秒,就重新转回BattleCanvas画面。
当然,如果当前已是最后一关,就不会再转回。
进入下一关时,许多变量需要重新被初始化,如地图的绘制、敌人出现位置的重置、敌人的数量、玩家坦克的当前位置。
如果游戏未结束,则需判断屏上坦克是否已小于还剩坦克的总数,如果是这样,就需要再提供一辆坦克。
提供新坦克之前,在屏幕上设置了一个专用指示的闪光符号,它继承了Sprite,运行在单独的线程中。
以在两秒钟内反复闪现两次为一个生命周期。
当它闪光完毕后,敌人就会从闪光位置出现。
这样可提示玩家具体敌人将在什么时刻出现,以便做好准备。
闪光位置设置了三处坐标,由于敌人不能同时出现,便设置了enemyOutDelay的倒数计时,每次屏幕刷新会减少一次计数,直到为0时就准备一辆坦克。
本程序设置的两次坦克出现的最小间隔为2秒。
如果玩家已经死亡,就需要使用LayerManager的insert()将gameover字样的图片覆盖到最上层,效果如图4.3所示。
在检测用户输入的input()函数中,当按方向键时,玩家坦克就将向不同的方向运行,这调用了UserSprite的go()函数;
当开炮时,就调用其fire()函数,作出相应的行为。
在出现正式画面前设置了一个loadingstate*字样的单独屏幕,调用了loadinglevel()函数,并停滞了1500毫秒,提示用户做好准备。
效果如图4.4所示。
在绘图的render()过程中,除了要重绘坦克、地图、子弹外,还会在右边空白处绘出一个生命统计栏。
并反复使用Graphics的drawLine()、drawImage()绘画出一个三维的效果,增强视觉感。
该三维栏的上方为白色,下方为黑色,就创造了立体感。
在每次刷新绘图页面时,应使用GameCanvas的flushGraphics()将屏幕后台的缓冲区内的图象刷新到前台来。
在允许敌人出现前,需要检测给即将出现的敌人分配一个数组序号。
在程序中调用了getNullEnemyIndex()进行测试,当返回为-1时说明没有序号可以分配,否则,将返回空的序号。
游戏的最终运行状态如图4.5所示。
4.3坦克的共同行为
在TankSprite中定义了所有坦克(包括敌方坦克和玩家坦克)的共同行为和属性。
EnemeySprite和UserSprite都继承了该类以简化结构。
在transformDirection[]中定义了坦克四个方向分别应将原始图片旋转的角度,分别为TRANS_NONE,TRANS_ROT90,TRANS_ROT180,TRANS_ROT270,以便在后来的setTransform()中将这些常量代入。
构造函数中创建了每个坦克必须拥有的一颗子弹,这些子弹就将只跟随自己的坦克调动。
相关代码:
privatestaticinttransformDirection[]=
{
TRANS_NONE,TRANS_ROT90,TRANS_ROT180,TRANS_ROT270
};
privateintcurrentDirection=0;
//ifnodirectiondefined,itwill
//staywhereitis.
publicBulletSprite(Imageimage)throwsIOException{
super(image);
defineReferencePixel(1,3);
//centerandbottomofthebullet
}
为了能提前预测碰撞,调用了defineCollisionRectangle(0,-1,11,12)将碰撞矩形向前设置了一个象素,具体原理见第二章。
在setBulletDirection()中,将根据坦克当前的方向确定子弹出膛后的方向,其中setRefPixelPosition()将子弹的参考点设置在其未变形状态的底部,setXY()将其放置到炮口的位置,setTransform()将其图片方向转到需要使用的位置。
canPass()函数将返回坦克是否能够向前前进,考虑到的因素有边界、障碍物。
它返回一个boolean值,提供给go()函数,做进一步的判断。
getTileIndex()将检测传递来的象素处是什么类型的障碍物,它将象素除以8(即障碍物的象素宽度),取整,再通过getCell()得到。
在得到障碍物属性后,判断其序号是否与草相同,或是否为空(序号为0)。
因为所有的障碍物中只有草不会阻碍坦克的向前运行。
4.4玩家坦克的功能属性
构造函数中需要将坦克方向设置为向上,因为刚出现时就是这样的状态。
当开炮时,调用BulletSprite的setLayerManager()将子弹与layerManager联系起来。
需要联系的还有自身坦克、地图。
这些都由坦克传递给子弹。
因为子弹是属于坦克的,它的属性需要跟当前的坦克保持一致。
接着使用append()将子弹贴到layerManager上显示出来。
最终调用其start()开始子弹自己的线程。
子弹一旦开始运行,就脱离了当前坦克的控制,直到其生命周期终止。
无论子弹是属于敌人还是玩家的,它都必须记录自己的来源和攻击的对象。
在玩家坦克发射的子弹中,就必须将攻击对象设置为所有的敌人。
这样,它才能有扫描的目标。
在setShootCheck()的参数中,传给子弹的是敌人的数
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 坦克 大战 设计 报告