Java手机游戏开发简明教程 (SunJava开发者认证程序员 郎锐)

原文发布时间为:2008-07-30 —— 来源于本人的百度文章 [由搬家工具导入]css

Java手机游戏开发实例简明教程

(SunJava开发者认证程序员 郎锐)
1、手机游戏编写基础
1.手机游戏设计的基本原则
  目前,市面上的手机不管在处理能力仍是在存储容量上都不足与PC机相提并论,但也足以支持一个设计优化的微型游戏程序的运行。加上它的网络通讯能力,甚至还能够支持有联机对战能力的网络游戏。正是因为硬件设备的极大差别,才直接致使了手机游戏开发与传统游戏开发的极大差异。
  鉴于手机游戏与传统游戏开发的巨大差异,并考虑到做为其运行载体的手机的实际局限性,在进行手机游戏的设计时也有必须遵循的原则,即有限的游戏时间;缩短等待时间;精干的程序;寻求最大的兼容性。
  手机做为一种典型的MIDP设备,其能量供应是有限度的,在设计游戏时应当为用户提供一个有限的游戏时间,以避免游戏时间过长而大量消耗有限的能源。例如,能够把游戏时间限定在几分种以内完成或是将其划分为若干阶段分次进行。
  鉴于手机游戏的处理速度不可能太快的客观事实,为保持游戏的顺畅进行,就必须尽可能缩短游戏中的等待时间,尤为是在设计多人联机游戏时必定要注意这个问题。并且因为存储空间的限制,也要求设计精干的程序,不然将致使开发的游戏因过于臃肿而没法在手机执行。
  为手机游戏寻求最大的兼容性也是有必要的。因为不一样型号,不一样款式的手机不只支持的J2ME SDK(Java 2 Micro Edition SDK)不一样,屏幕尺寸及按键等也都存在差别。一款好的游戏若是由于底层的不兼容而局限于某一款机型显然是一种浪费,其实游戏的剧本、流程设计等彻底不用更改,只需针对其余系列的手机更换必要的低层处理就能够把游戏的市场拓展到其余机型。
2.手机游戏的实现技术
  虽然J2ME对手机游戏的开发已经成为主流,但并非说只有J2ME可以开发手机游戏,除此以外还有嵌入式和短信息等其余几种手机游戏实现技术:
  嵌入式游戏是指在手机出厂时就已经固化在芯片中的游戏。早期手机提供的游戏大可能是这一类游戏。因为这种技术不容许用户自由更新游戏,因此这类游戏很快便被淘汰了。
  短信息游戏是基于手机短信息服务(SMS)的手机游戏,经过向游戏服务商的服务器发送简短的文字信息来获取从游戏服务器反馈的结果信息。因为这种游戏是纯文本交互形式,所以一般较乏味且输入烦琐,游戏成本较高(一般1条短信0.1元)。
  随着Java技术的发展和Java手机的推广应用,使手机游戏进入J2ME时代。这种简化版本的Java极大地提升了手机对游戏的支持能力,它拥有比嵌入式和短信息手机游戏更为完美的界面,并且容许使用子图形动画。J2ME手机程序已经成为目前最佳的移动游戏开发环境,本文也正是围绕着J2ME技术展开对手机游戏开发过程的介绍。
3.《赛车》游戏的剧本设计
  本文将向你们介绍一款赛车游戏的制做过程。这是一款典型的体育竞技类游戏,它以公路做为赛车场地,选手为一辆赛车,障碍物为在公路放置的炸弹。因为只安排了一辆赛车,因此制定的游戏规则不以速度取胜,而是按玩家规避障碍物的灵巧程度来积分。这可用玩家安全驾车的时长来度量,由于玩家玩得越熟练,其规避障碍物的手法也就更灵巧,安全驾驶的时间也就越长。
  因为手机屏幕狭小,表现能力有限,并且在手机上也没有提供任何软硬件图像处理加速,因此在手机游戏中不可能追求PC机的表现效果。在追求视觉效果的同时,应尽可能作到简单。
  本游戏实例采用的是二维图形表现形式,以笔直无转弯的公路做为赛道。玩家将能够经过手机方向键控制赛车的左右移动,以规避随机布置在赛道上的炸弹,炸弹在随机布置后将再也不移动。若是赛车的任意部分与炸弹相接触即被断定为触弹爆炸,本局游戏结束。
