[计算机毕设]基于java的手机游戏堡垒的设计与实现(源代码+项目报告)

项目说明报告

手机游戏(堡垒)的设计与开发

随着手机业务的迅速发展,手机游戏逐渐成为移动增值服务的兴奋点。本项目设计就着眼于J2ME技术的应用,设计与开发一款探险类手机游戏(堡垒)。

该堡垒游戏是基于J2ME开发的手机RPG游戏,采用midp 技术实现了菜单、地图、主角动作及怪物动作和AI等,主要通过精灵间的碰撞检测来触动事件发生。游戏的主流程是玩家利用手机键盘操作主角在堡垒中拾取道具破解迷宫,并且随着关数的增加,游戏的难度也逐渐增加。另外,游戏中还包括了排行榜,声音设置,帮助等各种附加功能。其中充满了趣味性和刺激性,是适合各年龄段的益智冒险类游戏。

本报告介绍了J2ME的相关技术及该堡垒游戏程序的结构分析和具体功能的实现。

J2ME;  手机游戏;  堡垒

                                                     

                                                        总页数:23页

1引  言... 1

2 手机游戏的现状和J2ME的概况... 1

2.1软件现状... 1

2.2 J2ME概况... 2

2.2.1 J2ME的由来... 2

2.2.2 J2ME的3层体系结构及MIDP简介.. 2

2.2.3 Configuration和Profiles 3

2.3 J2ME现状和前景.. 4

2.4 手机游戏业务... 5

3 开发环境介绍... 5

3.1开发环境... 5

3.2 关于SonyEricsson  Wireless Tool Kit. 5

4手机游戏(堡垒)的开发... 5

4.1 游戏的的思路、构想... 5

4.1.1 游戏想法的产生.. 5

4.1.2 对游戏设计的初步认识... 6

4.1.3 模块成型阶段... 6

4.2 程序的类结构... 7

4.3 游戏的流程图... 7

4.4 游戏的实现... 8

4.4.1 主类GameMIDlet的实现.. 8

4.4.2 游戏画布MyGame类的实现... 13

4.4.3 玩家精灵GamePlayer类的实现... 17

4.4.5 SoundEffects类的实现... 19

5 程序设计过程中遇到的一些重要问题... 19

5.1 关于碰撞的问题... 19

5.2 关于游戏画面的显示问题... 20

结    论... 20

参考文献... 20

致    谢... 22

声    明... 23

1引  言

Java语言是美国Sun Microsystem的James Gosling、Pratrick Naughton及Mike Sheridan等人于1991年精心设计出来的计算机编程语言,其构想在于实现使用同一种编程语言所写出来的程序可以在不同的平台上运作。这种架构对于消费性电子产品而言是具有革命性的,因为在消费性电子产品中的处理器及操作系统各不相同,要在这些平台上开发程序必须要了解各个平台的特性,以及其提供的API使用方式,分别开发不同的版本才能执行,影响应用程序的普及性。

近几年,由于微处理器性能的大幅提升,加上无线通讯技术的突破,手持式移动设备开始受到大众的青睐。短短几年内,手机已经升级了几代产品,普及率逐年攀升,生产效率不断上升,产品价格比个人电脑的摩尔定律有更惊人的下调,以至手机是大多是城市居民不可缺少的一件随身设备。继短信、彩信等服务之后,中国移动提供基于Java的百宝箱业务,应用产品遍及商务应用、信息获取、英汉互译、游戏娱乐等多媒体领域。

为了适应移动数据的发展,推动无线电子商务等业务的发展,J2ME(Java 2 Micro Edition)既用于嵌入式系统的Java被引入无线领域。J2ME的出现实际上是Java技术的回归。作为Java2平台的一部分,J2ME与J2SE、J2EE一起,为无线应用的客户端和服务器端建立了完整的开发、部署环境。随着J2ME的应用,它为移动互联引入了一种新的模型,既允许手机可以从互联网上下载各种应用程序,并在手机创造可执行环境离线运行这些程序。由于定义了可执行下载的标准,并在手机上创立了可执行环境和程序开发语言,由此,在移动通信业第一次为软件开发商创造了巨大的商业机会,手机用户在得到丰富应用体验的同时,也大大提高了运营商的网络流量。

2 手机游戏的现状和J2ME的概况

2.1软件现状

在信息社会中,手机及其他无线设备越来越多的走进普通百姓的工作和生活,随着信息网络化的不断进展,手机及其他无线设备上网络势在必行。但是传统手机存在以下弊端:

