当前位置:文档之家› J2ME 游戏程序开发实例精讲详解

J2ME 游戏程序开发实例精讲详解

J2ME 游戏程序开发实例精讲详解
J2ME 游戏程序开发实例精讲详解

J2ME 游戏程序开发实例精讲详解

一、序言

昨天在网上闲逛,发现一篇讲解用delphi实现华容道游戏的文章,颇受启发.于是,产生了将华容道游戏移植到手机中去的冲动.现在手机游戏琳琅满目,不一而足,华容道的实现版本也很多.正巧不久前笔者

对J2ME下了一番功夫,正想借这个机会小试牛刀。选用J2ME的原因还有一个就是目前Java开发大行

其到,无线增殖业务迅猛发展,J2ME的应用日渐活跃起来,也希望我的这篇文章能够为J2ME知识的普

及和开发团队的壮大推波助澜。由于长期受ISO规范的影响,这次小试牛刀我也打算遵照软件工程的要求,并采取瀑布式的开发模式来规划项目,也希望借此机会向各位没有机会参与正式项目开发的读者介绍

一下软件开发的流程。

这里我们先定义项目组的人员体制(其实只有我一个人):技术调研、需求分析、概要设计、详细设计、编码、测试均有笔者一人担任;美工这里我找了个捷径,盗用网上现成的图片,然后用ACDSee把它由

BMP转换成PNG格式(我出于讲座的目的,未做商业应用,应该不算侵权吧);至于发布工作,由于缺少OTA服务器,此项工作不做(但是我会介绍这步如何做)。

接下来,我们规划一下项目实现的时间表,以我个人经验,设想如下:技术调研用2天(这部分解决项目

的可行性和重大技术问题,时间会长一些),需求分析用半天(毕竟有现成的东东可以参照,只要理清思路

就行了,况且还有很多以前用过的设计模式和写好的代码),概要设计再用半天(有了需求,概要只不够是

照方抓药),详细设计要用2天(这一步要把所有的问题想清楚,还要尽可能的准确描述出来),编码用2天(其实1天就够了,技术已经不是问题,多计划出一天来应付突发事件),测试用2天(测试应该至少占全部项目的四分之一,不过这个项目只是一个Demo,也太简单了),发布也要用上半天(尽管我们不去实际发

布它,但是还要花点时间搞清楚应该如何做),最后就是项目总结和开庆功会(时间待定)。

二、利其器

“公欲善其事,必先利其器”,做项目之前第一步是前期调研.我们要做的华容道这个东东随处可见,我们

要调研的是两个方面:

1. 游戏的内容:游戏本身很简单,就是有几个格子,曹操占据其中一个较大的格子,然后被几个格子包围,这些格子形状不一定相同,但是挡住了曹操移动的方向.游戏者需要挪动这些格子最终把曹操移动到一个

指定的位置才算是过关.更具体的分析我们放在后面需求分析和概要设计中讨论。

2. 技术储备:谈到技术,这里简单介绍一下J2ME.Java有三个版本,分别是J2ME(微型版).J2SE(标

准版).J2EE(企业版).J2ME是一个标准,采用3层结构设计.最低层是配置层(Configuration)也

就是设备层,其上是简表层(Profile),再上是应用层(Application).MIDP就是移动信息设备简表,目前

主流手机支持MIDP1.0,最新的是MIDP2.0,它比前一个版本增加了对游戏的支持,在

javax.microedition.lcdui.game包中提供了一些类来处理游戏中的技术,比如我们后面会用到的Sprite类,

它是用来翻转图片的.权衡再三,笔者决定使用MIDP2.0来做开发.首先需要安装一个J2ME的模拟器,我们就用Sun公司的WTK2.0,我觉得Sun的东西最权威.当然你也可以使用Nokia.Siemens或是Motolora等其他模拟器,但是他们的JDK不尽相同,写出来的程序移植是比较麻烦的.

Sun公司的WTK2.0可以到搜索引擎寻找下载,当然要想成功下载的前提是你要先注册成为Sun的会员(其实这样对你是有好处的).当下来之后就是按照提示一步一步的安装.安装好了之后,我们用一个"Hello World"程序开始你的J2ME之旅.我们启动WTK2.0工具集中的KToolBar,然后点击New Project 按钮,在弹出的输入框中输入Project Name为HelloWorld,MIDlet Class Name为Hello,然后点击Create Project,开始生成项目,工具会弹出MIDP配置简表,这里接受生成的默认值(以后还可以修改)点击OK,工具提示我们把写好的Java源程序放到[WTK_HOME]\apps\HelloWorld\src目录之下.我们编辑如下代码,并保存在上述目录之下,文件名为Hello.java。

