Java Solaris 加入Sun中国技术社区 我的社区 注册说明
 
JDK 6.0 API 中文版
 
 
 
 
Java API 文档中文版
通过实例学习 NetBeans 6 的新功能 第 3 部分:使用 Mobility 开发游戏
 
By 大野圭一, 7/15/08  

第 3 部分:使用 Mobility 开发游戏


NetBeans 6.0.1 拥有非常强大的 Java ME 集成开发环境。本部分将介绍用于游戏开发的游戏生成器,具体的技术信息请参阅本文结束部分的参考资料以及 NetBeans Mobility 中包含的示例源代码,这些信息对游戏设计器本身和游戏的开发进行了说明。在本文中,我们将介绍如何使用游戏生成器开发游戏。请轻松阅读本部分内容。


 


目录

 


应用程序及其规格
 

Java ME 开发环境与桌面及服务器应用程序的运行环境不同,API 中规定了各类设备的 Java 虚拟机器规格,这些规格定义为“配置”和“配置文件”的组合。(根据需要可以追加“扩展配置文件”)

规格 = 配置 + 配置文件 ( + 扩展配置文件)

开发人员在配置中定义基本的 Java 虚拟机器规格及类库的最小集,而配置以 JCP 为标准,主要有以手机为例的 CLDC (Connected Limited Device Configuration) 和以嵌入式机器为例的 CDC (Connected Device Configuration);配置文件用于定义特定类别的(手机、PDA 等)、面向机器的 API,其他附加部分则定义在扩展配置文件中。作为 MIDP (Mobile Information Device Profile) 配置文件的标准集,CLDC 在移动电话领域得到了广泛应用。

举例来说:开发面向日本市场的手机 Java 应用程序时,它的规格是配置和配置文件的组合,如下所示。( ) 表示各种规格的版本:

手机运营商 规格组合
NTT DoCoMo i 应用服务 CLDC (1.0 或 1.1) + DoJa 配置文件
au 开放式应用服务 CLDC (1.1) + MIDP (2.0)
SoftBank S! 应用服务 CLDC (1.0 或 1.1) + MIDP (1.0 或 2.0) + JSCL/MEXA

 

NTT DoCoMo 的 DoJa 配置文件是指 NTT DoCoMo 面向 FOMA 定制的规格,有很多版本。SoftBank 的 JSCL/MEXA 是指面向 SoftBank 终端定制的、可以根据实际需要进行扩展的规格,即所谓的“扩展配置文件”。

本文介绍的游戏基于 CLDC 1.1 + MIDP 2.0 的应用服务。


使用 API 创建游戏
 

在本例中,2.0 兼容应用程序采用了面向游戏开发的 API,收录在 Java 程序包 javax.microedtion.lcdui.game 中。该游戏程序包,即用户接口提供的类定义如下:

GameCanvas 提供游戏用户界面基础。
Layer 表示游戏中视觉要素的抽象类。下面的 SpriteTiledLayer 继承这个 Layer 的特性。
LeyerManager 管理一系列 Layer。
Sprite 游戏的基本要素,由一个或数个图像组合描述而成。组合数个图像时、每个图像分别用一个类似电影的镜头来表示,因此将所有图像组合起来后能够表现角色的动作。
TiledLayer 就像平铺式铺满的地板一样,用分割的帖图可以表现画面要素。具体来讲,就是用 TiledLayer 可以表现游戏的背景及游戏的结构件。


游戏生成器
 

游戏生成器由场景、平铺层、动画层组成,可以在图形环境中编辑上面的 LayerManager、TiledLeyer、Sprite。

图1 游戏生成器设计画面
图1 游戏生成器设计画面

 

要在游戏的场景和角色中使用 Sprite 和 TiledLayer,可以用游戏生成器将背景、角色和结构件等部分编写到图形中。剧本和人物动作等这些游戏操作内容必须全部通过 Java 程序描述。大致的作业流程基于以下事项:

 

  1. 准备背景和角色原型的图像文件
  2. 将图像文件导入到游戏生成器中
  3. 在游戏生成器的 GUI 环境中创建平铺层和动画层
  4. 通过游戏生成器结合平铺层和动画层,以创建场景
  5. 设计角色动作及游戏推进等程序

假设游戏生成器要使用 API 中说明的平铺层、动画层的 GameCanvas 类或者 GameCanvas 扩展类。游戏生成器将编辑后的结果全部保存在 Java 类中,同时自动生成平铺层和动画层的 getter 方法并将其保存在类中。调用此获取方法可以生成平铺层和动画层的实例并返回给调用源,因此可以使用 GameCanvas 类的实例获取方法来得到对象。最后,可以从继承 MIDlet 类的主程序(确切来讲相当于包含 Java SE 的 main 方法的类)中调用这个 GameCanvas (继承)类时,游戏应用程序的开发就大功告成了。

游戏生成器创建、保存的类的源代码,大多数只能用来做参考。您可以通过游戏生成器对它进行修改,我们为您预留了可以编辑直接代码来追加特定处理的地方。