1.  传统手机出厂时均由硬件厂商固化程序,程序不能增加、删除,有了错误也不能更新、修改,若要增加新功能必须另换一部手机。

2.  传统手机访问互联网是通过WAP(Wireless Application Protocal),所有网络资源必须接通网络才能在线访问,非常耗时、费用亦很高。

而Java技术在无线应用方面的优势非常明显:

1.  应用程序可按需下载,而不是购买由硬件商提供的套件,可升级空大。

2.  Java技术提供了一个类库,它使的应用开发商可以创建更为直觉、丰富的用户界面(GUI);

3.Java技术使网络带宽的应用更为有效,因为应用程序可以下载到器件上,并在本地运行,仅仅是在连接到服务器时才会占用网络带宽。

2.2 J2ME概况

2.2.1 J2ME的由来

Java的最大目标和特点,就是“一次编写,到处运行”的平台无关性。但是,一套标准无法适应各种不同的需求。因此,Java技术目前共有三套,分别针对不同的平台和应用。

Standard Edition(J2SE,标准版):针对桌面端PC和工作站的个人和低端商务应用。

Enterprise Edition(J2EE,企业版):针对服务器端企业级应用,支持Servlets, JSP和XML等等。

Micro Edition(J2ME,袖珍版):针对有限内存,显示和处理能力的设备,主要是消费电子和嵌入式设备领域(这实际正是Java语言设计最初的目标领域)。


图1 java结构

在消费电子和嵌入式设备领域,内存从几百K到几十M,从没有屏幕Web-TV,CPU从低功耗的嵌入式处理器到206MHz的RISC处理器,硬件条件的差异是相当大的。这就使得J2ME的标准需要有不同的层次和类别来适应这个复杂的领域,因此相比之下J2ME就比J2SE和J2EE的标准要复杂得多。因此,清楚的理解J2ME的体系结构的划分才能更好的理解和掌握J2ME。

2.2.2 J2ME的3层体系结构及MIDP简介

J2ME的3层体系结构依照各种设备的资源特性,将J2ME技术构架分为简表(Profile)、配置(Configuration)和Java Virtual Machine(JVM)3层,然后再进一步细分,这使J2ME能够在每一类设备的限制下工作,而同时提供最低限度的Java语言功能性。

关于J2ME的体系结构,可以这样来进行总结:Configuration的分类是根据计算能力的不同来划分的,同类设备的计算能力相近。Configuration是一个规范,定义了这类设备的共同Java平台,定义与设备无关的Java虚拟机和核心库,是平台相容性的基础。Profile的分类是根据设备功能划分的,同类功能的设备其他各种硬件条件和需求也相近。Profile是一组API,在某Configuration的基础上扩展了针对设备特定功能的API,使得标准能够完全适应特殊的设备,彻底发挥设备的功能。

J2ME体系的一般结构是:由Configuration定义的Java虚拟机运行于设备的宿主操作系统之上,构成整个平台的基础。Configuration提供了基本的语言特性,Profile提供针对设备的特殊功能API和扩展类库。应用程序的运行环境需要一个Configuration和至少一个Profile,多个Profile可以共存,也可以叠加。

MIDP(Mobile Information Device Profile)定义了针对移动信息处理设备(主要指智能手机和一部分具有无线通信功能的PDA)的图形界面,输入和时间处理,持久性存储,无线电话网络连接之上的一些消息处理(例如短消息),安全等等API,并且考虑到了移动信息设备的屏幕和内存限制。类似于J2SE中的Applet框架,MIDP提供了基于javax.microedition.midlet 包的MIDlet应用程序框架。

因为MIDP提出的比较早,目前重要的智能手机和PDA操作系统上都已有了相应的实现,而且应用的也比较广泛。

2.2.3 Configuration和Profiles

针对消费电子和嵌入式设备领域丰富多样的设备和彼此相差极大的计算能力及各种硬件条件,J2ME首先根据最基本的一些特征把它们划分为两类。

具备间断网络通讯能力的个人移动信息设备:如手机,双向呼机,PDA(Personal Digital Assistant,个人数字助理,也称掌上电脑)等等。 有固定的不间断网络连接的共享连接信息设备:如置顶盒(set-top boxes),Web-TV,支持Internet的有屏幕电话,汽车娱乐/导航系统等等。