专门用于管理图片,它有createImage()方法,可以直接读取图片文件(J2ME只支持PNG格式的图片),也可以截取已有的图片的一部分(这样我们可以把很多图片放在一起,然后一张一张的截下来,好处是节

省存储空间和文件读取时间,对于手机这两者都是性能的瓶颈).

J2ME还有一个Graphics类,专门用于绘图,它有drawImage()方法,可以把一副图片在指定的位置上显示出来,它还有drawRect()方法和setColor()方法,这两个方法在后面我们进行游戏操作时就会用到,这

里先交代一下.有了图片和绘图的方法,还需要知道把图画到谁身上,J2ME提供了一个Canvas类,字

面意思就是画布,它有一个paint()方法用于刷新页面,还有一个repaint()方法用于调用paint()方法.听着有些糊涂是吧,不要紧,我来结合具体程序讲解一下.为了今后编程的方便,我们创建两个类Images和Draw,Images用于保存一些常量值和图片,Draw主要是用于画图,这两个类的源代码如下。

Images类的源代码如下:

Draw类主要是用来在画布上画出图形,它有两个paint方法,这是很常见的函数重载。但是程序中实际

上只用到了4个参数的paint方法,它直接获得要画图片的相对坐标位置信息,然后调用5个参数的paint 方法。5个参数的paint方法将相对坐标位置信息转换成绝对位置,并实际调用Graphics.drawImage()方法,将Images中的图片画了出来。这种实现方法的好处是灵活和便于扩展,但你需要画图的位置并不能

够对应到格子中的相对坐标位置时,你就可以直接调用5个参数的paint方法,而不必再去修改这各类;

但你添加新的图片时,只要在Images中增加对应的常量,然后向Draw中5个参数的paint方法添加一

条处理就可以了。写到这里,两天的时间刚好用完。

三、需求分析

这部分叫做需求分析,听起来挺吓人的,其实就是搞清楚我们要做什么,做成什么样,那些不做。下面我引领着大家共同来完成这一步骤。首先,我们要做一个华容道的游戏,华容道的故事这里不再赘述了,但其中的人物在这里限定一下,如上面Images类里的定义,我们这个版本只提供曹操(Caocao)、关羽(Guanyu)、张飞(Zhangfei)、赵云(Zhaoyun)、黄忠(Huangzhong)、马超(Machao)和卒(Zu)。我们这里也

限定一下游戏的操作方法:首先要通过方向键选择一个要移动的区域(就是一张图片),被选择的区域用黑

色方框框住;选好后按Fire键(就是确定键)将这块区域选中,被选中的区域用绿色方框框住;然后选择要

移动到的区域,此时用红色方框框住被选择的区域;选好要移动到的区域之后按Fire键将要移动的区域(图片)移到要移动到的区域,并去掉绿色和红色的方框。这里需要强调的概念有选择的区域、选中的区域、要移动的区域和要移动到的区域,这四个概念请读者注意区分,当然也应当把这一部分记入数据字典之中。

为了使文章的重点突出(介绍如何制作一个J2ME的收集游戏),我们这里限定一些与本主题无关的内容暂

不去实现:过关之后的动画(实现时要用到TimerTask或Thread类,后续的系列文章中我会详细介绍动

画方面的知识)、关面之间的切换(其实很简单,当完成任务之后重新再做一边)、暂停和保存等操作(这部

分的内容介绍的资料很多,我也写不出什么新的东东来,难免抄袭,故此免掉)。

需求分析基本完成,离下午还有一段时间,马上动手用ACDSee把从网上找来的BMP文件,调整其大小为271*177(我的这个图片是两个部分合在一起,所以比手机实际屏幕大了),另存为PNG格式。半天时

间刚刚好,不但搞清楚了要做的东东,还把要用的图片准备好了。

四、概要设计

概要设计是从需求分析过渡到详细设计的桥梁和纽带,这一部分中我们确定项目的实现方法和模块的划分。我们决定将整个项目分成五个部分,分别是前面介绍的Images、Draw,还有Map和Displayable1和MIDlet1。Images和Draw类功能简单、结构固定,因此很多项目我们都使用这两各类,这里直接拿来改

改就能用了,前面已经介绍过这里不再赘述。Map类是用来从外部文件读入地图,然后保存在一个数组

之中,这部分的内容是我们在本阶段讨论的重点。Displayable1是一个继承了Canvas类的画布,它用来

处理程序的主要控制逻辑和一部分控制逻辑所需的辅助函数,主要函数应该包括用来绘图的paint()函数、用来控制操作的keyPressed()函数、用来控制选择区域的setRange()函数、用来控制选择要移动到区域

