(最新版)基于JAVA的游戏毕业设计论文

更新时间:2024-05-30 18:42:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

基于JAVA的游戏设计

摘要

J2SE(Java 2 Simple Edition) 定位在客户端,主要用于桌面应用软件的编程,J2SE包含于J2EE中,J2ME包含了J2SE的核心类,但新添加了一些专有类。因其拥有“Write Once, run anywhere”的Java特性而提高开发的效率。

随着JAVA应用的日益普及、Java在各种平台上的的实现,Java应用程序一次编译到处运行的特点逐渐体现出其影响力,对减少重复编程、提供快捷的跨平台应用起着不可忽视的作用。本论文着眼于JAVA技术的应用,开发一款可用于各种平台之上的游戏程序——坦克大战。本程序的思路来自于日本任天堂公司在20世纪80年代开发的Battle City游戏,将老少皆宜的经典作品重新用JAVA进行了呈现,为更流行的硬件平台提供应用软件。

关键词 JAVA;J2SE;游戏;坦克大战

1

Abstract

J2SE is a kind of fast developing technology implemented on various devices especially mobile communication equipments. It focuses on application for consumptive electronic products, providing revolutionary solution to the intelligentization and diversification of the equipment. It improve the efficiency of the development process thanks to its “Write Once, run anywhere” nature.

When cell phone is getting ever more popular nowadays, with the

implementation of Java technology on mobile equipment, increment of capital on communication service exhibits its force on people’s everyday life, providing them ever fast information just in focuses on implementation of J2SE technology and on mobile phones—Tank. This application inherits many characters of the old fashioned game Battle City which developed by Nintendo in 1980s. It transports the classical product to mobile phones, offering corresponding software for such more popular Microsystems公司于1995年5月推出的Java程序设计语言(以下简称Java语言)和Java平台的总称。用Java实现的Hot Java浏览器(支持Java applet)显示了Java的魅力:跨平台、动态的Web、Internet计算。从此,Java被广泛接受并推动了Web的迅速发展,常用的浏览器现在均支持Java applet。另一方面,Java技术也不断更新。

Java平台由Java虚拟机(Java Virtual Machine)和Java 应用编程接口(Application Programming Interface、简称API)构成。Java 应用编程接口为Java应用提供了一个独立于操作系统的标准接口,可分为基本部分和扩展部分。在硬件或操作系统平台上安装一个Java平台之后,Java应用程序就可运行。现在Java平台已经嵌入了几乎所有的操作系统。这样Java程序可以只编译一次,就可以在各种系统中运行。Java应用编程接口已经从1.1x版发展到1.2版。目前常用的Java平台基于Java1.4,最近版本为Java1.7(本文应用的JDK1.7版本)。

虽然 Java 已经被用到许多企业级软体上,可是其实骨子里面还是非常适合用在嵌入式系统之中。Java平台演进到Java2后,Java平台分别针对不同领域的需求

被分成四个版本,亦即J2EE、J2SE、J2ME以及Java Card(其结构示意图见图1.1)。

2

图1.1 Java结构图

J2SE就是Java2的标准版,主要用于桌面应用软件的编程;J2ME主要应用于嵌入是系统开发,如手机和PDA的编程;J2EE是Java2的企业版,主要用于分布式的网络程序的开发,如电子商务网站和ERP系统。

Standard Edition(标准版) J2SE 包含那些构成Java语言核心的类。比如:数据库连接、接口定义、输入输出、网络编程。

Enterprise Edition(企业版) J2EE 包含J2SE 中的类,并且还包含用于开发企业级应用的类。比如:EJB、Servlet、JSP、XML、事务控制。

Micro Edition(微缩版) J2ME 包含J2SE中一部分类,用于消费类电子产品的软件开发。比如:呼机、智能卡、手机、PDA、机顶盒。

通过本次设计可以综合运用J2SE所拥有的API,初步掌握面向对象编程的基本思想,掌握Eclipse开发J2SE程序的基本方法。掌握Eclipse调试程序的方法。简单的应用了设计模式等概念。

3

第2章 开发环境及相关技术的介绍

2.1开发环境

操作系统:Microsoft Windows XP 程序语言:Java 2

开发包: Java(TM) 2 Standard Edition (build 1.7.1)Sun Micro. IDE: Eclipse -SDK-3.4.1

2.2 Java语言的特点