Sun对J2ME 有一个很好的概括:J2ME技术有两个设计中心——手持的设备,和可以插到墙上插座的设备。第一类设备往往是个人化的,移动的,使用电池,体积和功耗都有限制,因此功能和计算能力有限。第二类设备一般是固定的,因此体积没有太大限制。由于固定,可以有持续电源供应,因此功耗没有太大问题,计算能力相对充裕。

计算能力是这两类设备的主要区别,对其上可能的应用和环境显然有着本质影响,不同类别的设备不可能采用同样的Java平台,必须分别定义。针对这两大类设备的平台规范就是Configuration。第一类设备的Configuration称为CLDC(Connected, Limited Device Configuration),第二类称为CDC(Connected Device Configuration)。

属于同一类的设备计算能力是相似的,但是其他功能和条件还有非常大的区别。作为Java平台必须保证相容性,这就必须舍弃所有的设备特殊性。因此,Configuration就是支持一组通用设备的最小Java平台,作为这些设备的最小公分母来保证不同设备间的平台相容性。这里的Java平台主要是指Java虚拟机(JVM)和核心库。

在Configuration中舍弃了设备的特殊性来保证Java平台的相容性,但是仅仅有Configuration显然是不够的,特殊的具体设备其独有的功能和硬件条件都没有得到支持。为此,在Configuration的基础上,根据设备具体功能再进行一次划分,比如智能手机,PDA等等。功能的划分也就是其他硬件条件的划分,比如屏幕大小,内存,计算能力,电力供应等等都是从属于功能的,因此同功能的设备的硬件条件都是非常相似的。Profile(译为简表或者简档)就是针对每一类功能设备的特殊性定义的与设备特性相关的API,建筑于Configuration之上,作为Configuration的扩展和补充。例如MIDP(Mobile Information Device Profile,移动信息设备Profile)就定义了关于移动信息设备(主要指智能手机和一部分具有无线通信功能的PDA)的图形界面,输入和时间处理,持久性存储,短消息等等的API,并且考虑到了移动信息设备的屏幕和内存限制。而正在制定中的PDA Profile则定义了针对PDA的API,其屏幕,内存条件都要大于MIDP,但是网络方面的要求则显然和手机有所不同。如下图所示,同属于Configuration的设备根据功能不同由不同的Profile来支持,Profile体现设备的特殊性,但是都建筑在一个共同的基础Configuration平台之上。

2.3 J2ME现状和前景

J2ME已经广泛的应用在了很多的移动设备上,很多的移动设备都实现MIDP的参考实现,但不同的移动设备还是有一些不同的地方,比如应用与手机上的Profile就不适合在PDA的Profile。有一些系统,比如Symbian实现了CLDC和MIDP,作为智能手机的操作系统,是理想的MIDP应用平台。其他的系统,如在Compaq的iPaq上已经实现了CDC,IBM的WebSphere Micro Environment在Pocket PC上实现了CLDC,CDC和MIDP。可见,在硬件条件较好的PDA上都可以实现CDC的标准。由于这些主要操作系统平台都是开放的,基本可以相信,主要的移动信息设备操作系统都将一直提供J2ME的支持,但是具体支持哪个标准则并不一定死板地按照CLDC和CDC的最初定义,和设备的硬件条件和厂商的选择有关,或者可能同时实现多个标准。所以说J2ME的还是在快速的发展的。

2.4 手机游戏业务

手机游戏是移动多媒体时代最有价值的应用。这是因为,游戏是多媒体应用中集大成的业务,图像、音乐、互动都能在游戏中实现,能充分满足用户各方面的需求。

虽然目前手机游戏还无法与PC游戏相比,其显示功能和键盘输入、声音处理能力也形成一定制约。但是随时随地可操作可联网的特性大大拓展了人们娱乐休闲的时间和空间,以游戏功能为主的手机终端在市场上渐被认可,多媒体功能正向手机的标配功能演进,制约手机游戏发展的技术瓶颈将被打破。当前的手机游戏产业尽管仍然存在很多制约其发展的瓶颈,但手机游戏已显示出非比寻常的发展速度,其市场潜力十分巨大,将成为移动增值服务市场新的增长点。

3 开发环境介绍

3.1开发环境

操作系统:Microsoft Windows XP

程序语言:Java 2

开发平台:Java 2 Micro Edition

开发工具: Wireless Tool Kit 2.1+ UltraEdit-32_12.00a+1_SC

3.2 关于SonyEricsson  Wireless Tool Kit

