1、基于 J2ME 的手机游戏开发摘要:随着通信技术的发展和手机的普及,手机游戏的开发技术越来越为人们所关注。以J2ME 为开发平台,利用 Java 提供强大工具,不但可以在手机上实现静态 HTML 技术所无法实现的计算处理、数据存储、与服务器的通信等功能,而且能够开发各种手机游戏。本文在介绍 J2ME 及其体系结构的基础上,以贪吃蛇游戏为实例,描述了借助 J2ME 的MIDlet 类库开发手机游戏的过程。关键词:手机游戏; MIDP 应用程序; 永久性数据Develops based on the J2ME handset gameAbstract: Along with communicati
2、on development and handset popularization, people more and more pay attention to the handset game development technology. Develops the platform take J2ME, provides the powerful tool using Java, not only may realize the handset functions that static HTML technology be unable to realize, such as compu
3、tation processing, data storage, and communication with server, but also can develop all kinds of handset games. On the basis of the technology and architecture of J2ME being introduced, the gluttonous snake game was taken as a example, the development process of handset game with the aid of the J2M
4、E MIDlet class library is described in this article.Key Words: Handset game; MIDP application pragram; Permanent data目 录第一章 绪论 .11.1 研究背景 11.2 研究内容 1第二章 J2ME 及其体系结构概述 22.1 J2ME 简介 22.2 J2ME 体系结构 .22.3 移动信息设备简表概述 32.3.1 MIDP 的目标硬件环境 32.3.2 MIDP 应用程序 .32.3.3 CLDC 和 MIDP 库中的类 32.4 J2ME API 简介 42.4.1 MI
5、DP API 概述 .42.4.2 MIDlet 应用程序 .42.4.3 使用定时器 .52.4.4 网络 62.4.5 使用 Connector 72.4.6 使用 HttpConnection 82.4.7 永久性数据(RMS) 92.4.8 存储集(Record Store) 102.4.9 记录 .112.4.10 枚举 .122.4.11 异常 132.5 用户界面(LCDUI 132.5.1 UI 基础 .132.5.2 高级 UI .142.5.3 低级 UI 15第三章 手机游戏开发过程 163.1 贪吃蛇游戏的规则简介以及开发环境 .163.1.1 贪吃蛇游戏的规则简介 1
6、63.1.2 开发环境 163.2 详细设计 163.2.1 代码设计 17第四章 程序的调试与运行 224.1 游戏的调试 224.2 游戏的运行环境 .23第五章 总结 .24致 谢 .25参考文献 .251第一章 绪论1.1 研究背景JAVA 自从 20 世纪 90 年代早期诞生以来,以其强大的功能迅速为广大程序员们所接受。从 2001 年开始,日本的国内的移动电话开始搭载 Java。使用本来就是一种程序语言的 Java 之后,就可以在移动电话上完成以往静态的 HTML内容所无法达成的计算处理、数据存储、与服务器的通信等等。如果能利用Java 上其他丰富功能,那么就可以实现更多的功能。随
7、着手机游戏的发展,国内外各大开发商纷纷运用 Java 进行手机游戏开发。 J2ME 作为一种基于 Java 的便携设备开发平台,在各大手机开发公司得到了广泛应用。1.2 研究内容本课题拟研究基于 J2ME 的手机游戏开发技术以及其特点,具体研究内容如下:1、手机游戏开发以及 J2ME 的基本理论和 J2ME 类库的使用;2、J2ME 体系结构的研究;3、MIDP 移动信息设备简表的研究;(1) 、MIDP 的目标硬件环境;(2) 、MIDP 应用程序;(3) 、CLDC 和 MIDP 库中的类。4、J2ME API 的研究;(1)MIDlet 应用程序的研究;(2)MIDlet 的类库研究;(
8、3)各事件发生器的应用。5、开发工具的应用和开发环境的设置。其中 MIDP 移动信息设备简表的研究和 J2ME API 的研究为重点,本课题将通过一个具体的手机游戏的开发来研究以上内容。2第二章 J2ME 及其体系结构概述2.1 J2ME 简介现在 JAVA-JAVA2 Platform 大致可分为 J2SE、J2EE、J2ME 三类。J2SE为 JAVA-JAVA2 Platform 的标准版,通常在 PC 上使用的 JAVA。J2EE 是在J2SE 的 API 上,扩展了给企业使用 EJB 与 Servlet 等主要使用在服务器上的功能。而 J2ME 则是面向家电和通信工具等微小设备。J2
9、ME 的目标是微小设备,这类设备有许多种类,在这些设备的 J2ME 当中,定义了 CDC( Connected Device Configuration),CLDC(Connected Limited Device Configuration)这两个 Configuration。CDC 是以能用在个人网关、下一代移动电话、PDA(个人数字助理) 、家电设备、POS 终端、车辆导航系统等上运行为前提设计出来的。CLDC,是以能使用在移动电话、PDA(个人数字助理) 、家电设备、 POS 终端等上面为前提设计出来的。2.2 J2ME 体系结构配置和简表:配置定义了一个设计在一系列类似硬件上运行的
10、Java 平台的能力。J2me 的目标是家电与嵌入式设备,这类设备有很多种类,对应这些设备的 J2me 当中,定义了 CDC(连接设备配置)和 CLDC(受限接设备配置)两个配置,配置所提供的类函数只有 Java.lang, Java.io,Javautil 包等 J2SE 等核心类的子集。CLDC 是与手机相关的,它实际是定义一个设备制造商用来实现Java 运行环境的标准,第三方开发者只需要遵循这个标准。CLDC 主要影响Java 开发和软件发布的以下方面:1)目标设备的特性;2)安全模型:安全模型有两个部分,虚拟机和应用程序安全。虚拟机安全层的目的是保护下面的设备不受任何执行代码可能引起的
11、损害。32.3 移动信息设备简表概述2.3.1 MIDP 的目标硬件环境1)显示 :96*54 象素,1 位颜色,大约 1:1 比例;2)输入: (a)单手键盘或者小键盘;(b)双手的 QWERTV 键盘;(c)触摸屏。 3)内存: (a)128KB 非易失性内存,供 MIDP 组件使用;(b)8KB 的非易失性内存,供应用程序生成的永久数据使用;(c)32KB 的易失性内存,供 Java 堆使用。4)网络: (a)双响无线网络,可间歇性连接;(b)通常是很有限的带宽。2.3.2 MIDP 应用程序在 MIDP 上运行的 Java 程序被称为 MIDlet。MIDlet 是服从一些关于它运行环
12、境和程序打包的一些规则。其运行环境是启动 MIDlet,这是设备内置应用管理器的任务。应用程序能访问到下面的一些资源:(1)震动文件中的所有文件。 (2)MIDlet 描叙文件的内容( JAD) 。2.3.3 CLDC 和 MIDP 库中的类打包:MIDlet 应用一般采用震动文件的形式。这个文件应该包含运行应用程序需要的类和所有的资源文件,它也应该包含一个叫 manifest.mf 的清单文件。保存在震动文件中的清单文件是一个简单的文本文件,包含属性值。应用程序描叙(JADs)在移动电话网络上传送大量的数据,需要有一个描叙文件让用户在没有下载整个包之前来查看一下 MIDlet 震动的细节。4
13、2.4 J2ME API 简介2.4.1 MIDP API 概述MIDP API 包含以下五个部分,如表 2-1 所示:表 2-1 MIDP API类 别 描 述Application 包括 MIDlet 类。Timers 主要包括 Timers 和 Timers Task 类。Networking 提供访问设备通信能力的接口。Persistence 通过记录管理系统(RMS)API 访问用户永久存储。User Interface 包括 MIDP LCDUI(液晶显示器用户界面)类。2.4.2 MIDlet 应用程序MIDlet 即 MIDP 的应用程序, MIDlet 应用程序的核心是 MI
14、Dlet 类。为了创建一个 MIDlet,必须从这个虚基类派生出自己的类。表 2-2 提供了从 MIDlet类继承的方法。表 2-2 MIDlet 类方 法 描 述访问 JAR 和 JAD 文件中的属性String gerAppProperty(string key)返回 JAR 和 JAD 中与 key 相对应的属性的值。Abstract void destoryApp (boolean unconditinal)应用程序管理器在应用程序关闭前,调用这个方法来给我们做一些事情的机会(例如保存状态和释放资源) 。Abstract void pauseApp() 在用户暂停游戏时,应用程序管理器
15、调用 MIDlet 的类方法。Abstract void startApp() 应用程序管理器调用 MIDlet 的这个方法,来告诉用户再次开启游戏。5Abstract void notifyDestroyed() 如果游戏者决定退出游戏,可以调用这个方法来通知应用程序管理器。续表 2-2 MIDlet 类方 法 描 述Abstract void notifyPausrd() 调用这个方法来通知应用程序管理器游戏者已经暂停游戏。Abstract void notifyRequest() 调用这个方法来告诉应用程序管理器 MIDlet 要重新开始。应用程序管理器(Application Mana
16、ger ,AM)的作用就是管理 MIDlet 。本质上来说,MIDlet 应用程序只存在两种状态 暂停和运行。MIDlet 被创建后默认为暂停状态,当应用程序管理器认为它准备完毕,它会调用 startApp 方法来通知 MIDlet 进入运行状态。2.4.3 使用定时器 MIDP API 包括两个关于定时器的类 Java.util.Timer 和 Java.util.Timer Tast 类 (如表 2-3 和 2-4 所示 ):表 2-3 Java.util .Timer 类方 法 描 述Timer() 构造一个新的 Timer 对象。Void cancel() 停止 Timer。Void
17、schedule(TimeTask task,Dare d) 把一个任务定时在时间 d 运行。Void schedule(TimeTask task, Data firstTime, long period )让一个任务第一次在一个指定的时间运行,然后每隔 period 毫秒运行一次。Void schedule(TimeTask task,long delay) 指定一个任务在 delay 毫秒后运行一次。Void schedule(TimeTask task,long delay,long period)指定一个任务从 delay 毫秒连续运行,然后每隔 period 毫秒运行一次。6Voi
18、d scheduleAtFixedRate(timeTask task,Date firstTime,long period)指定一个任务从 firstTime 连续运行,然后以固定间隔 period 毫秒连续运行。Void scheduleAtFixedRate(TimeTask task,long delay,long period)指定一个任务在 delay 毫秒后运行,然后以固定间隔 period 毫秒连续运行。表 2-4 Java.util.Timer Tast 类方 法 描 述Timer Task() 构造一个新的 Timer Task 对象。Boolean cancel() 结束
19、该任务。Abstract void run() 这个方法必须被一个包含 Timer 时间执行的代码的方法重载。Long scheduledExecution Time() 返回任务上一次执行的确切时间。我们可以通过不同 schedule 的方法来确定什么时候执行任务,包括在一个指定的时间执行一次和那个时间后按照一个固定的时间间隔连续执行。也可以在一段延迟(单位是毫秒)后执行任务,还可以选择以固定的时间间隔连续执行。2.4.4 网络 MIDP 包含对 CLDC 中的 GCF(Generic Connection Framework),即通用连接框架的支持,MIDP 规范只是要区分必须实现 HTT
20、P 的连接。如果想开发的是基于无线网络的高性能的多人联网游戏,这非常值得考虑应用。目前的情况是,无线网络的传输情况是高延迟以及高丢失率,所以响应时间在 50ms 的游戏很难实现。通用连接框架使用静态工厂类 Connector 去创建和返回一个连接。如图 2-1所示是所有类型的类层次图。7Connector.openConnectionInputConnection OutputConnectionStreamConnectionContentConnectionHttpConnectionStreamConnectionNotifer DatagramConnection图 2-1 类层次图图
21、 2-1 通用连接框架包含丰富的多功能的通信类;但是 MIDP 只确保支持HttpConnection。2.4.5 使用 Connector通用连接框架设计包括一个超级 Connector 的概念,这个 Connector 作为一个支持任何连接类型的工厂,基本上来说,调用 Connector 类的静态方法 open即可,把需要连接的资源的名字作为参数传递过去,这个名字应该采用“协议: 地址: 参数” 的格式。在代码里将采用 HttpConnection 类,如表 2-5 所示:表 2-5 HttpConnection 类方 法 描 述Static Connection open (String
22、 name) 构造,打开和返回一个指向一个指定URL 的连接。8续表 2-5 HttpConnection 类Static Connection open(String name , int mode)构造,打开和返回一个连接,连接一个指定资源 URL 和打开的模式都需要设定。Static Connection open(String name , int mode , Boolean timeouts)构造,打开和返回一个连接,连接一个指定资源 URL 和打开的模式都需要设定,同时也有一个参数指定是否需要超时异常。static Connection openDataInputStream(S
23、tring name)打开一个连接,然后构造和返回一个数据输入流。static Connection openDataOutputStream(string name)打开一个连接,然后构造和返回一个数据输出流。static Connection openinputStream(String name)打开一个连接,然后构造和返回一个输入流。static Connection openOutStream(String name)打开一个连接,然后构造和返回一个输出流。2.4.6 使用 HttpConnectionHttpConnection 类是一个全功能的 HTTP 客户端,实用于大多数的网
24、络任务(低延迟) 。对于游戏而言,可以用它来按需下载内容(如新的关卡) ,更新得分,或者实现游戏者之间的通信。表 2-6 是所有 HttpConnection 类的可用方法。表 2-6 javx.microedition.io.HttpConnection 类方 法 描 述long getData() 获取头中的日期值。Long getExpiration() 获取头中的过期时间。String getHeaderFieldkey(int n) 根据索引获取头中的键名。String getHeaderField(int n) 根据索引获取头中的键值。String getHeaderField(S
25、tring name) 获取指定的头文字段的值。9续表 2-6 javx.microedition.io.HttpConnection 类long getHeaderFieldData(String name, long def)按照长日期类型返回指定字段的值,如果该字段不存在就返回 def 的值。int getHeaderFieldInt(String name,int def)按照整数类型返回指定字段的值,如果该字段不存在就返回 def 的值。Long getLastModified() 返回最后一次更新的时间。String getURL() 返回 URL。String getFile()
26、 获取 URL 中的文件部分。String getHost() 获取 URL 中的主机部分。int getPort() 获取 URL 中的端口部分。String getProtocol() 获取 URL 中的协议部分。String getQuery() 获取 URL 中的查询部分。String getRef() 获取 URL 中的引用部分。Int getResponseCode() 返回 HTTP 响应状态码String ResponseMessage() 返回 HTTP 响应消息(如果存在的话) 。String getREquestMethod() 获取连接请求的方法。Void getReq
27、uestMethod(String method) 设置 URL 请求的方法。可用的类型有GET, POST 和 HEAD。String getRequestProperty(String key) 获取与指定的键相关联的请求属性值。Void setRequestProperty(String key, String value)设定与指定的键相关联的请求属性值。2.4.7 永久性数据(RMS)开发游戏时,保存数据在 J2ME 里是用 RMS(Record Management System,记录管理系统)来实现的,可以在 Javax.microedition.rms 包中找到它,表 2-7就
28、是这个包中所有的类的列表。RMS 采用记录的方式来保存数据,然后使用唯10一的记录号来应用这些数据,成组的数据就被保存在存储集中。表 2-7 RMS 包(不包含异常)类 描 述类RecordStore 允许访问记录存储集功能。接口RecordComparator 提供一个用来实现两个记录间比较的接口。RecordComparation 提供记录存储集的枚举器;可以和比较器和过滤器联合使用。recordFilter 对获取的数据进行过滤。RecordListener 提供一个用来“ 监听”RMS 中发生的事件的接口,比如记录增加,修改和删除。2.4.8 存储集(Record Store)记录存储
29、集即一个记录存储的机制,表 2-8 中展示了完整的 API。表 2-8 记录存储 API方 法 描 述存储集访问方法Static RecordStore openRecordStroe(String record Name,blooean createIfNecessary)打开一个存储集或者在它不存在的时候创建一个存储集。Void closeRecordStore() 关闭一个存储集。Static void deleteRecordStore(String recordStore Name)删除一个存储集。Long getLastModified() 获取存储集最后被修改的时间。String
30、 getName() 获取存储集的名称。int getNumrecords() 返回存储集当前记录的数量。int getSize() 返回存储集使用的总字节数。int getSizeAvailable() 获取空闲空间。11int getVersion() 获取存储集的版本号。12续表 2-8 记录存储 APIStatic String listRecordStores() 获取 MID 中你可以访问的所有的记录存储集的字符串数组。记录访问方法int addRecord(byte,int offset,int numBytes)向存储集中加入一条新的记录。byte getRecord(int
31、recordId) 用 ID 来获取一条记录。int getRecord(int recorded,byte buffer,int offset)把一条记录读取到 buffer 中。Void deletRecord(int recorded) 删除与 recordId 相关的记录。Void setRecord(int recorded,byte newData,int offset,intnumBytes)使用新的字节数组与 recordId 相关联的内容。Int getNextRecordID() 在插入后获取下一个记录的 ID。Int getRecord(int recorded) 返回按
32、字节计算的记录存储集当前的数据大小。RecordEnumeration enumerate Records(RecordFilterfilter,RecordComparator,bool-ean keepUpdataed)返回一个 RecordEnumerator 对象。它是用来在一个记录集合中枚举的(使用comparator 参数) 。与时间有关的方法Void addRecordListener(RecordListener listener)加入一个监听器对象,它可以在有这个记录存储集消息的时候被调用。Void removeRecordLisrener(RecordListener li
33、stener)移除原来用 addRecordListener 方法加入的监听器对象。记录存储集在与 MIDlet 包范围,也就是说同一个包的任何 MIDlet 都可以访问这个包中的记录存储集,其他包中的 MIDlet 甚至不能感知到别的包里记录存储集的存在。2.4.9 记录一个记录就是一个字节数组,可以在里面写任何格式的数据。可以用DataInputStream、DataOutputStream 往记录中写入数据,也可以用ByteArrayInputStream 和 ByteArrayOutputStream。在记录存储集中记录是以一种类表的结构存储,如下图 2-2 所示:13ID Recor
34、d data(byte array)1 “John”2 “64997”3 .png image data - _图 2-2 Record data Store “A”每一个记录和它相关的字节数组都有一个整数主键唯一来标识,RMS 会成为记录设定 ID。头一个写入的 ID 是 1,每次增加一条记录它的 ID 就增加 1,上图展示了一个记录集的简单用法。在这个例子中,玩家的名字(字符串“John”)存储在记录 1 中,记录 2 保存最高分,记录 3 是先前从网络上下载的缓存的图象。2.4.10 枚举 RMS 支持使用 Javax.microedition.rms.RecordEnumerator
35、类来排序记录,如表 2-9 展示了它所有属于这个类中的全部的方法。 表 2-9 Javax.microedition.rms.RecordEnumerator 类方 法 描 述常用方法Void destroy() 销毁枚举器。Boolean isKeptUpdated() 指出在下面的记录存储集改变后该枚举器是否自动更新生成。keepUpdated(Boolean keepUpdated) 改变 keepUpdated 的状态。Void rebuild() 引起枚举器管理的索引重新生成。14续表 2-9 Javax.microedition.rms.RecordEnumerator 类Void
36、 reset() 把枚举器设置成刚刚创建后的状态。访问Boolean hasNextElement() 测试在从前一个到最后一个的顺序中是否还有可以枚举的记录。Boolean hasPreviousElement() 测试在从最后一个到前一个的顺序中是否还有可以枚举的记录。Byte nextRecord() 获取存储集中的下一个记录。Byte previousRecord() 获取存储集中的前一个记录。Int previousRecoed() 获取前一天记录的 ID。Int nextRecord() 获取下一个记录的 ID。Int numRecord() 获取记录的数量,这在你使用过滤器的时候
37、是很重要的。可以用记录存储集来访问枚举器,也可以使用枚举器在记录中双向遍历。如果反向遍历只需要使用 previousRecord。2.4.11 异常RMS 异常都是因为不正确的环境造成的,对于这些异常需要编写代码来处理问题(RecordStoreNotFoundException、RecondStoreNotOpenException、InvalidRecordIDExcepaion 的情况) ,或者只能接受它。2.5 用户界面(LCDUI在创建游戏时,MIDP 允许我们使用两种截然不同的界面系统 高级 UI和低级 UI。152.5.1 UI 基础LCDUI 的核心是 screen 的概念,它
38、代表 MID 上的一个 display,在任何一个时间点,只能有一个 screen 可见。在 LCDUI 中有 3 种类型的 screen:(1) 低级 UI 可以通过 Canvas 类访问;(2) Form 显示一组简单的 UI 组件,或者说控件;(3) 复杂组件(Complex components) 。2.5.2 高级 UI高级 UI 提供了 MID 的一个抽象接口,通过它可以获得大量的功能。使用高级 API 首先创建组件把它们加入到屏幕,然后与它们相交互。高级 UI 一般划分为两大类:屏幕和组件。(1) 屏幕(screen )screen 是一个完整类组件,它管理整个屏幕。Form 是
39、一个特殊的 screen,可以在 Form 中由少量几个组件来构造一个 screen。(2) 列表(List)List 是一个可以给用户显示一组备选项的组件。这个类实现了Javax.microedition.lcdui.Choice 接口,ChoiceCroup item 也实现了这个接口。(3) 文本框(TestBox)TestBox 组件是微型世界的字处理器,它只能输入多行的文字。它可以让玩家输入多行文字、剪切、复制以及从剪切板粘帖、过滤输入的数据。(4) 警告(Alert)可以使用它来显示一个提示信息(因为它是一个 screen,所以它接管整个屏幕) 。(5) Form 和 ItemFo
40、rm 是一种可以包含一个或者多个下面这些从 Item 类派生出来的组件的screenStringItem、ImageItem、TextField、ChoieGroup、DataField 和Gauge。(6) StringItem 类16运用 StringItem 类在 Form 上加入简单的文字消息。2.5.3 低级 UI低级 UI 提供了一个工具包来移动和绘制图形、显示文字、获取直接的按键事件等。(1) Canvas 类Canvas 又称画布,是一个 Displayable 对象,所有绘图操作都画在它上面。(2) Graphics 类Graphics 类工具在 Canvas 中承担基本的二
41、维绘图。(3) 二维绘图工具drawLine 采用 4 个参数直线起点的 x、y 坐标值和直线终点 x、y 的坐标值,例如:graphics.drawLine(50,0,100,0) ;这行代码会从位置(50,0)到(100,0)绘制一条直线。绘制一个矩形是一个类似的过程,不同的只是需要用起点加上宽度和高度的方式来指定这个对象,可以绘制透明的或者填充的矩形,甚至可以绘制圆角的矩形。4 个绘制矩形的方法是:drawRect、drawRoundedRect、fillRect 和fillRoundedRect。弧是使用 6 个参数来绘制的,前 3 个参数是弧所在的整个圆的外切矩形。剩下的两个参数是
42、startAngle 和 arcAngle。Angle 是度数,0 为右侧(在三点的位置)的地方,180 是左侧(在九点的位置)的位置。(4) 绘制文字可以使用方法 drawChar、drawChars、drawString 和 drawSubstring 在Canvas 上面绘制文字。(5) 图象和裁剪裁剪让人可以把图象输出限制到显示设备的一个特定区域中,例如,如果将输出限制在一个从(10,10)开始到(50,50)的区域中,那么从那个时候起,没有图像会出现在显示设备上这个区域之外的任何地方。(6) 事件响应17实现一个或者多个按键事件响应方法:keyPressde、keyRleased 和
43、keyRepeated。第三章 手机游戏开发过程3.1 贪吃蛇游戏的规则简介以及开发环境3.1.1 贪吃蛇游戏的规则简介在贪吃蛇游戏中,玩家操作由小方块连接而成的蛇,去吃随机散落在画面内的小方块,每吃一块就增加一小方块长度,要是撞壁以及撞自己的尾,就属于失败,如无失败则直到通关为止。屏幕的长度的行向为 11 单位,纵向为 18 单位。在这个范围内,玩家通过操作方向键来控制蛇的运动方向。该游戏的最大特色是屏幕自适应,无论各种手机,PDA 的屏幕大小如何,该游戏总是能获得最佳的显示效果。3.1.2 开发环境(1)开发的硬件环境:CPU C1.7HZ/Maxor 40G/DDR 256M/CD-RO
44、W 40X(2)开发软件:JDK1.3 和 J2MEWTK3.2 详细设计本游戏的操作流程(如图 3-1):用户在启动 MIDlet 后,即进入游戏主画面,屏幕开始显示为欢迎画面。用户按下开始按钮后,就可以开始玩游戏。当用户想暂停时,再次按一下开始按钮,游戏就暂停了,在暂停的情况下再按开始 按钮,游戏继续运行。任何时候按退出 按钮,游戏 MIDlet 都会终止。18图 3-1 操作流程3.2.1 代码设计 (1)游戏地图代码设计游戏地图是蛇的活动范围和食物随机散落的范围,游戏的容器为行向为 11单位,纵向为 18 单位,如下代码:private final int iX = 10; /地图的开
45、始坐标private final int iY = 10; /private final int SWIDTH = 16; /图标的宽度private final int iCells = 11; /地图的列数private final int iRows = 18; /地图的行数private final int iBoxW = SWIDTH*iCells; /地图的宽19采用二维绘图工具:二维绘图工具 drawLine 采用 4 个参数直线起点的x、y 坐标值和直线终点 x、y 的坐标值,例如:graphics.drawLine(50,0,100,0) ;这行代码会从位置(50,0)到(1
46、00,0)绘制一条直线。绘制一个矩形是一个类似的过程,不同的只是需要用起点加上宽度和高度的方式来指定这个对象。可以绘制透明的或者填充的矩形,甚至可以绘制圆角的矩形。4 个绘制矩形的方法是:drawRect、drawRoundedRect、fillRect 和fillRoundedRect。(2)贪吃蛇和食物的代码设计屏幕的长度为行向为 11 单位,纵向为 18 单位;在这个范围内(如图 3.3),玩家操作方向键控制蛇的运动方向。该游戏的最大特色是屏幕自适应,无论各种手机,PDA 的屏幕大小如何,该游戏总是能获得最佳的显示效果。图 3-3 游戏区域贪吃蛇最初由 3 个小正方形组成,小正方形是蛇的
47、身体和游戏容器的组成部分。食物也由一块小正方形组成,并且随机散落在游戏框图的区域内,每次只出现唯一的一个,待玩家操作游戏完成一个任务后面,再出现下个食物,小蛇每吃一个食物就增加一个长度。实现代码如下:20public int getCell()return iCell;public int getRow()return iRow;public void show()sLabel.setVisible(true);public boolean isVisible()return sLabel.isVisible();public void hide()sLabel.setVisible(fals
48、e);protected void setPosition(int row, int cell)iCell = cell;iRow = row;sLabel.setBounds(cell*SWIDTH, row*SWIDTH, SWIDTH, SWIDTH);public void moveUp()if(iRow0)setPosition(-iRow,iCell);elsesetTouch();public void moveDown()if(iRow0)setPosition(iRow,-iCell);elsesetTouch();public void moveRight()if(iCel
49、liBoxW-1)setPosition(iRow,+iCell);elsesetTouch();static boolean getTouch()return isTouch;static void setTouch()isTouch = true;static void setImTouch()isTouch = false;public Snake clone()Snake tem = new Snake();tem.setPosition(this.getRow(),this.getCell();return tem;22(3)操作控制代码设计MIDP 的游戏设计,本质上就是用一个线程或者定时器产生重绘事件,用线程和用户输入改变游戏状态。这个游戏也不例外,启动 MIDlet 后,就立即生成一个重绘线程,该线程每隔 50ms 绘制一次屏幕。当然,重绘时有一些优化措施,并不是屏幕上所有的像素都需