1、 平台无关性

Java引进虚拟机原理,并运行于虚拟机,实现不同平台之间的Java接口。使用Java编写的程序能在世界范围内共享。Java的数据类型与机器无关。 2、 安全性

Java的编程类似C++,但舍弃了C++的指针对存储器地址的直接操作,程序运行时,内存由操作系统分配,这样可以避免病毒通过指针入侵系统。它提供了安全管理器,防止程序的非法访问。 3、 面向对象

Java吸收了C++面向对象的概念,将数据封装于类中,实现了程序的简洁性和便于维护性,使程序代码可以只需一次编译就可反复利用。 4、 分布式

Java建立在TCPIP网络平台上,提供了用HTTP和FTP协议传送和接收信息的库函数,使用其相关技术可以十分方便的构建分布式应用系统。 5、 健壮性

Java致力与检查程序在编译和运行时的错误,并自动回收内存,减少了内存出错的可能性。Java取消了C语言的结构、指针、#define语句、多重继承、goto语句、操作符、重载等不易被掌握的特性,提供垃圾收集器自动回收不用的内存空间。

4

2.3 关于ECLIPSE

Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括 Java 开发工具(Java Development Tools,JDT)。

虽然大多数用户很乐于将 Eclipse 当作 Java IDE 来使用,但 Eclipse 的目标不仅限于此。Eclipse 还包括插件开发环境(Plug-in Development Environment,PDE),这个组件主要针对希望扩展 Eclipse 的软件开发人员,因为它允许他们构建与 Eclipse 环境无缝集成的工具。由于 Eclipse 中的每样东西都是插件,对于给 Eclipse 提供插件,以及给用户提供一致和统一的集成开发环境而言,所有工具开发人员都具有同等的发挥场所。

这种平等和一致性并不仅限于 Java 开发工具。尽管 Eclipse 是使用 Java 语言开发的,但它的用途并不限于 Java 语言;例如,支持诸如 CC++、COBOL 和 Eiffel 等编程语言的插件已经可用,或预计会推出。Eclipse 框架还可用来作为与软件开发无关的其他应用程序类型的基础,比如内容管理系统。Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建。

5

第3章 程序结构、思想和相关技术

3.1 本程序需解决的有关技术问题

1、 游戏程序是一项精度要求很高的程序系统,因为其代码利用率很高。一个实时运行的最终作品,每秒都会运行成千上万行程序,绘图事件、键盘事件都会以极高的频率在后台等待响应,若有丝毫的差别都将很容易导致程序在运行不久后可能出现严重错误,甚至死循环。因此,其逻辑设计应当相当严谨,需将所有可能发生的事件及意外情况考虑在设计中。

2、 游戏中为了美观,适用性强,可能需要采用外部文件引入的图片贴图,有关贴图,在MIDP2.0中提供了用于增强游戏功能的game包,使得解决静态或动态、画面背景、屏幕刷新的双缓冲等都有较好的解决方案。

3、 己方坦克的运行可以通过键盘响应事件控制,但敌方则因为是自动运行,就需要有一定其一定的智能性;同时,出现在屏幕上的敌方可能会有较多的数量,这需要为每个敌方开辟一个线程以便能让其独立运行。Java的多线程能力为实现这样的游戏提供了可能。敌人坦克的运行算法也需要进行适当的设置,以免游戏过于简单,单调。

4、 对于双方坦克发出的子弹的控制也需要对其跟踪控制,子弹也需要处在独立的线程中。敌方子弹仅需要扫描用户坦克,而用户坦克需要在每一步扫描所有的敌方坦克。这需要对所有的对象有较好的控制。另外,子弹在运行过程中也需要实时扫描是否碰撞到了相关障碍物或屏幕边界。如此过多的线程同时在本来效率就不高的KVM虚拟机上运行,也许会导致程序的缓慢。

5、 双方的坦克在前进时也需要考虑到是否碰撞到相关物体或对方坦克,以免重叠运行,造成许多物理上不可能的情况,缺乏真实感。每一次刷新页面、每前进一步都需要将所有的周围环境都进行扫描。

6、 游戏的结束、开始、动态信息画面作为构成一个完美程序都是必不可少的重要部分。良好的用户界面更是吸引用户的硬指标,相关的美术构图也需要有一定的考虑。

6