SonyEricsson WTK(Wireless Tool Kit)是SonyEricsson公司针对J2ME推出的用于手机和Palm等移动设备的开发包,是手机厂商的专用开发包。它通用性高,开发出的应用程序可保证能运行在大部分设备上,而不像专用厂商具有一定的不兼容性。虽然它没有强大的功能和完善的调试手段,但它提供运行模拟器的最基本组件,是其他IDE需集成采用的必备元素。

当前的最新Release的版本为J2ME WTK2.2。

4手机游戏(堡垒)的开发

4.1 游戏的的思路、构想

4.1.1 游戏想法的产生

相信大家一定都在8位机机上玩过《冒险岛》这款游戏,非常有趣味性。

游戏中玩家通过不断的闯关,来解救公主。在每个关都很很多的怪物阻挡着你,所以需要运用各种机关或者秘籍来杀死它们。杀死他们的同时还可以获得各种奖励,加生命,加血等,增加了游戏的趣味性。

如图2所示:

图2 游戏截图

这款《冒险岛》游戏的实现相对于其他RPG或者网络版手机游戏稍简单一些,适合初学者作为练习,所以我决定编写一款类似的手机游戏。

由于之前对手机游戏的编程知识以及游戏的设计只有初步的了解,因此,我们在游戏的构架和思路上经历了几个阶段。

4.1.2 对游戏设计的初步认识

刚开始我们只对J2ME有初步的了解。这时我们只是模仿之前在PC上看到的游戏,用语言把游戏的实现感性的描述为几大部分:

游戏界面系统:包括游戏开始界面;游戏开局界面;游戏运行界面;游戏结束界面。

游戏元素:菜单类;画布类;人物类;排行榜类。

4.1.3 模块成型阶段

在进一步熟悉了J2ME知识后,对框架做出了一些修改,逐步把游戏的基本功能确定。游戏依次进入加载界面;主菜单;游戏运行界面;游戏结束界面。

具体实现的功能为:

1.主菜单,有如下选项:

(1)开始游戏——进入游戏界面。

(2)声音——设置声音的有无选项。

(3)帮助——介绍游戏的玩法。

(4)排行榜——玩家所得分数的排行榜。

(5)关于——用来显示说明信息以及背景图片。

2.游戏运行界面,包括:

游戏界面;目前游戏得分;游戏关数;生命次数;

3.游戏结束界面:游戏结束后,显示一行说明信息,然后退回到菜单。

游戏的主要模块为:

1.游戏主MIDlet(GameMIDlet)——对游戏生命周期的判断;对画布类的调用;管理游戏程序中各个屏幕之间的转换。

2.游戏画布(MyGame)——对游戏所用变量,常量的设定;游戏的初始化;游戏中精灵运动轨迹的控制;精灵与砖块的碰撞检测以及砖块状态的控制;游戏中各关卡的基本设定;游戏中对按键状态的处理。

3.菜单类——游戏中菜单事件的处理。

4.GameOgre类——游戏中怪物的类。

5.GamePlayer类——玩家控制的精灵类。

6.GameRMS类——用于实现分数排行榜。

7.PlayMusic类——用于实现音乐的播放。

8.MySet类——声音大小的设置。

4.2 程序的类结构

程序一共有8个主要类,其中菜单类负责各个屏幕的切换。程序的类结构如图3所示:

PlayMusic

GameOgre

GameMIDlet

:MIDlet

Mymenu

MyGame

GameRMS

MySet

Myhelp

 

图3   类结构

4.3 游戏的流程图

进入游戏菜单。初始情况下,游戏菜单有5个选项,它们分别是开始游戏、游戏说明和排行榜、设置、关于。选择开始新游戏则进入游戏,在游戏中如果按下非游戏键则中断游戏返回菜单,此时菜单中增加了一个继续游戏的选项,可以返回游戏也可以重新开始新的游戏。在菜单中选择游戏说明或者高分记录,则进入相应的屏幕,他们都能用“后退”软键返回菜单。菜单中的退出选项用于退出程序。游戏的流程如图4所示:

退出

新游戏

说明

排行榜

设置

关于

菜单

关于

Back

设置

Back

排行榜

Back

说明

Back

游戏

                                                                     

图4  游戏的流程图

4.4 游戏的实现

游戏一共实现了几个类,包括用于游戏外部的、菜单类、排行榜屏幕类、声音设置屏幕类、结束屏幕类,以及用于游戏本身的游戏画布类、声音效果类。