2、配置Eclipse开发环境
  在使用任何一种语言进行编程时都离不开开发环境,Java语言也不例外,这里将向你们介绍一种很是著名的开发环境——Eclipse。
1.Eclipse基础
  (1)认识Eclipse
  Eclipse是一个开放源代码的、与NetBeans、Sun ONE Studio和Borland Jbuilder相似的一种基于Java的整合型可扩展开发平台。就其自己而言,它只是一个框架和一组服务,用于经过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(JDT)。其将来的目标不只仅是成为专门开发Java程序的IDE环境,根据Eclipse的体系结构,经过开发插件,它能扩展到任何语言的开发,甚至能成为图片绘制的工具。
  难能难得的是,Eclipse是一个开放源代码的项目,任何人均可如下载Eclipse的源代码,而且在此基础上开发本身的功能插件。也就是说将来只要有人须要,就会有创建在Eclipse之上的COBOL、Perl、Python等语言的开发插件出现。同时能够经过开发新的插件扩展示有插件的功能,例如,为了进行手机应用程序的开发,本文所涉及到的《赛车》游戏就是经过J2ME插件的扩展来加以实现的。
  (2)Eclipse的组织结构
  Eclipse是一个开放源代码的软件开发项目,它专一于为高度集成的工具开发提供一个全功能的、具备商业品质的工业平台。它主要由Eclipse项目、Eclipse工具项目和Eclipse技术项目等组成,具体包括Eclipse Platform、JDT、CDT和PDE等4个部分。JDT支持Java开发、CDT支持C开发、PDE用来支持插件开发,Eclipse Platform则是一个开放的可扩展IDE,提供了一个通用的开发平台。它提供建造块和构造并运行集成软件开发工具的基础。Eclipse Platform容许工具建造者独立开发与他人工具无缝集成的工具从而无须分辨一个工具功能在哪里结束,而另外一个工具功能在哪里开始。
  Eclipse SDK(软件开发者包)是Eclipse Platform、JDT和PDE所生产的组件合并,提供了一个具备丰富特性的开发环境,容许开发者有效地建造能够无缝集成到Eclipse Platform中的工具。Eclipse SDK由Eclipse项目生产的工具和来自其余开放源代码的第三方软件组合而成。Eclipse项目生产的软件以CPL发布,第三方组件有各自自身的许可协议。
2.Eclipse的下载与安装
  经过前面的介绍,咱们了解到Eclipse是一款很是出色和著名的开源项目。你只需登录Eclipse官方网站(www.eclipse.org)就能够免费得到这款优秀的开发环境。
  进入主页后单击“Downloads”连接,将出现镜像列表页面,从中选择较近的镜像点并进入下载页面,目前最新版本为3.0.1)。通常状况下,Eclipse同时提供了Release、Stable Build、Integration Build和Nightly Build等多个下载版本,建议下载Release或Stable版本。这里选择Release版本。
  进入该版本的下载页面,单击“eclipse-SDK-3.0.1-win32.zip”连接进行安装包下载(针对Windows平台)。同时,单击“eclipse3.0.1-SDK-win-LanguagePackFeature.zip”连接下载对应的多国语言包插件以实现软件的本地化。
  安装Eclipse的步骤很是简单:你只需将下载的安装压缩包按原路径直接解压便可。以后将多国语言包解压缩,并将解压获得的“plugins”和“features”文件夹去覆盖解压到Eclipse安装目录下“eclipse”文件夹下的同名文件夹便可。若是当前操做系统的JRE环境安装正确无误,运行Eclipse.exe将进入其默认界面。
  注意:这里的前提是JRE环境的安装正确无误,因为Eclipse自己是用Java语言编写的,而下载的安装压缩包中并不包含Java运行环境,所以须要用户本身另行安装JRE,而且须要在操做系统的环境变量中指明JRE中bin的路径。若是上述设置不正确,Eclipse将没法正常运行。另外,因为Eclipse版本升级较快,若是有更新版本,需先删除旧版本从新安装,而不能直接解压到原来的路径覆盖旧版本。