7、 游戏的地图不可能通过绘图来解决。否则,不仅难于控制和处理过多的元素,也会因过多的大型图片而不能限制程序的大小,失去程序的原则和Java的优势。同时,地图关卡不宜保存占用过多的内存,而最好采取外部文件的读入读出方法。

8、 用户运行游戏时需要有分数记录的可能。如何采用合理的记分标准,需要进行适当的设计。记录分数的存储方式也需要有较好的解决方案。手机中由于处理器和内存空间、存储空间都十分有限,其数据库系统与普通PC大相径庭。其数据库结构较为简单,被称之为RMS系统。

9、 本程序应用的技术

多态Polymorphism;单例模式Singleton;责任链模式Chain of Responsibility;工厂模式Factory Method;简单工厂模式Simple Factory;抽象工厂模式Abstract Factory;策略模式Strategy;调停者模式Mediator;门面模式Facade等概念与技术并将一些属性信息抽象了除了以配置文件的方式出现,从而方便用户更改。以上相关技术细节和整体流程将分别在以下小节阐述。

3.2 程序截图

开始界面 坦克混战 图3.1 程序截图

游戏界面 狂轰滥炸 3.3 程序流程

本程序采用面向对象的设计模式,对游戏中的所有物体赋予对象的概念和属性。运行程序后允许用户选择执行选项菜单,在开始游戏后将先从外部文件载入地图文件,对背景的所有物体进行绘图。在主程序运行的线程中,画面刷新将以一定的频率采用双缓冲技术对屏幕重绘,实时反映整个游戏的进行状态。用户控制的坦克运行在主线程中,随屏幕刷新的频率而步进。敌方坦克将在游戏开始时逐渐新增线程,每增加一个敌方对象就新增加一条线程,一旦线程数满到最大值,就不允许敌人再继续出现。用户坦克自诞生之时起将拥有一发子弹,子弹虽然开在单独的线程中,

7

但运行结束后(比如撞到相关物体或敌方坦克时)并不结束子弹对象,只是将其线程终止。用户再次发射子弹时只是将终止的线程再次激活。在屏幕重绘的主程序中,将在每次的循环中判断若干事件。如:用户坦克的生命是否已完全用尽,敌方坦克数是否已经为零,屏幕上的坦克数量是否少于仍剩下的坦克数量等。以便程序进入相关的分支执行相关的反应代码,结束游戏或统计分数等。主程序流程如图3.2所示。

3.4 相关技术

3.4.1 多态

多态性是继数据抽象和继承后,面向对象语言的第三个特征。Java的多态性它的突出优点是使程序具有良好的扩展性。它通过继承,可以派生出任意多个新类型,或向基类增加更多方法时,无须修改原有对基础类进行处理的相关程序。就是扩展性好。

3.4.2 单例模式

作为对象的创建模式[GOF95], 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。

图3.3 单例模式图

显然单例模式的要点有三个;一是某各类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。在下面的对象图中,有一个\单例对象\,而\客户甲\、\客户乙\和\客户丙\是单例对象的三个客户对象。可以看到,所有的客户对象共享一个单例对象。而且从单例对象到自身的连接线可以看出,单例对象持有对自己的引用。如图3.3所示。

8

3.4.3 责任链模式

多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

适用范围:

1、 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。 2、 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、 可处理一个请求的对象集合应被动态指定。com.cz.tank包下的ColliderChain类用责任链模式遍历所有游戏物体 做碰撞检测。

3.4.4 工厂模式

工厂模式为系统结构提供了灵活的动态扩展机制,减少工作量方便维护,方便维护。com.cz.tank 类 GameFactoryMgr应用了工厂模式。

3.4.5 简单工厂模式

专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。它又称为静态工厂方法模式,属于类的创建型模式。简单工厂模式的UML类图如图3.4所示:

9

图3.4 简单工厂模式

简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。该模式中包含的角色及其职责。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。

3.4.6 抽象工厂模式

抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品具体类型的情况下,创建多个产品族中的产品对象。这就是抽象工厂模式的用意。

每个模式都是针对一定问题的解决方案。抽象工厂模式面对的问题是多产品等级结构的系统设计。

3.4.7 策略模式

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。本程序的坦克外观使

10

用了策略模式。com.cz.tank.strategies的DrawTankStrategy类。

3.4.8 调停者模式

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。com.cz.tank 类 Game Mediator使用了调停者模式。

