1、J2ME 游戏程序开发实例详解一、序言这里我们先定义项目组的人员体制(其实只有我一个人):技术调研、需求分析、概要设计、详细设计、编码、测试均有笔者一人担任;美工这里我找了个捷 径,盗用网上现成的图片,然后用 ACDSee 把它由 BMP 转换成 PNG 格式(我出于讲座的目的,未做商业应用,应该不算侵权吧);至于发布工作,由于缺少 OTA 服务器,此项工作不做(但是我会介绍这步如何做)。接下来,我们规划一下项目实现的时间表,以我个人经验,设想如下:技术调研用 2 天(这部分解决项目的可行性和重大技术问题,时间会长一些),需求分 析用半天(毕竟有现成的东东可以参照,只要理清思路就行了,况且还有
2、很多以前用过的设计模式和写好的代码),概要设计再用半天(有了需求,概要只不够是照 方抓药),详细设计要用 2 天(这一步要把所有的问题想清楚,还要尽可能的准确描述出来),编码用 2 天(其实 1 天就够了,技术已经不是问题,多计划出一天来 应付突发事件),测试用 2 天(测试应该至少占全部项目的四分之一,不过这个项目只是一个 Demo,也太简单了),发布也要用上半天(尽管我们不去实际发布 它,但是还要花点时间搞清楚应该如何做),最后就是项目总结和开庆功会(时间待定)。二、利其器“公欲善其事,必先利其器”,做项目之前第一步是前期调研我们要做的华容道这个东东随处可见,我们要调研的是两个方面:1.
3、游戏的内容:游戏本身很简单,就是有几个格子,曹操占据其中一个较大的格子,然后被几个格子包围,这些格子形状不一定相同,但是挡住了曹操移动的方向游 戏者需要挪动这些格子最终把曹操移动到一个指定的位置才算是过关更具体的分析我们放在后面需求分析和概要设计中讨论。2. 技术储备:谈到技术,这里简单介绍一下 J2ME.Java 有三个版本,分别是 J2ME(微型版).J2SE(标准版).J2EE(企业版)J2ME 是一 个标准,采用层结构设计最低层是配置层(Configuration)也就是设备层,其上是简表层(Profile),再上是应用层 (Application).MIDP 就是移动信息设备简表,目
4、前主流手机支持 MIDP1.0,最新的是 MIDP2.0,它比前一个版本增加了对游戏的支 持,在 javax.microedition.lcdui.game 包中提供了一些类来处理游戏中的技术,比如我们后面会用到的Sprite 类,它是用来 翻转图片的.权衡再三,笔者决定使用 MIDP2.0 来做开发首先需要安装一个 J2ME 的模拟器,我们就用Sun 公司的 WTK2.0,我觉得 Sun 的东西 最权威当然你也可以使用 Nokia.Siemens 或是 Motolora 等其他模拟器,但是他们的JDK 不尽相同,写出来的程序移植是比较麻烦的Sun 公司的 WTK2.0 可以到搜索引擎寻找下载
5、,当然要想成功下载的前提是你要先注册成为 Sun 的会员(其实这样对你是有好处的)当下来之后就 是按照提示一步一步的安装安装好了之后,我们用一个“Hello World“程序开始你的 J2ME 之旅我们启动 WTK2.0 工具集中的 KToolBar,然后点击 New Project 按钮,在弹出的输入框中输入 Project Name 为 HelloWorld,MIDlet Class Name 为 Hello,然后点击 Create Project,开始生成项目,工具会弹出 MIDP 配置简表,这里接受生成的默认值(以后还可以修改)点击 OK,工具提示我们把写好的 Java 源程序放到 W
6、TK_HOMEappsHelloWorldsrc 目录之下我们编辑如下代码,并保存在上述目录之下,文件名为 Hello.java。import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class Hello extends MIDlet private Display display; public Hello() display =Display.getDisplay(this); public void startApp() TextBox t = new TextBox(“Hello“,
7、“Hello“,256,0); display.setCurrent(t); public void pauseApp() public void destroyApp(boolean unconditional) 保存好了之后,点击 Build 按钮,工具会为你编译程序,如无意外再点击 Run 按钮,会弹出一个手机界面,剩下的就不用我教了吧(用鼠标对手机按键 一顿狂点)。呵呵,你的第一个 J2ME 程序已经 OK 了.什么?你还一点都没懂呢(真是厉害,不懂都能写出 J2ME 程序来,果然是高手)我这里主要是介绍 WTK2.0 工具的使用,程序并不是目的,不懂的话后面还会有详细的解说,这里只是
8、带你上路什么?你不懂 Java!那也没有关系,后面我再讲得细一点。跳过 J2ME,我们先来讲点游戏的理论具体到华容道这个游戏,主要有三个方面,贴图游戏操作逻辑判断这里讲讲贴图,其他两方面放在概要设计 和详细设计里讲所谓的贴图,其实就是画图,就是在要显示图形的位置上输出一副图片,(要是牵扯到动画就要麻烦一些,可以使用 TimerTask.Thread 或 Rannable 之类的技术),这副图片可以是事先准备好的也可以是临时处理的在 J2ME 中有一个 Image 类,专 门用于管理图片,它有 createImage()方法,可以直接读取图片文件(J2ME 只支持PNG 格式的图片),也可以截取
9、已有的图片的一部分(这样我 们可以把很多图片放在一起,然后一张一张的截下来,好处是节省存储空间和文件读取时间,对于手机这两者都是性能的瓶颈)J2ME 还有一个 Graphics 类,专门用于绘图,它有 drawImage()方法,可以把一副图片在指定的位置上显示出来,它还有 drawRect()方法和 setColor()方法,这两个方法在后面我们进行游戏操作时就会用到,这里先交代一下有了图片和绘图的方法,还需要知道 把图画到谁身上,J2ME 提供了一个 Canvas 类,字面意思就是画布,它有一个 paint()方法用于刷新页面,还有一个 repaint()方法用于调 用 paint()方法
10、听着有些糊涂是吧,不要紧,我来结合具体程序讲解一下为了今后编程的方便,我们创建两个类 Images 和 Draw,Images 用于保存一些常量值和图片,Draw 主要是用于画图,这两个类的源代码如下。Images 类的源代码如下:package huarongroad; import javax.microedition.lcdui.*; import javax.microedition.lcdui.game.*; public class Images /保存常量 /绘图位置常量 public static final int UNIT = 32;/方块的单位长度 public stat
11、ic final int LEFT = 10;/画图的左边界顶点 public static final int TOP = 9;/画图的上边界顶点 /地图位置常量 public static final int WIDTH = 4;/地图的宽度 public static final int HEIGHT = 5;/地图的高度 /地图标记常量 public static final byte CAOCAO = (byte) a; A href=“file:/曹“file:/曹/A操的地图标记 public static final byte MACHAO = (byte) b;/马超的地图标
12、记 public static final byte HUANGZHONG = (byte) c;/黄忠的地图标记 public static final byte GUANYU = (byte) d;/关羽的地图标记 public static final byte ZHANGFEI = (byte) e;/张飞的地图标记 public static final byte ZHAOYUN = (byte) f;/赵云的地图标记 public static final byte ZU = (byte) g;/卒的地图标记 public static final byte BLANK = (by
13、te) h;/空白的地图标记 public static final byte CURSOR = (byte) i;/光标的地图标记 /地图组合标记常量 public static final byte DLEFT = (byte) 1; A href=“file:/组“file:/组/A合图形左边标记 public static final byte DUP = (byte) 2; A href=“file:/组“file:/组/A合图形上边标记 public static final byte DLEFTUP = (byte) 3; A href=“file:/组“file:/组/A合图形
14、左上标记 /图片常量 public static Image image_base;/基本图片 public static Image image_Zhaoyun;/赵云的图片 public static Image image_Caocao;/曹操的图片 public static Image image_Huangzhong;/黄忠的图片 public static Image image_Machao;/马超的图片 public static Image image_Guanyu;/关羽的图片 public static Image image_Zhangfei;/张飞的图片 publi
15、c static Image image_Zu;/卒的图片 public static Image image_Blank;/空白的图片 public static Image image_Frame;/游戏框架的图片 public Images() /构造函数 public static boolean init() /初始化游戏中用到的图片 try image_base = Image.createImage(“/huarongroad/BITBACK.png“); image_Frame = Image.createImage(image_base, 126, 0, 145, 177,
16、Sprite.TRANS_NONE); /Sprite 类是用来翻转图片的,是 MIDP2.0 新新增加的支持游戏的特性 image_Zhaoyun = Image.createImage(image_base, 0, 0, UNIT, 2 * UNIT, Sprite.TRANS_NONE); image_Caocao = Image.createImage(image_base, UNIT, 0, 2 * UNIT, 2 * UNIT, Sprite.TRANS_NONE); image_Huangzhong = Image.createImage(image_base, 3 * UNIT
17、, 0, UNIT, 2 * UNIT, Sprite.TRANS_NONE); image_Machao = Image.createImage(image_base, 0, 2 * UNIT, UNIT, 2 * UNIT, Sprite.TRANS_NONE); image_Guanyu = Image.createImage(image_base, UNIT, 2 * UNIT, 2 * UNIT, UNIT, Sprite.TRANS_NONE); image_Zhangfei = Image.createImage(image_base, 3 * UNIT, 2 * UNIT, U
18、NIT, 2 * UNIT, Sprite.TRANS_NONE); image_Zu = Image.createImage(image_base, 0, 4 * UNIT, UNIT, UNIT, Sprite.TRANS_NONE); image_Blank = Image.createImage(image_base, 1 * UNIT, 4 * UNIT,UNIT, UNIT, Sprite.TRANS_NONE); return true; catch (Exception ex) return false; Draw 类的源代码如下:package huarongroad; im
19、port javax.microedition.lcdui.*; public class Draw /绘制游戏中的图片 public Draw(Canvas canvas) /构造函数 public static boolean paint(Graphics g, byte img, int x, int y) /在地图的 x,y 点绘制 img 指定的图片 try paint(g, img, x, y, Images.UNIT);/把地图 x,y 点转化成画布的绝对坐标,绘图 return true; catch (Exception ex) return false; public st
20、atic boolean paint(Graphics g, byte img, int x, int y, int unit) try switch (img) case Images.CAOCAO:/画曹操 /变成绝对坐标,并做调整 g.drawImage(Images.image_Caocao, Images.LEFT + x * unit, Images.TOP + y * unit, Graphics.TOP | Graphics.LEFT); break; case Images.GUANYU:/画关羽 g.drawImage(Images.image_Guanyu, Images
21、.LEFT + x * unit, Images.TOP + y * unit, Graphics.TOP | Graphics.LEFT); break; case Images.HUANGZHONG:/画黄忠 g.drawImage(Images.image_Huangzhong, Images.LEFT + x * unit, Images.TOP + y * unit, Graphics.TOP | Graphics.LEFT); break; case Images.MACHAO:/画马超 g.drawImage(Images.image_Machao, Images.LEFT +
22、x * unit, Images.TOP + y * unit, Graphics.TOP | Graphics.LEFT); break; case Images.ZHANGFEI:/画张飞 g.drawImage(Images.image_Zhangfei, Images.LEFT + x * unit, Images.TOP + y * unit, Graphics.TOP | Graphics.LEFT); break; case Images.ZHAOYUN:/画赵云 g.drawImage(Images.image_Zhaoyun, Images.LEFT + x * unit,
23、Images.TOP + y * unit, Graphics.TOP | Graphics.LEFT); break; case Images.ZU:/画卒 g.drawImage(Images.image_Zu, Images.LEFT + x * unit, Images.TOP + y * unit, Graphics.TOP | Graphics.LEFT); break; case Images.BLANK:/画空白 g.drawImage(Images.image_Blank, Images.LEFT + x * unit, Images.TOP + y * unit, Grap
24、hics.TOP | Graphics.LEFT); break; case Images.CURSOR:/画光标 g.drawRect(Images.LEFT + x * unit, Images.TOP + y * unit,Images.UNIT,Images.UNIT); break; return true; catch (Exception ex) return false; 其中 Images 类存的是绘图位置常量(也就是在画图时每个格子的长度和相对坐标原点位置要进行的调整)、地图位置常量(地图的长、宽),地图标记 常量(人物对应的记号),地图组合标记常量(后面会细说),图片常量
25、(存放人物的图片);Draw 类主要负责在制定的位置画出人物图片。下面我来说说 Images 类中的地图标记常量和地图组合标记常量。为了能够灵活的安排各个关面的布局,我们决定把游戏布局的信息存储在外部文件中,然后程序启动后把它 读进来。这样我们制定了一套存储图片的代码,这就是地图标记常量,如上面 Images 类中定义的 Caocao(曹操)用 a 字符来表示,当程序读到 a 字符时就 能将它转化成曹操对应的图片,并在读到 a 字符的位置上进行显示。但是从实际观察中我们发现所有的图片并不是统一大小的,有的占 4 个格子,有的占 2 个格子, 还有的占 1 个格子,而且即便同是占两个格子的图片还
26、有横、竖之分。有鉴于此,我们引入了地图组合标记常量,就是说在遇到占有多个格子的时候,值 1(也就是 Images.LEFT)表示它的左边是一个真正的地图标记,值 2(也就是 Images.UP)表示它的上边是一个真正的地图标记,值 1(也就是 Images.LEFTUP)表示它的左上边是一个真正的地图标记。地图组合标记常量其实就是用来占位置的,与实际显示无关,当后面我们将到移动时还会再 来分析组合标记的使用。Draw 类主要是用来在画布上画出图形,它有两个 paint 方法,这是很常见的函数重载。但是程序中实际上只用到了 4 个参数的paint 方法,它直 接获得要画图片的相对坐标位置信息,然
27、后调用 5 个参数的 paint 方法。5 个参数的 paint 方法将相对坐标位置信息转换成绝对位置,并实际调用 Graphics.drawImage()方法,将 Images 中的图片画了出来。这种实现方法的好处是灵活和便于扩展,但你需要画图的位置并不能够对应 到格子中的相对坐标位置时,你就可以直接调用 5 个参数的 paint 方法,而不必再去修改这各类;但你添加新的图片时,只要在 Images 中增加对应的常 量,然后向 Draw 中 5 个参数的 paint 方法添加一条处理就可以了。写到这里,两天的时间刚好用完。三、需求分析这部分叫做需求分析,听起来挺吓人的,其实就是搞清楚我们要做
28、什么,做成什么样,那些不做。下面我引领着大家共同来完成这一步骤。首先,我们要做一 个华容道的游戏,华容道的故事这里不再赘述了,但其中的人物在这里限定一下,如上面Images 类里的定义,我们这个版本只提供曹操(Caocao)、关 羽(Guanyu)、张飞(Zhangfei)、赵云(Zhaoyun)、黄忠(Huangzhong)、马超(Machao)和卒(Zu)。我们这里也 限定一下游戏的操作方法:首先要通过方向键选择一个要移动的区域(就是一张图片),被选择的区域用黑色方框框住;选好后按 Fire 键(就是确定键)将这块 区域选中,被选中的区域用绿色方框框住;然后选择要移动到的区域,此时用红色方
29、框框住被选择的区域;选好要移动到的区域之后按 Fire 键将要移动的区域 (图片)移到要移动到的区域,并去掉绿色和红色的方框。这里需要强调的概念有选择的区域、选中的区域、要移动的区域和要移动到的区域,这四个概念请读者注 意区分,当然也应当把这一部分记入数据字典之中。为了使文章的重点突出(介绍如何制作一个 J2ME 的收集游戏),我们这里限定一些与本主题无关的内容暂不去实现:过关之后的动画(实现时要用到 TimerTask 或 Thread 类,后续的系列文章中我会详细介绍动画方面的知识)、关面之间的切换(其实很简单,当完成任务之后重新再做一边)、暂停 和保存等操作(这部分的内容介绍的资料很多,
30、我也写不出什么新的东东来,难免抄袭,故此免掉)。需求分析基本完成,离下午还有一段时间,马上动手用 ACDSee 把从网上找来的 BMP 文件,调整其大小为 271*177(我的这个图片是两个部分合在一起,所以比手机实际屏幕大了),另存为 PNG 格式。半天时间刚刚好,不但搞清楚了要做的东东,还把要用的图片准备好了。四、概要设计概要设计是从需求分析过渡到详细设计的桥梁和纽带,这一部分中我们确定项目的实现方法和模块的划分。我们决定将整个项目分成五个部分,分别是前面介 绍的 Images、Draw,还有 Map 和 Displayable1 和 MIDlet1。Images 和 Draw 类功能简单
31、、结构固定,因此很多项目我们都 使用这两各类,这里直接拿来改改就能用了,前面已经介绍过这里不再赘述。Map 类是用来从外部文件读入地图,然后保存在一个数组之中,这部分的内容是我们 在本阶段讨论的重点。Displayable1 是一个继承了 Canvas类的画布,它用来处理程序的主要控制逻辑和一部分控制逻辑所需的辅助函数,主要函 数应该包括用来绘图的 paint()函数、用来控制操作的 keyPressed()函数、用来控制选择区域的 setRange()函数、用来控制选择要移 动到区域的 setMoveRange()函数、用来移动选中区域的 Move()函数和判断是否完成任务的 win()函数
32、,更具体的分析,我们放到详细设计 中去细化。MIDlet1 实际上就是一个控制整个 J2ME 应用的控制程序,其实也没有什么可特别的,它和我们前面介绍的“Hello World“程序大同小异,这里就不展开来说了,后面会贴出它的全部代码。Map 类主要应该有一个 Grid的二维数组,用来存放华容道的地图,还应该有一个 read_map()函数用来从外部文件读取地图内容填充 Grid 数据结构,再就是要有一个 draw_map()函数用来把 Grid 数据结构中的地图内容转换成图片显示出来(当然要调用 Draw 类的 paint 方 法)。说到读取外部文件,笔者知道有两种方法:一种是传统的定义一个
33、 InputStream 对象,然后用 getClass().getResourceAsStream()方法取得输入流,然后再从输入流中取得外部文件的内容,例如InputStream is = getClass().getResourceAsStream(“/filename“); if (is != null) byte a = (byte) is.read(); 这里请注意文件名中的根路径是相对于便以后的 class 文件放置的位置,而不是源文件(java)。第二种方法是使用 onnector.openInputStream 方法,然后打开的协议是 Resource,但是这种方法笔者反复尝
34、试都没能调通,报告的错误是缺少 Resource 协议,估计第二种方法用到 J2ME 的某些扩展类包,此处不再深究。由于以前已经做过一些类似华容道这样的地图,这里直接给出 Map 类的代 码,后面就不再详细解释 Map 类了,以便于我们可以集中精力处理 Displayable1 中的逻辑。Map 类的代码如下:package huarongroad; import java.io.InputStream; import javax.microedition.lcdui.*; public class Map /处理游戏的地图,负责从外部文件加载地图数据,存放地图数据,并按照地图数据绘制地图 p
35、ublic byte Grid;/存放地图数据 public Map() /构造函数,负责初始化地图数据的存储结构 this.Grid = new byteImages.HEIGHTImages.WIDTH; /用二维数组存放地图数据,注意第一维是竖直坐标,第二维是水平坐标 public int read_map(int i) A href=“file:/从“file:/从/A外部文件加载地图数据,并存放在存储结构中,返回值是光标点的位置 /参数是加载地图文件的等级 int a = new int2;/光标点的位置,0 是水平位置,1 是竖直位置 try InputStream is = ge
36、tClass().getResourceAsStream( “/huarongroad/level“.concat(String.valueOf(i); if (is != null) for (int k = 0; k Images.HEIGHT; k+) for (int j = 0; j Images.WIDTH; j+) this.Gridkj = (byte) is.read(); if ( this.Gridkj = Images.CURSOR ) /判断出光标所在位置 a0 = j;/光标水平位置 a1 = k;/光标竖直位置 this.Gridkj = Images.BLANK
37、;/将光标位置设成空白背景 is.read();/读取回车(13),忽略掉 is.read();/读取换行(10),忽略掉 is.close(); else /读取文件失败 a0 = -1; a1 = -1; catch (Exception ex) /打开文件失败 a0 = -1; a1 = -1; return a; public boolean draw_map(Graphics g) /调用 Draw 类的静态方法,绘制地图 try for (int i = 0; i Images.HEIGHT; i+) for (int j = 0; j Images.WIDTH; j+) Draw
38、.paint(g, this.Gridij, j, i);/绘制地图 return true; catch (Exception ex) return false; 对于像华容道这样的小型地图可以直接用手工来绘制地图的内容,比如:fa1c2232bd1e2gg2gihg但是,如果遇到像坦克大战或超级玛莉那样的地图,就必须另外开发一个地图编辑器了(我会在后续的文章中介绍用 vb 来开发一个地图编辑器)。五、详细设计详细设计是程序开发过程中至关重要的一个环节,好在我们在前面的各个阶段中已经搭建好了项目所需的一些工具,现在这个阶段中我们只需集中精力设计好 Displayable1 中的逻辑。(两天的
39、时间当然不只干这点活,还要把其他几个类的设计修改一下)Displayable1 这个类负责处理程序的控制逻辑。首先,它需要有表示当前关面的变量 level、表示当前光标位置的变量 loc、表示要移动 区域的变量 SelectArea、表示要移动到的区域的变量 MoveArea、表示是否已有区域被选中而准备移动的变量Selected 和 Map 类的实例 MyMap。然后,我们根据用户按不同的键来处理不同的消息,我们要实现 keyPressed()函数,在函数中我们处理按键的上下左右和选中 (Fire),这里的处理需要我展开来讲一讲,后面我很快会把这一部分详细展开。接下来,是实现 paint()
40、函数,我们打算在这一部分中反复的重画背景、地图和选择区域,这个函数必须处理好区域被选中之后的画笔颜色的切换,具 体讲就是在没有选中任何区域时要用黑色画笔,当选重要移动的区域时使用绿色画笔,当选择要移动到的区域时改用红色画笔(当然附加一张流程图是必不可少 的)。再下面要实现的 setRange()函数和 setMoveRange()函数,这两个函数用来设置要移动的区域和要移动到的区域,我的思路就是利用 前面在 Images 类中介绍过的地图组合标记常量,当移动到地图组合标记常量时,根据该点地图中的值做逆向变换找到相应的地图标记常量,然后设置相应的 loc、SelectArea 和 MoveAre
41、a,其中 setMoveRange()函数还用到了一个辅助函数 isInRange(),isInRange()函数是用来判断给定的点是否在已选中的要移动的区域之内,如果 isInRange()的返回值是假并且该 点处的值不是空白就表明要移动到的区域侵犯了其他以被占用的区域。有了 setRange()和 setMoveRange()函数,Move()函数就水到 渠成了,Move()函数将要移动的区域移动到要移动到的区域,在移动过程中分为三步进行:第一.复制要移动的区域;第二.将复制出的要移动区域复制到要移动到的区域(这两步分开进行的目的是防止在复制过程中覆盖掉要移动的区域);第三.用 isInR
42、ange2()判断给定的点是否在要移动到的区域内,将不在要移动到的区域内的点设置成空白。 下面我们详细的分析一下 keyPressed()函数的实现方法:首先,keyPressed()函数要处理按键的上下左右和选中(Fire),在处理时 需要用 Canvas类的 getGameAction 函数来将按键的键值转换成游戏的方向,这样可以提高游戏的兼容性(因为不同的 J2ME 实现,其方向键的 键值不一定是相同的)。接下来,分别处理四个方向和选中.当按下向上时,先判断是否已经选定了要移动的区域(即 this.selected 是否为真),如果没有选中要移动 区域则让光标向上移动一格,然后调用 se
43、tRange()函数设置选择要移动的区域,再调用 repaint()函数刷新屏幕,否则如果已经选中了要移动的 区域,就让光标向上移动一格,然后调用 setMoveRange()函数判断是否能够向上移动已选中的区域,如果能移动就调用 repaint()函数刷新 屏幕,如果不能移动就让光标向下退回到原来的位置。当按下向下时,先判断是否已经选定了要移动的区域,如果没有选中要移动的区域则判断当前所处的区域是否为两个格高,如果是两个格高则向下移动两格, 如果是一个格高则向下移动一格,接着再调用 setRange()函数设置选择要移动的区域,而后调用repaint()函数刷新屏幕,否则如果已经选中了 要移
44、动的区域,就让光标向下移动一格,然后调用 setMoveRange()函数判断是否能够向下移动已选中的区域,如果能移动就调用 repaint() 函数刷新屏幕,如果不能移动就让光标向上退回到原来的位置.按下向左时情况完全类似向上的情况,按下向右时情况完全类似向下的情况,因此这里不再赘述,详 细情况请参见程序的源代码。当按下选中键时,先判断是否已经选中了要移动的区域,如果已经选中了要移动的区域就调用 Move()函数完成由要移动的区域到要移动到的区域的移动 过程,接着调用 repaint()函数刷新屏幕,然后将已选择标记置成 false,继续调用 win()函数判断是否完成了任务,否则如果还没有
45、选定要移动 的区域则再判断当前选中区域是否为空白,如果不是空白就将选中标记置成 true,然后刷新屏幕.这里介绍一个技巧,在开发程序遇到复杂的逻辑的时候,可以 构造一格打印函数来将所关心的数据结构打印出来以利调试,这里我们就构造一个 PrintGrid()函数,这个函数纯粹是为了调试之用,效果这得不错.至 此我们完成了编码前的全部工作。package huarongroad; import javax.microedition.lcdui.*; public class Displayable1 extends Canvas implements CommandListener private
46、 int loc = new int2; A href=“file:/光“file:/光/A标的当前位置,0 是水平位置,1 是竖直位置 private int SelectArea = new int4;/被选定的区域,即要移动的区域 private int MoveArea = new int4;/要移动到的区域 private Map MyMap = new Map();/地图类 private boolean selected;/是否已经选中要移动区域的标志 private int level;/但前的关面 public Displayable1() /构造函数 try jbInit(
47、);/JBuilder 定义的初始化函数 catch (Exception e) e.printStackTrace(); private void Init_game() /初始化游戏,读取地图,设置选择区域,清空要移动到的区域 this.loc = MyMap.read_map(this.level);/读取地图文件,并返回光标的初始位置 /0 为水平位置,1 为竖直位置 this.SelectArea0 = this.loc0;/初始化选中的区域 this.SelectArea1 = this.loc1; this.SelectArea2 = 1; this.SelectArea3 =
48、1; this.MoveArea0 = -1;/初始化要移动到的区域 this.MoveArea1 = -1; this.MoveArea2 = 0; this.MoveArea3 = 0; private void jbInit() throws Exception /JBuilder 定义的初始化函数 A href=“file:/初“file:/初/A始化实例变量 this.selected = false;/设置没有被选中的要移动区域 this.level = 1; Images.init();/初始化图片常量 Init_game();/初始化游戏,读取地图,设置选择区域,清空要移动到的区域 setCommandListener(this);/添加命令监听,这是 Displayable 的实例方法 addCommand(new Command(“Exit“, Command.EXIT, 1);/添加“退出”按钮 public void commandAction(Command command, Displayable displayable) /命令处理