4.4.1 主类GameMIDlet的实现

MIDlet是最核心的类。MIDlet程序有三种状态:

1.暂停状态

2.运行状态

3.销毁状态

J2ME程序都是从MIDlet类开始执行,系统在执行MIDlet程序时,首先构造一个MIDlet类型的对象,然后使程序进入到暂停状态,按照生命周期的规定,系统会自动调用MIDlet对象的startApp方法使程序进入到运行状态,开始程序的执行。

下图是运行时显示的画布对象:

图5 屏幕之间的切换

首先,先要创建MIDlet类型的对象,下面我们来看对象的构造方法:

//主程序构造方法

        public GameMIDlet()

        {

                      rs = null;

                      RecordName = “GameRMS”;

                      GameMenu.display = Display.getDisplay(this) ;

                      GameMenu.midlet = this;

        }

在这个构造器中,创建了一个Display对象用于显示,然后,把当前程序的引用传给菜单类中的静态变量。

Display类有两个最主要的作用:

1、  获得屏幕的属性。例如屏幕是否是彩色的,以及支持的颜色数量等信息。

2、  控制屏幕的显示。例如使屏幕显示某个指定界面或者获得当前的显示界面等。

其中,特别是第二个作用使用的更加频繁。

当程序启动的时候,则调用了程序的startApp方法,用来显示画面:

   public void startApp()

        {

          //程序开始,打开数据库,如果数据库没有数据就添加10笔空白数据,最后关闭数据库

          try {

                            rs = RecordStore.openRecordStore(RecordName,true);

                     } catch (Exception e)

                     {

                            System.out.println(“创建数据库失败”);

                     }

                     GameRMS rd = new GameRMS(“player”,0);

                     byte tem[] = rd.encode();

                     try

                     {

                            if(rs.getNumRecords()==0)

                            {    

                                   for(int i=1;i<=11;i++)

                                          {

                                                 try

                                                   {

                                                   rs.addRecord(tem,0,tem.length);

                                                   }catch(Exception e)

                                                   {

                                                      System.out.println(“添加数据失败”);

                                                   }

                                       }

                            }    

                     }

            catch (Exception e1)

                     {

                            System.out.println(“得到数据库大小失败”);

                     }       

                           

                     try

                     {

                         rs.closeRecordStore();

                     }catch(Exception e)

                     {

                           System.out.println(“关闭数据库失败”);

                     }

               //将画面设为主画面MAIN SCREEN

                     new Thread(this).start();

        }

程序开始,打开数据库,如果数据库没有数据就添加10笔空白数据,最后关闭数据库,然后开始一个新的线程,启动菜单。

MIDP中的存储系统是实际为一个类似于数据库的系统,而并不是简单的文件系统,这个系统称为记录管理系统(Record Management System,RMS)。RMS实现数据的持久性管理,提供了数据存储的功能,可以在程序下次启动是再次使用。

记录存储是面向记录的数据库,可把一个记录存储看作一个数据库文件,由许多记录组合而成,这些记录将持久保存并支持跨多个MIDlet的请求。在系统平台的整个常规应用期间,包括重启,更换电池等,MIDlet的记录存储都由系统平台负责维护,系统会尽可能维持记录的完整性。

当调用destroyApp 这个方法的时候,则退出程序。

public void destroyApp(boolean unconditional)

{

        exit();

 }

public void exit()

{

        System.gc();

        notifyDestroyed();

 }

退出程序的时候,要实行垃圾回收,释放掉不再使用的内存。

2.屏幕切换,如图6:

图6 屏幕切换

菜单的图形切换采用的是流程控制器,非常方便,简洁的实现了屏幕画面的切换,下面是关键实现代码:

//导航器

       //设置4个常量分别代表主画面,游戏画面,帮助画面和排行榜画面

       final public static int MY_MENU = 1;

       final public static int MY_GAME = 2;

       final public static int MY_HELP = 3;

       final public static int MY_RMS = 4;

       final public static int MY_ABOUT = 5;

       final public static int MY_SET = 6;

采用静态变量来对画面进行标识。