3.4.9 门面模式

外部与一个子系统的通信必须通过一个统一的门面(Facade)对象进行,这就是门面模式。

3.4.10 PNG格式

PNG具体格式由PNG Specification Version 1.0定义的。PNG格式提供透明背景的图像,这对绘制游戏画面和被操纵主角极有帮助。坦克之间或与障碍物碰撞时就不会因为背景有特定的颜色,显示出的效果像贴上的图片而缺乏真实感,物体之间轻微重叠时最上层图片也不会覆盖超过其有效象素外的部分。

PNG格式图片中包含许多定义其图片特性的冗余部分(Chunks)。这些代码包含在每一个单独的PNG格式图像中,然而如果将多个PNG图像合并在一张幅面稍大一些的整图中,多个chunks就可以得到精简,图片的大小可以得到控制。使用Image类中的create Image函数可从整图中分割出所需要的元素。在Game包中的Tiled Layer和Sprite类都整合了这样的功能。本程序中的地图元素都集成在一张MAP.png图片中,实现了方便的管理和程序体积的精简。

3.4.11 AWT绘制的基本原理

AWT的绘制与界面更新使用了一个单独的线程,称为AWT线程。paint、repaint、update 三个方法关系如图3.5所示 :

11

图3.5 双缓冲原理示意图

3.4.12 双缓冲

进行游戏绘图一般需要手动编程使用双缓冲。需要在paint()方法内所想要画的图形画在一张预先准备好的背景,等所有绘图操作都完成后再将背景的数据拷贝到实际的屏幕上。Image类提供了一个建立背景的静态方法createImage(int width, int )。

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

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

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

12

在检测用户输入的input()函数中,当按方向键时,玩家坦克就将向不同的方向运行,这调用了UserSprite的go()函数;当开炮时,就调用其fire()函数,作出相应的行为。

在出现正式画面前设置了一个loading state*字样的单独屏幕,调用了loadinglevel()函数,并停滞了1500毫秒,提示用户做好准备。

在绘图的render()过程中,除了要重绘坦克、地图、子弹外,还会在右边空白处绘出一个生命统计栏。并反复使用Graphics的drawLine()、drawImage()绘画出一个三维的效果,增强视觉感。该三维栏的上方为白色,下方为黑色,就创造了立体感。在每次刷新绘图页面时,应使用GameCanvas的flushGraphics()将屏幕后台的缓冲区内的图象刷新到前台来。

在允许敌人出现前,需要检测给即将出现的敌人分配一个数组序号。在程序中调用了getNullEnemyIndex()进行测试,当返回为-1时说明没有序号可以分配,否则,将返回空的序号。

4.2 坦克的共同行为

在TankSprite中定义了所有坦克(包括敌方坦克和玩家坦克)的共同行为和属性。EnemeySprite和UserSprite都继承了该类以简化结构。在transformDirection[]中定义了坦克四个方向分别应将原始图片旋转的角度,分别为

TRANS_NONE,TRANS_ROT90,TRANS_ROT180,TRANS_ROT270,以便在后来的setTransform()中将这些常量代入。构造函数中创建了每个坦克必须拥有的一颗子弹,这些子弹就将只跟随自己的坦克调动。

为了能提前预测碰撞,调用了defineCollisionRectangle()将碰撞矩形向前设置了一个象素,具体原理见第二章。

在setBulletDirection()中,将根据坦克当前的方向确定子弹出膛后的方向,其中setRefPixelPosition()将子弹的参考点设置在其未变形状态的底部,setXY()将其放置到炮口的位置,setTransform()将其图片方向转到需要使用的位置。

canPass()函数将返回坦克是否能够向前前进,考虑到的因素有边界、障碍物。它返回一个boolean值,提供给go()函数,做进一步的判断。getTileIndex()将检测传递来的象素处是什么类型的障碍物,它将象素除以8(即障碍物的象素宽度),取整,

13

再通过getCell()得到。在得到障碍物属性后,判断其序号是否与草相同,或是否为空(序号为0)。因为所有的障碍物中只有草不会阻碍坦克的向前运行。

4.3 玩家坦克的功能属性