要通过 NetBeans 打开游戏生成器,需要创建 MIDP 应用程序项目,并在项目中创建新的视觉游戏设计图。实际试用的时候打开样例项目比较好,从主菜单选择样例项目的方法:“文件”>“新建项目”>“样例”>“Mobility”>“MIDP”>“通过游戏生成器创建的简单游戏”,这样就可以打开游戏生成器了。

接下来,我们按顺序来看看这 5 个作业的概要。


准备和导入图像文件
 

将 1 和 2 结合起来说明。

图2 用做素材的图像文件
图 2 用做素材的图像文件

 

在游戏生成器中创建平铺层和动画层时,需要使用嵌入平铺层中的图像和用作动画层帧的角色图像。比如说,NetBeans 中预留的示例图像文件含有纵横方向单位为 16*16 像素的背景、建筑物和角色,它们可以作为最基本的部件在游戏生成器中使用。在游戏生成器中导入图像时,需要指定分割图像的纵横像素值,因此在导入上面的图像时,如果指定为 16 像素,如下图所示,图像将被分割为 16*16 大小的贴图导入到游戏生成器中,然后可以将各个贴图作为独立的部件使用。

图3 游戏生成器设计画面
图 3 导入到游戏生成器中的图像文件

 

在 Java 程序中处理平铺层(TiledLayer 类)和动画层(Sprite 类)时,这些经过分割的帖图将被赋予索引编号,我们可以通过索引编号来访问它们。比如在上图中,左上角茶色帖图的索引编号是“1”,而第一行中间位置上的红色屋顶图像可以通过索引编号“9”来访问。索引编号“0”表示图像未被赋予任何职能。


在游戏生成器中的 GUI 环境中创建平铺层和动画层
 

步骤 3:分别指定平铺层和动画层的相关内容。

平铺层

在平铺层的编辑画面,可以配置各个读入图像的部件。在下图中,中间是平铺层的编辑画面,其下方列出了利用读入图像生成的平铺层的索引编号,左下方是当前图层的信息。

图4 平铺层的编辑画面
图 4 平铺层的编辑画面

 

在平铺层中,可以通过“准备和导入图像文件”中说明的索引编号来访问图像,平铺层的信息由游戏生成器保存在 2 维整数数组中。下例表示将索引编号为“7”的图像粘贴到平铺层的第 1 行和第 1 列中(平铺层的行、列编号从 0 开始)。同样,将索引编号为“16”的图像粘贴到第 1 行、第 3 列中。

int tiles[][] = {
{ 7, 3, 17, 6, 6, 6, 6, 35, 23, 16, 16, ... }
{ 7, 3, 5, 16, 16, 16, 16, 16, 26, 16, ...}
....
{16, 16, ..... }
};

 

在 Java 程序中,TiledLayer 采用如下所示的结构。

TiledLayer tl = new TiledLayer(colums, rows, image, tileWidth, tileHeight);
/*
int columns : 图层的列数(图层上横向排列的平铺数量)。列编号从 0 开始。
int rows : 图层和行数(图层上纵向排列的平铺数量)。行编号从 0 开始。
Image image : Image 类提供的图像文件对象
int tileWidth : image 类中的平铺层的横向宽度(像素)
int tileHeight : image 类中的平铺层的纵向高度(像素)
*/

 

如下所示,在平铺层 tl 右上方的帖图(第 0 行 第 0 列)中配置红色屋顶的房子时(图像文件的索引编号为 9),可以使用 setCell() 方法来定义平铺层的图像:

tl.setCell(0, 0, 9);  // 将索引编号为“9”的图像复制到平铺层的第 0 行和第 0 列中

 

如下所示,游戏生成器自动生成平铺层的获取方法并将其保存在类中〔下面的 getMyImage() 方法用于读入图像文件并充当 Image 对象的返回方法〕。

public TiledLayer getMyTiledLayer() throws java.io.IOException {
if (MyTileLayer == null) {
MyTileLayer = new TileLayer(24, 23, getMyImage(), 16, 16);
int tiles[][] = {
{ 7, 3, 17, 6, 6, 6, 6, 35, 23, 16, 16, ... }
{ 7, 3, 5, 16, 16, 16, 16, 16, 26, 16, ...}
....
{16, 16, ..... }
};
for (int row = 0; row < 23; row++) {
for (int col = 0; col < 24; col++) {
tl.setCell(col, row, tiles[row][col]);
}
}
}
return myTiledLayer;
}

 

还可以在图层中嵌入动画,显示动画的图层叫做“动画层”。比如说,准备好以下图像,然后将各个图像定义为帧之后就可以实现灯光火焰摇曳的情景。

图5 燈火的炎
图 5 灯光的火焰

 

以纸质笔记本上的“翻页动画”涂鸦为例,绘制在每张纸上的画就相当于 1 个帧。游戏生成器可以通过设置帧来创建动画,如下所示,将每个图像都当做 1 个帧并且按顺序粘贴起来,这样便可以实现动画效果。下面的图像有点不好解释,但上面的 4 个图像按从左到右的顺序配置后,用 200ms 的速度来切换图像,就可以表现出进行此类编辑的情形。按下播放键一边确认一边继续编辑。完成后的动画(这里就是指摇曳的灯火)可以配置在平铺层的任何位置。

