基于J2ME的Java游戏--坦克大战的开发毕业设计论文 联系客服

发布时间 : 星期四 文章基于J2ME的Java游戏--坦克大战的开发毕业设计论文更新完毕开始阅读de8e9b6a561252d380eb6e62

3.10 本章小结:

第三章中介绍了程序的流程、相关技术的思想及其在本程序中的应用。分别对绘图、数据库、游戏基本算法等做了详细叙述。具体算法的代码实现和详

图3-4 内存监视器

细流程将在下章介绍。

- 18 -

第四章 程序分析和具体实现

4.1 游戏进入前的选择

每个MIDlet程序都必须有一个主类,该类必须继承自MIDlet。它控制着整个程序的运行,并且可以通过相应函数从程序描述文件中获取相关的信息。该类中拥有可以管理程序的创建、开始、暂停(手机中很可能有正在运行程序却突然

来电的情况,这时应进入暂停状态。)、结束的函数。

进入时,首先载入画面的不是游戏运行状态,而是提供选项,当再次选择Start Game时才正式运行。运行画面如图4-1所示。因此,在TankMain的构造函数中分配了StartChoice类,即选项画面的内存空间。在startApp()函数中,随即调用了Displable的setCurrent()函数将当前屏幕设置为

图4-1 游戏前的选项画面

startChoice。在显示高级用户界面前,建造了一个Alert类。Alert对象

用于显示提示、警告等告之用户信息的临时闪现的屏幕,它可作为setCurrent的参数,提前显示在最终需要显示的屏幕前。当将FOREVER作为Alert的参数时,将永久显示,直到用户点击相应按钮手动结束。但是当显示的画面元素超过一屏大小时,将自动转换为永久状态。在此,由于贴在Alert上的图片大小超出了其范围,故已成为永久状态。效果如图4-2所示。

startChoice继承了接口commandListener,这样,就可以使用高级界面的Command按钮。继承了commandListener的类必须拥有commandAction(),以决定对按键采取什么样的行为。即按钮事件触发后需执行的函数。在设置好commandlistener后,需要调用setCommandListener()以将按钮事件激活。键盘事件中,可用getCommandType()返回的Command类型来确定选择的是什么按钮。

startChoice继承了List类,用于显示列表选项,使用其append()函数可将选项加入到列表中。getSelectIndex()可检测到选择的项目的序号,序号从0开始递增。其中,当选择第一项时将载入正式游戏画面BattleCanvas类,第二项将显示帮助信息(效

- 19 -

图4-2 程序开始时的logo画面

图4-3 使用说明画面

果如图4-3),第三项则是重新显示与作品和作者相关的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。

- 20 -

结束 内存回收 N 玩家是否死亡 Y 显示GameOver 重绘屏幕 Y 敌人数量大于屏幕上的数量吗? N 最后一关或死亡了吗? N 进入下一关 Y 敌人数量小于0吗? Y 显示记分画面 N 开始 增加一个敌人 图4-4 BattleCanvas类主要关系流程图

绘出地图后,可用LayerManager的append()将地图放置在第一层。这是很有必要的。因为地图上的障碍物之一——草,在坦克运行中时是必须处于坦克的上层的,否则将失去真实性。为此,地图必须首先载入。

由于敌人将依次出现在屏幕上,同时出现的数量应当受到控制。本程序设置为6。所以在构造函数中,也应当分配6个EnemySprite对象的内存空间。构造坦克时,将把坦克的png图片作为参数传递给EnemySprite和UserSprite,BattleCanvas中创建坦克仅调用createEnemy()和createUser()实现。

在构造函数自己调用了线程的start后,程序将开始循环运行,直至跳出while的循环。每次循环中将检测是否死亡,屏幕上坦克的数量,是否该过关统计分数,检测用户输入的按键、重绘整个屏幕及回收垃圾内存(Garbage Collection)。

当敌人坦克完全死亡时(enemyNum为0),需调用System类的

currentTimeMillis()赋值给结果的时间。接着调用setCurrent()显示统计分数的画面,为了进入下一关,统计画面只是停留四秒,就重新转回BattleCanvas画面。当然,如果当前已是最后一关,就不会再转回。进入下一关时,许多变量需要重新被初始化,如地图的绘制、敌人出现位置的重置、敌人的数量、玩家坦克的当前位置。

如果游戏未结束,则需判断屏上坦克是否已小于还剩坦克的总数,如果是这样,就需要再提供一辆坦克。提供新坦克之前,在屏幕上设置了一个专用指示的闪光符号,它继承了Sprite,运行在单独的线程中。以在两秒钟内反复闪现两次为一个生命周期。当它闪光完毕后,敌人就会从闪光位置出现。这样可提示玩家具体敌人将在什么时刻出现,以便做好准备。闪光位置设置了三处坐标,由于敌人不能同时出现,便设置了enemyOutDelay的倒数计时,每次屏幕刷新会减少一

次计数,直到为0时就准备一辆坦克。本程序设置的两次坦克出现的最小间隔为2秒。

如果玩家已经死亡,就需要使用LayerManager的insert()将gameover字样插入到最上层,以免被其他物体覆盖。效果如图4-5所示。

在检测用户输入的input()函数中,当按方向键时,玩家坦克就将向不同的方向运行,这调用了

图4-5 游戏结束的画面

UserSprite的go()函数;当开炮时,就调用其

fire()函数,作出相应的行为。

在出现正式画面前设置了一个loading state*字样的单独屏幕,调用了loadinglevel()函数,并停滞了

- 21 -

图4-6 装载中的画面