构造函数中需要将坦克方向设置为向上,因为刚出现时就是这样的状态。当开炮时,调用BulletSprite的setLayerManager()将子弹与layerManager联系起来。需要联系的还有自身坦克、地图。这些都由坦克传递给子弹。因为子弹是属于坦克的,它的属性需要跟当前的坦克保持一致。接着使用append()将子弹贴到layerManager上显示出来。最终调用其start()开始子弹自己的线程。子弹一旦开始运行,就脱离了当前坦克的控制,直到其生命周期终止。

无论子弹是属于敌人还是玩家的,它都必须记录自己的来源和攻击的对象。在玩家坦克发射的子弹中,就必须将攻击对象设置为所有的敌人。这样,它才能有扫描的目标。在setShootCheck()的参数中,传给子弹的是敌人的数组,子弹的对象就被确定了。

die()、resetPosition()、getLife()都是很简短的函数,但却提供必不可少的功能。他们可被外部调用,以取得生命值、死亡记数、重置位置。

在go()函数,每个方向在走前都须用if (canPass(UP)&&!collidesEnemy()) 检测是否可以行走。canPass()检测是否有障碍物及是否到边界。collidesEnenmy检测是否前方有坦克阻碍行动。当可以行走时,就在当前方向的坐标上增加或减少一个象素。

在collidesEnemy()函数中,将有一个for循环按照敌人数组的序号依次检测6次。有一点非常重要:在检测前,需要将敌人的检测矩形区域设置为与原来图片一样大小。否则,当玩家向上走,而有敌人从左方向右走,并且已经碰撞到玩家坦克时,玩家坦克会因为被判定已与敌人发生碰撞而不允许前进。事实上,敌人坦克此时并没有阻碍玩家前进。这样的判断必须排除在考虑范围外。当然,在设置完成后,必须将将检测区域设置回原先的状态,否则敌人在往后自己的检测中将发生错误。

14

4.4 敌人坦克的功能属性

由于和UserSrite同属于一个TankSprite的继承类,其功能就与UserSprite有很大的相似之处,但也有其自身的特别属性。其主要功能流程图如图4.2所示。

首先,EnemySprite继承了Runable接口。因为敌人的运行是自动的,需要有设定的程序让它可自己控制,而不像UserSprite完全通过每次输入的键盘信号来做出反映。因此,它可以运行在单独的线程中。

setEnemyShootCheck()函数与UserSprite中的一样,设置了攻击的对象,并且此函数将继续把参数传递给自身的子弹,以便子弹可以识别攻击对象。此函数由BattleCanvas调用。

getRandomDirection()以当前系统时间作为种子,调用了Random类的nextInt()产生一个随机的整数,此整数取除4的余数的绝对值作为随机的方向。

Random random=new Random(System.currentTimeMillis()); return Math.abs(random.nextInt())%4+1;

此时返回的值的范围就确定在1~4之间,正好对应四个方向。将他们代入需要使用方向的函数中就可以使用了。

getRandomStep()的原理类似:

Random random=new Random(System.currentTimeMillis()); return (Math.abs(random.nextInt())%4)*50;

只是需要乘以每秒会刷新的屏幕的次数。这样就相当于允许在某一个方向运行0~3秒钟的时间。

每个敌人还需要拥有一个内部的所有敌人的数组元素。这样,它们才可以自动检测自己是否与同伴发生了碰撞,以便采取躲避、转向等行动。

collidesWithOtherTank()将检测是否与其他坦克(包括敌人和玩家)。一个循环将依据敌人的序号查找5次。if(i==number)break ;语句将避免检测到自己,永远返回真。

collidesInOtherTank()虽与上面的函数很相似,但仍有一些细微不同,那就是不需要在检测前设置被检测方的矩形区域。因为不需要进行预先检测。此函数用来检测是否在刚出现时就与其他坦克发生碰撞的。如果一出现,出口就被堵死,显然,

15

不能永远不出现,那就应采取其他的办法,否则两辆坦克将因为都处在碰撞状态中而无法移出。

在运行的线程中,需在每前进的一步骤中循环做下列事件: 如果坦克已死亡,立刻退出。(由boolean值destroyed决定)。

如果不是刚出现(由isBeginner决定),判断是否与将其他坦克发生碰撞,就向当前方向前进一步骤,否则,将需要循环检测的当前随机步数减少为原先的23(为了加速离开的时间)。如果刚出现,就直接走一步,具体如何行走将在go()函数中决定,并且此go()与UserSprite中的有所区别。