//流程执行,获得需要画面的对象,并显示在屏幕上

       public static void show()

       {

              switch(current)

              {

                     case MY_MENU:

                            display.setCurrent(MyMenu.getInstance());

                            break;

                     case MY_GAME:

                            display.setCurrent(MyGame.getInstance());

                            break;

                     case MY_SET:

                            display.setCurrent(MySet.getInstance());

                            break;

                     case MY_HELP:

                            display.setCurrent(MyHelp.getInstance());

                            break;

                     case MY_RMS:

                            display.setCurrent(MyRms.getInstance());

                            break;

                     case MY_ABOUT:

                            display.setCurrent(MyAbout.getInstance());

                            break;

              }

       }

这样,采用上面这个函数,非常方便的实现了流程的转换。实现屏幕的切换。

4.4.2 游戏画布MyGame类的实现

在J2ME游戏编程中,Canvas类是最常用的类之一,该类提供了获得手机屏幕属性、绘制界面以及事件处理等很多实用的功能。

Canvas类是Displayable的子类,主要用来需要处理低级事件,例如键盘按键事件等,以及需要绘制屏幕的程序。在实际的使用过程,一般都通过继承Canvas来利用该类提供的功能。Canvas类是一个抽象类,继承该类的时候必须覆盖paint方法。

GameCanvas 类提供了基本的游戏用户接口。除了从Canvas 继承下来的特性(命令,输入事件等)以外,它还提供了专门针对游戏的功能,比如后备屏幕缓冲和键盘状态查询的能力。这也是GameCanvas与Canvas相比所具有的两个优点.来看游戏画面:

当流程控制器转到游戏运行界面时,则用到了游戏画布MyGame类。

下面是游戏截图:

图7 游戏截图

下面来看类的声明:

public class MyGame extends GameCanvas implements Runnable

{

}

我们所用的画布程序,正是继承了GameCanvas这个类,同时派生了Runnable接口,来实现生成一个新的线程的功能。

程序的run方法:

public void run()

       {

              long st = 0;

        long et = 0;

        Graphics g = getGraphics();

        for(stage = 2;stage <= 4;stage++)

        {

               flag = true;

               g.setColor(0,0,0);

               g.fillRect(0,0,getWidth(),getHeight());

               g.setColor(255,255,0);        g.setFont(Font.getFont(Font.FACE_PROPORTIONAL,Font.STYLE_BOLD,Font.SIZE_LARGE));

g.drawString(“第 ” + (stage -1)+ “ 关”,getWidth()/2-30,getHeight()/2-10,Graphics.TOP|Graphics.LEFT);

               flushGraphics();          

               try { Thread.sleep(1000);}

catch (InterruptedException e1) {}

                     CREAT_STAGE();   // 调用创建关卡的方法

               try {Thread.sleep(500);}

               catch (InterruptedException e1) {}

                     mpaint(g);

                     isKey = true;

               while(flag)   //游戏正式开始

               {

                      while(ispause)  //判断是否按下暂停

                      {

                             try{ Thread.sleep(100); }

                             catch(Exception e){}

                      }

                   st = System.currentTimeMillis();

                   StartGameTime = System.currentTimeMillis();

                            INPUT_KEY();       //调用按键方法

                        PENG_ZHUANG();    //调用各种判断和行动的方法

                       movMing();    //调用刷新画面的方法

                   mpaint(g);

                   et = System.currentTimeMillis();

                   if((et-st)<rest)

                   {

                try { Thread.sleep(rest-(et-st)); }

catch(Exception e){}

                   }}

               if(isEndGame)      //判断是否输掉游戏

               {

                      if(islose)

                      {

                             EedGameTime = System.currentTimeMillis();

                             g.setColor(0,0,0);

                             g.fillRect(0,0,getWidth(),getHeight());

                             g.setColor(255,255,0);                  g.setFont(Font.getFont(Font.FACE_PROPORTIONAL,Font.STYLE_PLAIN,Font.SIZE_LARGE));

                             g.drawString(“你失败了!”,getWidth()/2-40,getHeight()/2-20,Graphics.TOP|Graphics.LEFT);

                             flushGraphics();

                             try { Thread.sleep(3000); }

catch(Exception e){}

//                     init_Game();

                       break;

                      }}}

        if(isEndGame)      //判断是否赢得游戏

        {

               if(!islose)

               {

                      EedGameTime = System.currentTimeMillis();

                      g.setColor(0,0,0);

                      g.fillRect(0,0,getWidth(),getHeight());

                      g.setColor(255,255,0);

g.setFont(Font.getFont(Font.FACE_PROPORTIONAL,Font.STYLE_PLAIN,Font.SIZE_LARGE));

                      g.drawString(“你胜利了!”,getWidth()/2-40,getHeight()/2-20,Graphics.TOP|Graphics.LEFT);

                      flushGraphics();

                      try {Thread.sleep(3000); }

catch(Exception e){}

//                 init_Game();

               }

//             GetScore();

               if (score > 0)

               {

                      GameName in = new GameName();

                      GameMenu.display.setCurrent(in);

                      in.start();

               }

               else

               {

                      GameMenu.current = GameMenu.MY_MENU;

                      GameMenu.show();

               }} } }