3.一些必要的配置
  (1)配置JRE
  为了保证Eclipse的正常运行,咱们须要配置JRE。你能够安装Sun的JDK或IBM的JDK,推荐使用1.4以上版本。由于只有使用1.4以上版本的JDK才能够享受到新增的HotSwap功能对于调试带来的方便。这里,咱们使用Sun公司的1.5.0版本JDK,你能够从Sun公司官方网站http://java.sun.com免费下载。
  (2)安装J2ME SDK
  为可以保证手机应用程序的开发,你还必须安装J2ME SDK。Sun公司的J2ME Wireless Toolkit(WTK)即是经常使用的一款J2ME SDK,它提供了运行J2ME应用程序所须要的库以及模拟器等,经过它能够进行程序的编译、校验、运行。有关WTK的信息可查询http://java.sun.com/products/j2mewtoolkit
  目前,J2ME Wireless Toolkit共分3个版本:1.0.四、2.0和2.1。其中,1.0.4版只能开发MIDP 1.0程序,2.0版能够开发MIDP 2.0应用程序,2.1版则能够同时开发MIDP 1.0、JTWI、自定义等3种环境。须要注意的是,并不是版本越高越好,必须视需求不一样而选择适当的版本,才能开发出能够在真机上运行的MIDP应用程序。这里选用的是WTK 2.1,你可从Sun公司官方网站免费下载,按默认方式安装该工具包并记下其安装路径以便之后在安装EclipseMe插件时使用。
  这里之因此选用Sun公司的J2ME Wireless Toolkit产品,是由于这样开发出来的手机软件能够具备更大的通用性。若是你只是出于为本身的爱机DIY应用软件的目的,则彻底能够根据本身使用手机的型号从相应厂商网站下载与之对应的J2ME SDK,这样开发出来的手机软件可以以更优的方式在真机运行。目前一些大的手机厂商开发的特定J2ME SDK主要有:Nokia的Nokia DEveloper's Suite与Nokia各款手机专属SDK;SonyEricsson的SonyEricsson J2ME SDK;Siemens的Siemens Mobility Toolkits等。
4.J2ME插件EclipseMe的安装
  经过上面的介绍,你如今应当理解:对手机程序的开发实际也就是等于对J2ME项目的开发。虽然上面咱们对环境进行了配置,使其可以支持J2ME开发,并且Ecilpse使用起来很是方便,但这对J2ME开发的支持仍是远远不够。下面,咱们将经过为Eclipse安装一个开发J2ME程序的插件EclipseMe来完善手机应用程序开发的最后一项准备工做。
  目前,EclipseMe的最新版本为0.5.5(eclipseme.feature_0.5.5_site.zip),你能够登录SourceForge网站http://eclipseme.sourceforge.net/免费下载。
  进入SourceForge网站后单击“Downloads”连接进入产品下载页面,该页面列有所有版本的EclipseMe插件及部分版本的源程序代码。单击须要下载的eclipseme.feature_0.5.5_site.zip,将出现下载镜像列表页面,你能够从中选取距离较近的镜像站点进行下载。
  对于EclipseMe 0.5.0版本及更早版本的安装,能够下载后直接将其解压到Eclipse安装目录下的“plugin”文件夹下便可很方便地完成对插件的安装。可是到了0.5.5版本之后,EclipseMe的安装方式发生了较大变化,再用之前的方法将不能成功安装插件。下面将给出EclipseMe这一版本插件的具体安装过程:
  启动Eclipse,单击“帮助→软件更新→查找并安装……”菜单命令,打开“安装/更新”对话框,选中“搜索要安装的新功能部件”选项。单击“下一步”按钮。
  在出现的对话框中单击“新建本地站点……”按钮,在打开的对话框中指定EclipseMe压缩包的当前解压路径,而后将会在“要包括在搜索中的站点”列表中出现以当前指定目录为名称的站点项目。选中该项目,展开其树型结构,能够看见其子项EclipseME也被同时选中。单击“下一步”按钮。
  提示:最好将EclipseMe压缩包解压到一个路径名中不包含汉字的文件夹下,例如,E:\EclipsMe\下,不然可能会在安装过程当中出现一些奇怪现象而妨碍安装过程的顺利的进行。
  在出现的对话框中选中“EclipseME”按钮。单击“下一步”按钮。在出现的对话框中单击“我接受许可协议中的条款”选项。单击“下一步”按钮。在出现的对话框中指定Eclipse插件要安装到的路径,你能够单击“添加站点”按钮,在出现的对话框中选择其余路径(最好仍是安装到Eclipse的安装目录下),单击“肯定”按钮完成便可。
  为查看EclipseMe插件是否成功安装,你能够在重启Eclipse后单击“窗口→首选项”菜单命令,打开“首选项”对话框。在左侧窗口看到J2ME项即标明EclipseMe插件已经成功安装。java


 