当随机发炮数减少到0时,就进行发炮的动作。发炮后应立即重新赋值给随机发炮数,以便重新倒数计算。

当所有的步骤走完后,因为需要转动方向,于是,调用一次随机取得方向的函数再次获值。其他的随机值也应当重置。

在go()函数中首先检测是否正处于碰撞状态中,如果不是,就需要取消Beginner的状态,因为不需要Beginner这样的特殊身份,让别的坦克不检测了。

在运行在某个方向上,当确定为canPass时,应再检测是否为Beginner。如果是,就不应该受到其他坦克的影响而直接改变坐标,但若不是,就应当远地不动。

4.5 子弹的运行和控制

子弹继承了Runnable,运行在独立的线程中。它拥有一个很重要的变量,isFromEnemy。它标识了该子弹是属于玩家的,还是敌人的,这样可以控制子弹在脱离坦克管束后的运行状态中的行为。其主要功能流程图如图4.3所示。

checkHit(int x,int y)调用了getTileIndex(x,y)获取当前子弹击中的是什么障碍物,如果返回了false就表示没有击中任何东西。当击中了需要作出反映的物体时,就分别采取措施:击中草时,由于没有定义相关函数,就不会有任何反映,会重合在草上正常通过;击中砖块时,将产生爆炸,调用setCell将当前块置为空,并产生爆炸效果。爆炸效果由tileExplode(x,y)根据需要爆炸的坐标点生成,其中将一个Sprite图片在界面上闪现150毫秒。爆炸效果需要将图片insert进第0层,这样才不至于被其他景物所覆盖,爆炸结束后layerManager会自动相应调整。击中钢筋时,将只产生爆炸效果。

16

setShootCheck(EnemySprite enemySprite[]);setUserSprite(UserSprite userSprite);

setEnemySprite(EnemySprite enemySprite)都是将相关的坦克传入到子弹类里来,以便确认来源或攻击目标。

在线程的循环中while ( (x < 155) && (x >=5) && (y >=5) && (y < 171))作为循环的条件可以控制子弹出界的范围。这几项参数在编写时很容易出错。它们反映了象素级处理的技巧。如果程序在子弹已经到达X轴的155坐标时仍允许子弹继续运行,子弹将一次性向右运行2个象素,到达157点。在随后的checkHit(RIGHT)调用中,它将检测它是否在x+3点,即160点击中了某个障碍物,但是1608=20。地图的tiledLayer对象中并不存在序号为20的块,最大只为19。此时ArrayOutOfBoundException异常就会抛出,程序终止运行。

子弹运行中,将用collidesWith(tiledLayer,true)测试是否碰撞上了地图。如果为真,就继续检测碰撞上了什么样的物体。这将针对四个不同的方向分别以象素级检测。如果击中了某样物体,那么checkHit自然会处理,子弹的生命周期结束,以break退出循环。

如果没有击中物体,就继续检测是否击中了某辆坦克。这根据子弹的来源分为两种情况。当来自玩家时,将首先检测所有的敌人发出的子弹,当发生子弹间的碰撞时,用户的子弹将被移除,虽然按照道理敌人的子弹同时也应被移除,但敌人子弹是运行在另一线程中的,应当由它自己来控制为好,用户的子弹只需要管理好自己的状态就可以了。如果没有和子弹发生碰撞,就检测是否与敌人碰撞,发生碰撞时,将敌人从layerManager中移除,并置为null,产生爆炸效果,敌人数量减少一位,敌人屏幕上数量减少一位。

如果是来自敌人的子弹,将同样检测与玩家子弹的碰撞,及与玩家坦克的碰撞如有碰撞,玩家生命数减少一位,位置重置。如果玩家生命已死亡殆尽,就需要在进行以上操作的同时将玩家坦克的位置放置到屏幕外的部分。因为layerManager的remove函数并不会真正将层移除。只是用户看不见而已。如果不放置到屏外,敌人坦克仍会被阻挡,子弹仍会再次击中用户坦克。这将会是很荒唐的场面。

为了能控制一辆坦克在同一时间只能发射一发子弹,在子弹生命运行结束时候,将调用userSprite.enableShoot()恢复坦克继续发炮的能力。因为在发炮期间,坦克的

17

再次发炮的功能是被锁定的。

18

结论