在线程中,通过  

1、调用创建关卡的方法CREAT_STAGE();

2、判断是否按下暂停while(ispause)

3、调用按键方法INPUT_KEY();

4、调用各种判断和行动的方法PENG_ZHUANG();

5、调用刷新画面的方法movMing();

6、判断是否输掉游戏if(isEndGame)

7、判断是否赢得游戏if(isEndGame)

来对游戏进行不断监控。

4.4.3 玩家精灵GamePlayer类的实现

 Sprite类是继承自Layer的用于存储多帧的基本可视元素。不同的frame可交相显示,构成动态的效果。图片可翻转、颠倒、由一个主角图片就可以方便的得到所有方向的显示状态,相比原先只能使用Canvas绘图,需要将所有方向的主角图像都绘制在png图像中简化了许多。Sprite也可以从整合的图像中读图,读图时将把大图分解为若干等宽等高的小图。每个小图按照其排列顺序有相应的序号,在程序中调用其序号,就可以绘制出相应的图片。本程序中的玩家、怪物都由Sprite继承得到。在有些情况下,控制主角的翻转,尤其是多幅图片配合显示的过程,如果将多图的共享定位点设置在通常的左上角,将很不容易控制,因为许多翻转都是以其他点为参考电的(比如,中心点)。由此,引入参考点的概念。参考点由defineReferencePixel函数确定未翻转图片状态时的坐标。默认是(0,0)点,如果需要,可将参考点设置在画面边界之外。

在本程序中,由于J2ME中提供的Sprite类功能有限,所以我自己写了一个GamePlayer类来继承Sprite类,扩充了更多的功能。

public class GamePlayer extends Sprite

{

}

在游戏中和背景的碰撞检测始终是个难点,在本程序中是这样实现的:

public void isPeng(int x,int y,int Array[][],int N)