在“首选项”对话框中进行配置程序员

5.对EclipseMe插件的配置
  为了使新安装的EclipseMe插件可以正常工做,须要对其进行配置。展开J2ME项,选择“Platform Components”子项,在右侧窗口中将同步显示其详细配置。右键单击“Wireless Toolkits”选项,选择“Add Wireless Toolkit”命令,在打开的对话框中单击“浏览”按钮,在出现的对话框中指定先前安装的Wireless Toolkit路径。若是路径指定正确且Wireless Toolkit也安装正确,此时EclipseMe将自动检测出该目录所安装的Wireless Toolkit的版本,并显示在编辑框的下方。单击“完成”按钮,在“首选项”对话框右侧的配置窗口中将显示该Wireless Toolkit所支持的一些特性。若是你是针对某一机型的手机进行开发,能够重复上面的步骤将其余厂商的无线开发工具包添加其中。
3、搭建游戏框架
1.建立J2ME项目
  在Eclipse中首先建立J2ME MIDlet Suite项目“Racing”,全部后续的编码、调试和运行都是在这个工程中进行。
  启动Eclipse,单击“文件→新建→项目”菜单命令,在打开的对话框中展开“J2ME”选项,选中“J2ME Midlet Suite”子项后单击“下一步”按钮。在出现的对话框中设置项目名称和项目存放路径,通常保持默认路径便可。单击“下一步”按钮。
  在出现的对话框中对应用程序所支持的MIDP版本进行指定。若是考虑兼容性能够选择“J2ME Wireless Toolkit 2.1 MIDP 1.0 platform”选项。固然,你也能够选择“MIDP 2.0”选项。单击“下一步”按钮。
  在出现的对话框中对Java构建设置进行定义,一般保持默认值便可。单击“完成”按钮,EclipseMe将自动设置好项目的编辑及运行环境。你能够在导航器视图中单击刚才建立的项目,在右侧编辑视图中将能够查看EclipseMe生成的项目结构。算法


 

查看建立的项目编程

2.建立J2ME应用程序
  上面建立的MIDlet Suite,通常也称做MIDlet应用程序套件,它能够包含一个或多个MIDlet,只是在发布时是以MIDlet Suite为单位进行,咱们的一些实质性的工做都是在MIDlet中完成的。所以,须要继续添加J2ME MIDlet项“RacingMIDlet”到项目中。
  在导航器上单击鼠标右键,选择“新建→其余”菜单命令,在打开的对话框中展开“J2ME”选项,选中“J2ME Midlet”子项后单击“下一步”按钮。在出现的对话框中指定包(也能够保持默认值)和名称,单击“完成”按钮后,EclipseMe将自动生成框架代码,并将新建立的RacingMIDlet类按以下代码进行编辑:
  public class RacingMIDlet extends MIDlet {
   public Display display;
   public GameCtrl game;
   public RacingMIDlet() {
   super();
  }
   protected void startApp() throws MIDletStateChangeException {
   // 得到Display
   display = Display.getDisplay(this);
   // 得到Displayable
   Displayable current = display.getCurrent();
   if (current == null) {
   // 装载logo图像
   Image logo = null;
   try{
   logo = Image.createImage("/logo.png");
   }catch (IOException e) { }
   // 显示logo
   Alert splashScreen = new Alert(null, "郎锐2005年做\n版权全部(c)\n2005--2006", logo, AlertType.INFO);
   // 延迟4秒
   splashScreen.setTimeout(2000);
   //新建ChooseDemo对象
   game = new GameCtrl(this);
   // 显示闪屏界面
   display.setCurrent(splashScreen, game);
   }else {
   // 显示当前界面
   display.setCurrent(current);
   }
   }
   protected void pauseApp() {
  }
   protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
   }
   public void quit() throws MIDletStateChangeException {
   // 退出程序
   destroyApp(false);
   notifyDestroyed();
   }
  }
  这里经过一个Alert信息框完成对闪屏界面的显示,所使用的位图logo.png在开始能够暂用临时图像代替,最后再由美工完成的正式图像替换。
  由于游戏主题为赛车,所以本例使用的logo位图最好显示一些赛车的图标,并辅以具备艺术字效果的游戏名称。图标能够很方便地下载获得,而游戏名称的艺术字效果一般要由开发人员本身完成。除了可使用专业的设计软件外,还可以使用两种不一样颜色书写同字体、同大小的游戏名称,而后将深色文字置后,浅色文字错位少量后放置在前台的方法经过视觉错觉来实现立体字的效果。最后再与图标合成到一张PNG格式的位图,便可完成一个简单logo位图的制做。数组


 