本程序设计实现使用J2SE为工具的坦克大战游戏的开发,采用从外部文件读取配置文件、自动控制敌人坦克运行的方式进行控制,具有一定的可玩性和复杂性。经过了细心的调试和排错解决了绝大部分的问题。

但几乎每一个计算机程序都会有这样那样的不足,尤其是未经过精心维护的非商业软件。即使是作为操作系统的各种版本的Windows也时常会发生许多类型的错误和漏洞。本游戏程序对于初涉此领域的毕业设计课题来说,尤其在开始初期,感觉逻辑复杂,难以控制,因此至今还有一些未能解决的bug。 目前发现的bug和未完善的功能列表如下:

1、敌人的人工智能变化较少,不够理想。

2、子弹和敌人经常会与画面的刷新的线程不同步,造成画面闪烁。

3、 由于每次子弹发射和每次坦克的移动的一个像素都会对所有坦克和所有子弹进行一次循环检查,并由于同时开的线程比较多,使得本来运行效率就不高的JVM运行异常缓慢。即使刷屏没有间隔也不会提高速度。尤其在坦克比较多,炮弹比较多情况下尤为明显。

4、有的时候开始LOGO不能正常显示。 已经解决的重要bug:

1、当发出子弹到达边界并同时还在草丛中时会抛出数组边界异常。 2、有时会莫名其妙的死机。

本科期间做过很多课程设计,大多规模很小。在各种应用软件和游戏中,我仍觉得对游戏的设计有极大的热情。因为其各个模块间的联系十分紧密,代码重复执行率高,当经过无数次的调试、修改后,能最终看到成品,有无比自豪的心情。大学期间做过银行取款机、图书馆管理程序等简单的数据库管理系统的课程设计,思想大致相似,变化范围有限,没有太多自己可发挥的余地。大家作品的最终结果都离不开同一个模式。相比一些数据库软件,游戏的设计有很多人情色彩和艺术思想的发挥,正式商业的软件的人性化界面和各个游戏间迥异的结构每每会让人有去开发的冲动。

19

游戏程序最大限度的利用了硬件条件,因此展现出的画面往往多彩绚丽、效果惊人。成功的游戏融合了三维运算、人工智能、音效处理等计算机多媒体的精华部分。本毕业设计建立在Java平台上,是本人以前未曾接触过的领域。凭着探索新知识的热情,我选择了该设计题目。

学习该平台背景和功能的时间远远超出了我想象的时间。在设计初期,为了画出一个简单的图形,需要花费一天的时间,为了使图形产生动态效果又会花费几天的努力。很多相关的技术,如需要使用到的线程、设计模式、Game包的新功能、高级、低级图形界面的使用、时钟的控制、贴图,每一项都需要花一定的时间去掌握和熟悉。更为困难的是,JAVA虽然是现在的主流技术,但是其应用主要形成在WEB开发领域,GUI的开发还是相对较少的,参考资料不是很多,在发觉中文资料的稀少后,为了进一步探索深层次的技巧,我花费了大量时间在sun的Java主页上,阅读了几十篇英文的技巧和代码样例。并经常在各大论坛出没提出遇到的问题。

在终于可以照猫画虎的写出一小段动画的代码时,已经过去了相当长的准备时间。我原以为这样的速度将无法完成毕业设计,但当掌握了大部分应用技巧时,剩下的游戏思路的设计就显得不是最大的障碍了。指导老师说Java的上手比较困难,需要配置的环境和掌握的背景比较多。现在看来的确是这样。

我在一星期内写了1500行代码,经过了几百次的调试,终于完成了现在的程序。原先认为不可能的事,我发现,如果有不畏困难的信心和肯钻研的勇气,就一定会完成,甚至达到意想不到的效果。

本程序打包后体积6M多,运行时如进行gc()内存回收可将运行时堆内存控制在50K以内,然而,回首80年代的红白机上的坦克大战原始游戏,将惊叹那样的商业软件的巧夺天工。华丽的界面,出色的人工智能,流畅的运行效果、多音效、双人操作控制,其二进制程序体积仅仅为24K。运行在12MHz,8K内存的硬件机器上仍不失流畅性和可玩性。而许多游戏程序需要大量的运行内存空间、1GMHz以上的处理器,仍运行不够流畅。机器代码级和基于虚拟机的半解释性处理的程序在这里得到了最大的对比。

20

本文来源:https://www.bwwdw.com/article/ju96.html

Top