四、 构建示例游戏
为了更好地理解这些API和它们各自的类,你最好动手开发一个简单的移动游戏。这里是一个单人的离线游戏,通过障碍物线路的驾车游戏。玩家使用左键和右键用于改变车的方向到左边或者右边以防止与障碍物的碰撞。游戏在发生碰撞并显示得分后结束。该游戏命名为HardDrive。
注意:虽然这个示例游戏是使用J2ME Wireless Toolkit 2.1_01和J2SE 1.4.2_07 SDK在Windows 2000平台上开发的,但是,其它版本的与另外一些平台相匹配的Wireless Toolkit和J2SE SDK也可以利用。
现在开始构建游戏程序HardDrive。从前一节中得知,你第一个需要开发的程序是HardDriveMIDlet(HardDriveMIDlet.java),它扩展了javax.microedition.midlet.MIDlet类。
(一) HardDriveMIDlet.java
列表1.1:该代码片断来自于文件HardDriveMIDlet.java
import javax.microedition.midlet.MIDlet; import javax.microedition.lcdui.*; public class HardDriveMIDlet extends MIDlet implements CommandListener { ... ... ... ... ... ... ... ... |
HardDriveMIDlet还实现了javax.microedition.lcdui.CommandListener接口来接收命令事件,它们是在应用程序执行和处理期间产生的。当发出EXIT,CANCEL,BACK,OK,STOP以及类似的命令-这些命令通过使用软按钮(在移动电话屏幕附近的特殊的按钮,除了箭头键以外)产生并被HardDriveMIDlet的commandAction()方法所处理-时,这些命令事件发生。为了提高效率,可把这些命令添加到画布上去。
HardDriveMIDlet用作所有canvas的容器,这些canvas是一些描述可用于在移动设备屏幕上进行绘制的对象。这里,midlet包含了HardDriveCanvas,它扩展了javax.microedition.lcdui.game.GameCanvas类。GameCanvas是一个专门的画布,用于为游戏程序绘制有效的动画图像,还能够查询为实现平滑动画效果而采取的脱屏图像缓冲技术有关的关键状态。
HardDriveMIDlet包含的另外的一个canvas是GameOverCanvas,它扩展了javax.microedition.lcdui.Canvas类。Canvas是一个简单canvas,用于绘制文本,线段以及简单的形状等。当需要在屏幕上进行简单的绘制时-例如为显示游戏初启画面,游戏结束屏幕以及游戏指令屏幕-这个canvas被扩展,而取代了繁重的绘制。一个游戏程序的midlet可以包括任何个数的canvas,但是每次仅显示一个canvas,这是通过使用javax.microedition.lcdui.Display类的setCurrent()方法来实现的。
HardDriveMIDlet还包含3个另外的重要方法,也称作lifecycle方法。它们是startApp()、pauseApp()和destroyApp(),分别相应于该midlet的Active,Paused和Destroyed状态。在HardDriveMIDlet的startApp()方法中,实现实例化HardDriveCanvas并通过使用HardDriveCanvas类的方法addCommand()把EXIT命令添加到它上面去。
(二) HardDriveCanvas.java
HardDriveCanvas实现了一个java.lang.Runnable接口来使它自己可以运行在自己的线程中,这对于独立地执行游戏循环是必需的。该游戏循环被连续不断地执行,直到终止游戏的必备条件满足为止(在本例中,当汽车碰撞到障碍物上或者在任何时候当玩家使用Exit按钮退出游戏)。
列表1.2:文件HardDriveCanvas.java中的游戏循环
public void start() { gameRunning = true; Thread gameThread = new Thread(this); gameThread.start(); } ... ... ... ... ... ... ... ... public void run() { Graphics g = getGraphics(); //... ... ...一些代码 while (gameRunning) //游戏循环 { tick(); input(); render(g); //... ... ...一些代码 try { Thread.sleep(timeStep ); //... ... ... ...一些代码 } catch (InterruptedException ie) { stop(); } } |
列表1.2显示HardDriveCanvas.java中的游戏循环。这是一典型游戏循环,它包含了依次对tick(),input()和render()方法的调用。tick()方法检查是否停止该游戏的必需条件已经满足;如果满足,即相应地改变游戏的状态。方法input()处理游戏的键盘(keys assigned for游戏playing)输入并为每一次按键,如一个游戏元素的运动,执行必要的动作。根据其所处的状态,着色任务由render()方法来完成。
HardDriveCanvas也使用一个javax.microedition.lcdui.game.LayerManager的实例来增加和管理多层的HardDriveCanvas,其中每一层代表一个精灵。一个精灵是一部游戏中一个基本的可视化元素,或者是一个在游戏画布上移动的character,而且它能够与其它精灵(在这个示例中,汽车或障碍物都是精灵,它们可能进行彼此碰撞。)进行交互。每一个精灵形成一个虚拟层,它可能是全部或者部分透明地置于画布之上;这些层彼此以堆栈方式堆叠。一个精灵是一个javax.microedition.lcdui.game.Sprite类的对象,它负责显示、变形和旋转精灵以及进行精灵碰撞检测。被内部使用的tick()方法使用精灵类的collidesWith()方法进行碰撞检测。HardDriveCanvas实例化一个ObstacleManager类的对象,它用于着色并移动游戏画布上的障碍物精灵并检查是否它们与汽车精灵相碰撞。
(三) ObstacleManager.java
ObstacleManager负责创建和管理随机出现在汽车路径上的障碍物。为了简化和便利,ObstacleManager.java硬编码了每次出现在汽车路径上的障碍物的最大数目值。这个值可以根据需要进行修改。
列表1.3:该代码片段来自于ObstacleManager.java
private static final int MAX_OBS = 10; //... ...一些代码 |
为了在随机位置创建和显示障碍物,ObstacleManager使用了一种简单的策略。它产生最初的10个障碍物精灵,并使用LayerManager来把这些精灵添加到游戏画布上去。然后,它通过使用随机产生的x和y坐标值来设置它们的位置并开始朝着游戏画布的底部移动它们。一旦每一个障碍物到达了画布的底部而没有碰撞到汽车,它的位置就被通过使用相同的技术重新复位,而同时游戏的得分增加1。所以,ObstacleManager重用了同一个障碍物精灵并随机地显示它们。
(四) GameOverCanvas.java
GameOverCanvas是一个简单的canvas,它接收来自于HardDriveMIDlet游戏持续时间以及得分信息并显示之。