图6 应用平铺层的编辑
图 6 编辑动画层

 

在程序中,这个动作也是通过使用索引编号访问来实现。如下所示,创建一个单维数组,其中保存了图像各帧的索引编号(假设火焰各张图像的索引编号从右到左依次为:89、90、91、92),然后将这个数组传递给 TiledLayer 类的 createAnimatedTile() 方法,此平铺层的索引编号就重新分配并且做为返回值返回。

int[] AnimTorchSequence001 = {89, 90, 91, 92};

// tl 是 TiledLayer 类的实例
int AnimTorch = tl.createAnimatedTile(AnimTorchSequence001[0]);

 

如果在定义平铺层的 2 维数组中使用此平铺层的索引编号 (上例中为返回到 AnimTorch 的整数) ,那么就可以创建包含动画平铺的平铺层。

int tiles[][] = {
{ 7, 3, 17, 6, AnimTorch, 6, 6, 35, 23, 16, 16, ... }
{ 7, 3, 5, 16, 16, 16, 16, 16, 26, 16, ...}
....
{16, 16, ..... }
};

 

在上例中,我们定义了 200ms 的显示间隔,这个显示间隔仅仅做为游戏生成器创建的静态值保存在用于实际控制游戏的类中。这个显示间隔没有硬性规定必须在游戏生成器中定义,但是,如果以后游戏生成器扩展的话,它可能做为实际显示代码的一部分使用。

动画层

使用游戏生成器创建动画层和上面创建动画平铺的方法大体相同。首先创建相当于游戏角色的动画层,这样便可以在动画层中定义相应角色的复数动画。比如下面的图像是 NetBeans 提供的示例,它用一个个镜头表现角色的动作:第 1 行向下行走、第 2 行向上行走、第 3 行左右行走。事先准备好这些图像,并在动画层中将其设置为帧,就可以准备好游戏中上场的角色了。在程序中调用创建好的动画层和动画层中定义的动画,就可以让角色沿各个方向移动,或者做出特定动作。

图7 歩くキャラクタ
图 7 行走的角色

 

游戏生成器只能保存动画层帧的信息,将其做为包含索引编号的单维数组,动画层的动画对角色实际的动作信赖性很大。目前的游戏生成器虽然可以定义动画层,但无法定义画面中动画层的动作,而单维数组是用来表示被保存的帧的推进的,如何使用这个数组,只能交由用户处理。


使用游戏生成器将平铺层和动画层组合起来创建场景
 

步骤 4。

将创建好的平铺层和动画层组合起来就可以做成场景了。最简单的场景拥有一个平铺层和一个动画层,此时,平铺层就是背景,可以实现角色在一个背景下的动作。但更多情况下,场景由多个平铺层重叠而成。比如,角色向下行走时,如果遇到树木就就不能前进了,像这种设置障碍物的情况也是常有的。这时,预先在别的图层中定义障碍物,程序处理就变得简单多了。比如在下图中,一个场景“Forest”由 4 个平铺层组合而成,游戏者看到的是“Forest”画面,而它内部却是由 Things、Trees、Water 这3个图层叠加而成。

图8 複数的レイヤーを重ねて一つ的シーンを作成するイメージ
图 8 重叠数个图层来制作场景

 

程序是用来描述操作和处理的,比如说角色与“Trees”图层的图像重叠时的处理,或者角色与“Water”重叠时的处理等,因此可以描述角色走近水池和撞到树等动作。更具体一点来说,Sprite 类提供了一个 collidesWith() 方法,我们假设角色叫托马斯(Thomas),那么程序就可以描述“托马斯与平铺层 Trees 的图像发生冲突时的处理”。

...
private Sprite spriteThomas; //一个叫“托马斯”的角色
private TiledLeyer tlTrees; // 平铺层「Trees」
...
if (this.spriteThomas.collideswith(this.tileLayerTrees, true) {
// 托马斯与平铺层 Trees 的图像发生冲突时的处理
...
}
...

 

下图展示了如何通过游戏生成器创建场景。在确认平铺层以及动画层重叠情况的同时,还可以定义初始显示位置,图中 Z 列表示在图层中的位置(最前面为 0)。下图中各项目的含义:编辑中的场景从下至上按 Base、Water、Things、Trees 平铺层的顺序依次重叠,上面的两个动画层 Karel 和 Thomas 也在配置中。

图9 场景中的图层编辑
图 9 场景中的图层编辑

 


编写角色动作及游戏推进等程序
 

步骤 5。

目前,游戏生成器的功能就是这些,它可以用来准备游戏中使用的背景、结构件和角色。这些信息都保存在类文件中,可以通过获取方法访问它们。随后,我们可以从 GameCanvas 类或其他类中访问这些信息,从而实现游戏操作。所有这些都可通过直接编写 Java 程序来实现。

在实际编写游戏时,从必要的作业整体来看,MIDP 2.0 的游戏 API 能做到的只是编程作业的冰山一角,而游戏生成器可以做到的又是这其中的一小部分。如果您对实际的游戏开发感兴趣,建议多阅读这方面的相关书籍。


参考资料