Logo制做过程示意安全

  编辑完毕后,Eclipse将提示有多处错误存在,这主要是由GameCtrl类尚未添加形成的。接下来,向工程添加从Canvas类继承的GameCtrl类,并编辑其类为以下代码,以保存从RacingMIDlet类传入的MIDlet对象和对命令按键、方向按键的添加与响应:
  public class GameCtrl extends Canvas implements CommandListener{
   private final Command startCommand;
   private final Command quitCommand;
   private final RacingMIDlet midlet;
   public GameCtrl(RacingMIDlet midlet) {
   super();
   // 保存MIDlet类对象
   this.midlet = midlet;
   // 添加命令按键
   quitCommand = new Command("退出", Command.EXIT, 2);
   addCommand(quitCommand);
   startCommand = new Command("开始", Command.OK, 1);
   addCommand(startCommand);
   // 侦听按键响应
   setCommandListener(this);
   }
   protected void paint(Graphics g) {
   }
   public void commandAction(Command arg0, Displayable arg1) {
   if (arg0 == startCommand){
   // 用户开始游戏
   initialize();
   }
   if (arg0 == quitCommand){
   // 用户退出游戏
   try{
   midlet.quit();
   }
   catch(MIDletStateChangeException e){}
   }
   }
   private void initialize() {
   }
   protected void keyPressed(int keyCode) {
   // 获得按键动做
   int gameAction = getGameAction(keyCode);
   switch (gameAction) {
   case RIGHT:
   break;
   case LEFT:
   break;
   default:
   break;
   }
   }
  }
  这里除了新增的keyPressed()方法外,与之前介绍过的程序框架并无太大的差异。这个keyPressed()方法主要用来捕获用户的手机按键,因为在赛车驾驶时只需控制其左右移动方向便可,所以这里只对getGameAction ()方法返回的键值与RIGHT和LEFT进行比较。稍后将完成这两个分支的功能实现。
4、实现游戏界面
  因为将赛车游戏抽象为场地、选手和障碍物,所以在游戏的界面实现时也主要围绕这3个中心展开。
1.实现场地界面
  因为这里的公路是平直无转弯无路口的,所以展示到二维平面上就是一个矩形。能够想象,若是只在手机屏幕显示一个矩形,不管填充什么颜色,都很难使人联想到是一条公路。为了表现出公路的特征,不妨在公路中间绘制一条隔离车道用的斑点线。因为在比赛进行时,赛车与公路之间是相互运动的,而做为游戏的主角,赛车必定是不能超出玩家视线的。也就是说,赛车应当始终处于屏幕显示范围以内,这样一来,为了表现赛车的运动,就必须让公路动起来。一个简单的办法是,在绘制公路中间的斑点线时对同一位置的斑点进行交替绘制。服务器


 