{

for(int i = 0; i < 20; i++)

{                  

for(int j = 0; j< 18; j++)

       {                  

              if(Array[i][j] == N)

              {    

                     if (!MyGame.isU)

                     {

                            if( Length * j <= x + this.getWidth() /2 && Length *(j + 1) >= x + this.getWidth() /2  && 10 + Length * i <= y  && 10 + Length *(i + 1) >= y)

                            {

                                   this.setPosition(this.getX(),  20 + Length *(i + 1));

                                          System.out.println(“UP: ”+getY());

                            }

//左

                            if( Length * j <= x + 1 && Length *(j + 1) >= x + 1 && 10 + Length * i <= y + this.getHeight()/2 && 10 + Length *(i + 1) >= y + this.getHeight()/2)

                            {

                                   this.setPosition( Length * (j + 1),this.getY());

                                   }

                                   if( Length * j <=x + this.getWidth() - 1 && Length *(j + 1) >= x + this.getWidth() –1 && 10 + Length * i <= y + this.getHeight()/2 && 10 + Length *(i + 1) >= y + this.getHeight()/2)

                            {

                            this.setPosition(Length * j - this.getWidth() ,this.getY());

}

                            }

                            //左下

                     if( Length * j <= x + 3&& Length *(j + 1) >= x + 3 && 10 + Length * i <= y + this.getHeight() && 10 + Length *(i + 1) >= y + this.getHeight())

                     {

                            this.setPosition(this.getX(),  Length * (i -1));

}

                     //右下

                     if( Length * j <= x +this.getWidth() -3 && Length *(j + 1) >= x + this.getWidth() -3  && 10 + Length * i <= y + this.getHeight() && 10 + Length *(i + 1) >= y + this.getHeight())

                     {

this.setPosition(this.getX(),  Length * (i - 1));

Length * i:+Length * (i-1));

                     }

      

              }           

}           

通过查看背景数组和玩家坐标,来实现和背景的碰撞检测。

4.4.5 SoundEffects类的实现

声音效果是一个游戏中必不可少的部分,没有了生动的音乐效果,游戏的体验就会大打折扣。在我们的游戏中当然也不能没有声音。

在我们的游戏程序中的PlayMusic类就是游戏中的音效类。该类的主要功能为使用MIDP2.0 Media API播放游戏中的声音效果:背景音乐和游戏结束的提示音。

我们用private Player createPlayer(String filename, String f, int i) 创建播放器。该方法中的filename是要播放声音文件的相对路径,f是播放音乐文件的格式,i用来控制该音乐的播放次数。在播放某个声音之前我们都需要调用stop方法来中止声音(如果声音未播放则该方法无效)。游戏中的声音我们用的startPlayer方法来播放。在需要播放游戏中的声音时我们就调用该类中相应的方法。

5 程序设计过程中遇到的一些重要问题

5.1 关于碰撞的问题

在游戏中最先要解决的也是最重要的问题就是碰撞检测的实现以及碰撞后表现出的效果。在弹球游戏中碰撞检测分为俩种:精灵与精灵之间的碰撞检测以及精灵与方块图层之间的碰撞检测。

精灵与精灵之间的碰撞检测可以直接调用Sprite类中的collidesWith()方法或者自己重新Sprite类中的collidesWith()方法并调用来进行碰撞检测。在本游戏程序中我们使用的是后者。这点表现效果还是很不错的。

再者就是精灵与图层之间的碰撞检测即主角与砖块之间的碰撞检测。我们精灵中重写的collidesWith()方法来检测它们之间的碰撞检测,这个时候我们就存在一个怎么样判断与小球碰撞的是哪个砖块的问题。我所采用的是通过查看背景数组和玩家坐标,来实现和背景的碰撞检测,但是效果不是很理想。到目前在我们经过的多次测试中还没有出现判断失误以及无法判断等错误。可是,效果不理想,我还将继续探索更精更有效的算法。

5.2 关于游戏画面的显示问题

在后期测试中发现游戏在暂停后继续游戏时,游戏画面又恢复为游戏开始的画面,而不是暂停时的游戏画面,经过多次调试后发现问题在MyGameCanvas类。

在仔细阅读了相关的资料后发现线程的创建和运行是通过调用它本身的函数start()来调动run()函数开始运行的,当run ()方法执行完毕后,线程就结束了。一旦一个线程执行完毕,这个实例就不能再重新启动,只能重新生成一个新实例,再启动一个线程。鉴于此,我们决定在MyGameCanvas类的run()内设置一个暂停标志量pause。

这样就实现了游戏的暂停(挂起)功能。当继续游戏后,游戏画面就是我们暂停时的画面。

结    论

本程序设计实现了手机上以J2ME为平台的堡垒游戏的开发,具有一定的可玩性和复杂性。经过了细心的调试和排错解决了绝大部分的问题。

通过对“沙丘魔堡”这个手机游戏的构想,设计,代码的编写和调试,我进一步学习了J2ME这个平台,并对手机游戏编程有了新认识。就我所做的模块来说,我对J2ME中的菜单、声音、画布等技术有了更进一步的认识。一个简单的菜单的背后却有着不同的写法以及一些复杂的技术。我现在已经做出的是游戏的1.0版本,实现了游戏的基本功能,离一个完全意义上的手机游戏还有一段的距离:

1.游戏只在模拟器上运行,还没有经过真机调试;

2.游戏的选项界面没有经过任何效果美化;

3.能调节声音的大小及开关背景音乐。

这款游戏算是休闲类的一款小游戏,如果能继续完善游戏的菜单功能,增加游戏可玩性等,那这款游戏将会是一款比较具有人气的手机游戏。

参考文献

[1] 胡虚怀,杨志和,李焕.J2ME移动设备程序设计[M].北京:清华大学出版社,2005。

[2] 李振鹏,龚剑.J2ME手机游戏开发技术详解[M]. 北京:清华大学出版社,2006。

[3] 詹建飞.J2ME开发精解[M].北京:电子工业出版社,2006。

[4] 施铮.J2ME技术参考手册[M].北京:电子工业出版社,2004。

[5] 微型爪哇人.JAVA手机开发[M].北京:中国铁道出版社,2003。

[6] 闻怡洋.J2ME MIDP 1.0/2.0无线设备编程指南[M].北京:北京大学出版社,2004。

参考资料:

java毕业设计——java手机游戏(堡垒)的设计与开发(源代码+论文).zipJava毕业设计174例,包含部署视频-CSDN博客

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

毕业课程设计

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值