的setMoveRange()函数、用来移动选中区域的Move()函数和判断是否完成任务的win()函数,更具体的分析,我们放到详细设计中去细化。MIDlet1实际上就是一个控制整个J2ME应用的控制程序,其实也没有什么可特别的,它和我们前面介绍的"Hello World"程序大同小异,这里就不展开来说了,后面会贴出它的全部代码。

Map类主要应该有一个Grid[][]的二维数组,用来存放华容道的地图,还应该有一个read_map()函数用来从外部文件读取地图内容填充Grid数据结构,再就是要有一个draw_map()函数用来把Grid数据结构中的地图内容转换成图片显示出来(当然要调用Draw类的paint方法)。说到读取外部文件,笔者知道有两种方法:一种是传统的定义一个InputStream对象,然后用getClass().getResourceAsStream()方法取得输入流,然后再从输入流中取得外部文件的内容,例如

再下面要实现的setRange()函数和setMoveRange()函数,这两个函数用来设置要移动的区域和要移动到的区域,我的思路就是利用前面在Images类中介绍过的地图组合标记常量,当移动到地图组合标记常量时,根据该点地图中的值做逆向变换找到相应的地图标记常量,然后设置相应的loc、SelectArea和MoveArea,其中setMoveRange()函数还用到了一个辅助函数isInRange(),isInRange()函数是用来判断给

定的点是否在已选中的要移动的区域之内,如果isInRange()的返回值是假并且该点处的值不是空白就表明要移动到的区域侵犯了其他以被占用的区域。有了setRange()和setMoveRange()函数,Move()函数就水到渠成了,Move()函数将要移动的区域移动到要移动到的区域,在移动过程中分为三步进行:

第一.复制要移动的区域;

第二.将复制出的要移动区域复制到要移动到的区域(这两步分开进行的目的是防止在复制过程中覆盖掉要移动的区域);

第三.用isInRange2()判断给定的点是否在要移动到的区域内,将不在要移动到的区域内的点设置成空白。下面我们详细的分析一下keyPressed()函数的实现方法:首先,keyPressed()函数要处理按键的上下左右和选中(Fire),在处理时需要用Canvas类的getGameAction函数来将按键的键值转换成游戏的方向,这样可

以提高游戏的兼容性(因为不同的J2ME实现,其方向键的键值不一定是相同的)。

接下来,分别处理四个方向和选中.当按下向上时,先判断是否已经选定了要移动的区域(即this.selected是

否为真),如果没有选中要移动区域则让光标向上移动一格,然后调用setRange()函数设置选择要移动的区域,再调用repaint()函数刷新屏幕,否则如果已经选中了要移动的区域,就让光标向上移动一格,然后调用setMoveRange()函数判断是否能够向上移动已选中的区域,如果能移动就调用repaint()函数刷新屏幕,如果不能移动就让光标向下退回到原来的位置。

当按下向下时,先判断是否已经选定了要移动的区域,如果没有选中要移动的区域则判断当前所处的区域是否为两个格高,如果是两个格高则向下移动两格,如果是一个格高则向下移动一格,接着再调用setRange()函数设置选择要移动的区域,而后调用repaint()函数刷新屏幕,否则如果已经选中了要移动的区域,就让光标向下移动一格,然后调用setMoveRange()函数判断是否能够向下移动已选中的区域,如果能移动就调用repaint()函数刷新屏幕,如果不能移动就让光标向上退回到原来的位置.按下向左时情况完全类似向上的情况,按下向右时情况完全类似向下的情况,因此这里不再赘述,详细情况请参见程序的源代码。

当按下选中键时,先判断是否已经选中了要移动的区域,如果已经选中了要移动的区域就调用Move()函数完成由要移动的区域到要移动到的区域的移动过程,接着调用repaint()函数刷新屏幕,然后将已选择标记置成false,继续调用win()函数判断是否完成了任务,否则如果还没有选定要移动的区域则再判断当前选中区域是否为空白,如果不是空白就将选中标记置成true,然后刷新屏幕.这里介绍一个技巧,在开发程序遇到复杂的逻辑的时候,可以构造一格打印函数来将所关心的数据结构打印出来以利调试,这里我们就构造一个PrintGrid()函数,这个函数纯粹是为了调试之用,效果这得不错.至此我们完成了编码前的全部工作。

六、编码

整个项目共有五个类,有四个类的代码前面已经介绍过了,而且是在其他项目中使用过的相对成熟的代码.现在只需全力去实现Displayable1类.Displayable1类的代码如下:

相关主题
文本预览
相关文档 最新文档