简单展现公路特征网络

  可能从纸面上很难理解这样简单的处理怎么可以产生公路想后移动的效果,不妨将上图的公路中线看做13段连续的LED灯管,开始时为奇数的灯管点亮,为偶数的熄灭。接下来点亮的灯管熄灭,熄灭的点亮,如此反复,正如街头的霓虹灯,能够经过对灯管点亮、熄灭的控制来实现一种移动的视觉错觉。在代码实现上可在paint()方法中添加以下代码来实现对公路中线的绘制:
  // 绘制动态公路中线
  g.setColor(0, 0, 255);
  if (lineMode == true){
  lineMode = false;
  for (int i = 0; i < height; i += 20)
  g.drawLine(width / 2, i, width / 2, i + 10);
  }else{
  lineMode = true;
  for (int i = 10; i < height; i += 20)
  g.drawLine(width / 2, i, width / 2, i + 10);
  }
  其中,经过lineMode变量对虚线的绘制模式进行控制,width和height分别为屏幕的宽度和高度。在构造函数中分别经过getWidth()和getHeight()方法得到。为了可以以固定时间间隔周期性地调用paint()函数,可在程序初始化方法initialize()中建立一个定时器,并在定时器的执行方法run()中添加repaint()方法以完成对paint()函数的周期性调用。有关定时器的建立,可先向工程添加一个基于TimerTask类的新类NextFrame,用于周期性定时执行任务。并在GameCtrl类添加其类声明和另一个Timer类的对象:
  private Timer timer = new Timer();
  private NextFrame nextFrame;
  在须要开启定时器时,以nextFrame对象为参数去调用Timer类的schedule ()方法并指定时间间隔便可:
  nextFrame = new NextFrame(this);
  timer.schedule(nextFrame, 300, 300);
2.实现炸弹与赛车界面
  炸弹与赛车的界面实现,能够经过调用低级类Graphics中的相关绘图方法来绘制,也能够经过显示位图的方式来实现。前者几乎不占用内存,但绘制过程烦琐,后者的显示方法相比之下要简单许多但却要占用少许的内存。这里,咱们选用后者。框架


 

炸弹与赛车示意

  首先准备上图所示的两张PNG格式位图并将其添加到工程中。炸弹和赛车做为本游戏的主角,其图像在游戏过程当中将被频繁使用,所以,为方便使用可将与这两位图相关的Image对象定义为公有型的类成员变量。并在类构造函数中完成对位图文件的装载:
  try{
  // 装载炸弹图像
  bombImage = Image.createImage("/bomb.png");
  // 装载赛车图像
  carImage = Image.createImage("/car.png");
  }catch(Exception e) {}
  对于这种Image对象的绘制,可以使用Graphics类成员函数drawImage()方法,该方法的使用方法在前文已有过详细介绍。因为赛车须要左右移动,炸弹也要在被随机放置后不断从屏幕滑过,所以在绘制Image对象时,其位置最好能经过公有型的类成员变量来设置。这样就能够在一个专门的控制方法中对赛车和炸弹的显示位置进行调整,而在paint()方法中只负责对图形进行绘制,从而实现对游戏功能的模块化划分。下面这段赛车和炸弹图像的绘制代码将以各自图像的中心位置为基准点进行绘制,共完成一辆赛车和四棵炸弹的屏幕绘制:
  // 赛车水平位置
  public int carPos = 0;
  // 炸弹位置
  public int[] bombPosX = {0, 0, 0, 0};
  public int[] bombPosY = {0, 0, 0, 0};
  // 炸弹是否出界
  public boolean[] bombCanUse = {false, false, false, false};
  ……
  // 绘制赛车
  g.drawImage(carImage, carPos, height - carImage.getHeight(), Graphics.HCENTER | Graphics.VCENTER);
  // 绘制炸弹
  for (int i = 0; i < 4; i++){
   if (bombCanUse[i] == true)
   g.drawImage(bombImage, bombPosX[i], bombPosY[i], Graphics.HCENTER | Graphics.VCENTER);
  }
  这里的bombCanUse数组用来对当前炸弹是否出界予以标识,这里所说的炸弹出界并非指炸弹当前位置超出屏幕范围,而是在真实屏幕上方另设一连续的与真实屏幕等大的、可用来随机放置炸弹的虚拟屏幕。此虚拟屏幕和真实屏幕的并集才是炸弹的有效区域。凡是落在此区域内的炸弹均不予销毁,若是有炸弹移出有效区域,则在炸弹放置区从新随机放置一枚,始终保持炸弹有效区域内的炸弹总数为4个。


 

炸弹有效区域示意

  最后,必定要记得在paint()方法开始绘制下一场景以前经过下面的清屏语句擦除当前场景的显示。不然,在游戏开始后随着各类角色的移动,屏幕将变成一个“大花脸”。
  // 白色清空画布
  g.setColor(255, 255, 255);
  g.fillRect(0, 0, width, height);
5、角色移动与碰撞检测
  前面对游戏的骨架和界面都已经实现,但此时的游戏仍然毫无生气,由于咱们尚未实现其灵魂。接下来将要进行的角色移动与碰撞检测将可以使游戏中的主角动起来,并可以经过对当前游戏状态的检测来自行判断游戏是否结束。
1.角色移动
  (1)移动赛车
  因为道路的移动是经过交替绘制公路中线所引发的错觉来实现的。所以,实际真正须要移动的角色只有炸弹和赛车。本例将以赛车为基准,它始终处于屏幕下方,玩家能够经过手机左右方向键实现对赛车的左右移动。显然,对赛车的移动控制所有由玩家掌握,其控制代码只能在keyPressed()方法对左、右按键的分支处理中实现。因为在先前的设计中实现了显示与控制的分离,所以在这里只需对表示赛车水平位置的carPos变量取值进行修改便可。为防止赛车移出屏幕,须要添加必要的越界保护代码:
  // 获得按键动做
  int gameAction = getGameAction(keyCode) switch (gameAction) {
  case RIGHT:
   // 右移赛车
   carPos += 5;
   // 防止越界
   if (carPos > width - carImage.getWidth() / 2)
   carPos = width - carImage.getWidth() / 2;
   break;
  case LEFT:
   // 左移赛车
   carPos -= 5;
   // 防止越界
   if (carPos < carImage.getWidth() / 2)
   carPos = carImage.getWidth() / 2;
   break;
  default:
   break;
  }
  // 重绘屏幕
  repaint();
  (2)移动炸弹
  与赛车不一样,炸弹的移动控制由手机全权负责。只要游戏在运行,炸弹就不停的从屏幕上方滑落,对于相似的处理应当交由定时器任务类完成相关操做。NextFrame类成员方法run()将在定时器每次被触发时调用。
  在处理炸弹移动时,首先对炸弹是否超出有效区域进行检测。因为初始运行时屏幕没有炸弹,因此能够将其看成超出有效区域进行处理。对于这种状况,首先经过Random类的nextLong()方法获得两个随机数,而后分别以屏幕宽度和高度为模进行取模运算,其结果经越界限制后将做为炸弹的初始设置坐标。在每设置一棵炸弹后要及时对该炸弹所对应的bombCanUse元素设置炸弹有效值,以在后续的处理中执行下落显示。
  与赛车的左右移动相似,炸弹的下落能够经过不断增长其纵坐标来实现。只是在下落过程当中没必要进行越界保护处理,若是炸弹越过有效区域就经过bombCanUse将其标记为无效。将在下必定时周期重复前面的过程:
   for (int i = 0; i < 4; i++){
   // 炸弹没显示时设置初始位置,显示后水平位置固定
   if (gameCtrl.bombCanUse[i] == false){
   // 随机设置炸弹初始位置
   int x = (int)(rand.nextLong());
   x = (int)(x % gameCtrl.width);
   gameCtrl.bombPosX[i] = x;
   int y = (int)(rand.nextLong());
   y = (int)(y % gameCtrl.height);
   // 将炸弹设置在虚拟屏幕
   gameCtrl.bombPosY[i] = -y;
   // 限制炸弹水平位置
   if (x < bombWidth)
   x = bombWidth;
   if (x > gameCtrl.width - bombWidth)
   x = gameCtrl.width - bombWidth;
   // 标志第i个炸弹进入可视区
   gameCtrl.bombCanUse[i] = true;
   }else{
   // 炸弹下移
   gameCtrl.bombPosY[i] += 3;
   // 炸弹出界检测
   if (gameCtrl.bombPosY[i] > gameCtrl.height + bombHeight / 2)
   gameCtrl.bombCanUse[i] = false;
   }
  }
  若是此时运行程序,虽然能够实现赛车在布有炸弹的公路上行驶的效果,并且玩家也能够控制赛车的前进方向,但却存在一个致命的缺陷——当赛车和炸弹相撞时,炸弹依旧下落,赛车依旧行驶,好像什么都没有发生同样。这是因为没有为游戏添加碰撞检测代码所致。
2.碰撞检测
  碰撞检测是游戏中常用的一种重要算法。用于检测游戏中的两物体是否发生表面接触,例如,子弹是否命中歹徒,炮弹是否击中目标等等。只有进行了碰撞检测才有能在出现上述状况后实现歹徒被击毙、目标被摧毁等结果。


 

炸弹与赛车发生碰撞示意

  上图展现了炸弹与赛车发生碰撞时的全部可能情形。从图中能够看出,只要炸弹彻底进入图中的虚线矩形框就必然与赛车发生了碰撞。对本游戏而言,发生了碰撞即意味着赛车被炸毁,游戏结束。因此,在炸弹下落过程当中不难写出以下碰撞检测代码:   // 碰撞检测   if (gameCtrl.bombPosY[i] + bombHeight / 2 >= gameCtrl.height - carHeight * 3 / 2 && gameCtrl.bombPosY[i] - bombHeight / 2 <= gameCtrl.height - carHeight / 2 && gameCtrl.bombPosX[i] + bombWidth / 2 >= gameCtrl.carPos - carWidth / 2 && gameCtrl.bombPosX[i] - bombWidth / 2 <= gameCtrl.carPos + carWidth / 2){   // 结束游戏   gameCtrl.isGameOver = true;   // 关闭定时器   cancel();    }  其中,carWidth、carHeight、bombWidth和bombHeight变量分别是经过carImage和bombImage对象调用各自的getWidth()和getHeight()方法而返回获得的赛车图像尺寸和炸弹图像尺寸。若是发生碰撞,将经过公有型的boolean类型变量isGameOver来指示游戏的结束。同时调用TimerTask类成员方法cancel()关闭先前设置的定时器。  对于非胜负类游戏,因为在游戏结束时并无胜出方,因此通常都是以积分的形式反馈给玩家当前局所取得的分数。对于本例,分数显然是与安全驾驶时间成正比的,在程序实现时,能够在定时器每次触发run()方法时对积分进行累加,并在游戏结束时经过下述代码以信息框的形式将当前积分反馈给玩家:  isGameRun = false;  // 显示logo  Alert result = new Alert("本局积分", String.valueOf(score), null, AlertType.INFO);  // 延迟4秒   result.setTimeout(2000);  // 显示闪屏界面  midlet.display.setCurrent(result, this);  通过上述辛勤工做,一款真正的J2ME手机游戏程序已经完成!6、测试与发布游戏  单击“运行→运行”菜单命令,在打开的对话框左侧配置窗口中右键单击“Wireless Toolkit Emulator”选项,选择“新建”命令,在对话框右侧将显示相应的运行配置选项。通常可保持默认设置,也能够在“Emulation”选项卡中对默认设备进行指定。一般选择“DefaultClolorPhone”选项便可,其模拟的是在彩屏手机上的运行效果。因为目前支持Java的手机通常配置都不是很低,绝大多数也都是彩屏配置,所以“DefaultClolorPhone”选项应该是比较大众。固然,你也能够设置“DefaultGrayPhone”等其余选项以模拟在单色或其余配置的手机上的运行效果。  最后,单击“运行”按钮执行咱们建立的赛车游戏。  固然,本例做为一款教学性质的游戏实例,没有作太多的完善与优化。给你留下了较大的游戏扩展空间。你能够在本游戏基础上尝试进一步的扩展和修改,例如,增长先后方向键以模拟加大油门和刹车;另外增长一些参赛车辆;根据玩家游戏进行时间的长短动态调整游戏难度,包括加快车速、增长障碍物等等。代码编写无误后能够先在PC上的模拟器中运行调试,并对出现的问题进行修改,一切无误后再打包发布。

相关文章
相关标签/搜索