基于j2me技术的手机游戏开发内容摘要:

TPS协议、串口通信、 Socket 通信、 UDP 协议。 J2ME扩展包技术更是使得扩展 GCF后能够使用 Java编写手机蓝牙、红外、 USB等通信程序。 GCF本身是一个基于 Java语言接口技术的框架。 图 8 GCF 框架 3 游戏实现 游戏设有多个关卡,每个关卡中 青蛙都有不同的任务:在第一关中,跳跃的青蛙从底 部 12 开始,要在规定的 90 秒中通过 3 条马路到达顶部的目的地,每条马路上都有一个道具要捡取,马路上是行使的各种汽车,青蛙不能碰撞到汽车,不然就丢掉一次机会,要重新回到起点开始,第一关一共有三次重试机会。 图 9 游戏第一关 创建项目 与 应用程序管理器 在下载和安装已经发布的 Java 手机程序时都是以单个 MIDlet Suite( MIDP 程序套件)作为单位的 , 每个 MIDlet Suite 包含一个或者多个 MlDlet 程序 , 作为对 MIDlet 进行签名时也是以 MIDlet Suite 为单位的,数据共享、用户配置数据、持久存储等都能在同一个 MIDlet Suite 中共享,发布程序时以每个 MIDlet Suite 进行打包成 JAR 文件(一般同时间创建一个相应的 jad 文件来描述该 JAR 文件,在网络环境中需要提供 JAR 文件发送到互联网上供用户下载)。 在 J2ME 游戏创建 MIDlet Suite:创建一个名称为 Frogger 的移动应用程序项目,便于在 IDE 中管理项目资源,项目目录结构如下 [4]: Frogger/ 项目各种操作配置文件,如运行、测试、重点配置 j2mepolish对象,描述各种各种扩展元素 source/src/ 游戏源码存放位置 resources/ 存放游戏资源文件位置,如:图片、字体等 nbproject/ NetBeans 项目描述文件 dist/ 最终分发打包程序存放位置 build/ 目的地 汽车障碍 道具 起点,青蛙 13 再创建一个名称为 类做为游戏主类继承 :所有的 MID 应用程序主类都必需继承自 MIDlet 类。 MIDlet 实际上是 一个应用程序管理器(AMS)的接口, 实际程序中 通过 实现 MIDlet 类的 startApp()、 pauseApp()和 destroyApp()方法 来管理 整个 程序的生命周期: 图 10 MIDlet 程序的状态转换 下面是游戏的主类: // 引入相关的类包 import。 import .* public class Frogger extends MIDlet implements CommandListener { private Display display。 // 其它代码略:这里主要声明 Frogger 类用到成员变量,和整个游戏的全程对象 private final List mainMenu。 public Frogger(){ super()。 // 程序管理器构造 = new List(Frogger, )。 } // 开始运行游戏 protected void startApp(){ = ( this )。 ( )。 } protected void pauseApp( ) { } 14 protected void destroyApp(boolean unconditional){ } public void mandAction( Command cmd, Displayable screen ) { } } 这里只是一个最基本的 MIDlet 子类, 它的任务主要是启动游戏并创建一个菜单显示到屏幕上。 CSS 菜单设计 启动游戏时,首先展示一个启动画面和主菜单。 这是用户对游戏的第一印象,必须要力求精美。 在这个游戏中我用 CSS(层叠样式表 )来定制 UI 组件的:使用网页制作工具为不同的手机制作不同外观的菜单,下图展示了为不同手机设计的菜单: 图 11 不同机型 菜单 风格 截图 :左,默 认风格, 右,SonyEricsson/K700 首先在 j2mepolish标签:定义 build元素的 usePolishGui属性为 ture,使编译时支持 CSS。 再在程序中添加预处理项,如: ////Frogger类中 游戏 主要 导航菜单 、设置 CSS预处理 : //style mainScreen = new List( Frogger, )。 //style mainMenuItem ( ( ), null)。 //style mainMenuItem ( ( ), null)。 //style mainMenuItem ( ( ), null)。 //style mainMenuItem ( ( ), null)。 这样就可以在资源文件中随意的定义 CSS外观 , resources/义的默认属性,其中的列表 CSS属性将得到上面右幅图的菜单项效果: 15 //例如 mainMenuItem的 CSS风格定义 .mainMenuItem { margin: 2。 padding: 5。 background: none。 /**获得菜单项背景透明效果 **/ fontcolor: fontColor。 fontstyle: bold。 fontsize: small。 layout: center。 checkboxplain: none。 checkboxselected: url()。 } 游戏屏幕处理 FroggerScreen 类是游戏的核心,它控制循环操作,包括青蛙的移动,图像的绘制以及读取和响应用户的输入。 通常连续的刷新屏幕会使得屏幕图像效果不稳定,出现如闪烁等情况,而及时的按键响应对本游戏更为重要,这里需要使用游戏设计中两个重要的概念 [5]: ● 双缓冲屏幕操作 ● 实时按键响应(包括组合按键操 作) J2ME 为优化设计为这两种操作提供了本地 API: J2ME Game API。 FroggerScreen 继承了 GameCanvas 类。 绘制操作自动将下一屏幕绘制到脱机屏幕上,然后使用 flushGraphics()直接把图像从脱机屏幕上拷贝到当前屏幕上。 getKeyStates()同时间侦测从上一次操作后的多个游戏按键的状态,使得按键不被“遗忘”,这样保证了操作处理的实时性,甚至可以模拟游戏操作性极强的组合按键使用。 如果需要抑制主某些时间段的按键操作,只需要使用简单的背对背调用就可以了。 设计 Frogger 类: public class FroggerScreen extends GameCanvas implements Runnable { public FroggerScreen( Frogger midlet ) { super( true )。 } //开始游戏 public void start() { Thread thread = new Thread( this )。 ()。 } public void run() { 16 int keyState = getKeyStates()。 if (keyState != 0) { // 处理按键状态 } // 刷新屏幕 : flushGraphics()。 } } 游戏引擎设计 任何游戏的核心都不过是用来完成各种游戏任务的一个循环 ,在这个游戏里 就是移动的车辆,玩家 , 检测玩家输入 , 检测碰撞情况:将所有的东西渲染到 LCD 屏幕上 ,但是需要足够快的速度, 使的玩家有一种真实感。 为了实 现这个,我们需要使用 游戏循环的东西:任何需要处理的任务都是游戏循环的一部分,通常把每秒种循环次数称为 CPS(cycles per second)及帧率 , 也有的称为 FPS(frames per second)。 为了实现游戏循环,需要一个独立于应用程序的执行进程 ,这样才能对它进行控制 (如暂停程序 )。 在 Java 中通常有两种方法可以实现: 定时器 与线程。 ● 定时器 的 GameCanvas 为我们提供了 getKeyStates()主动按键查询功能 , 可以主动处理按键动作,通过 TimerTask 与 Timer 类的配合来模拟多线程, 可以很方便的开启多个线程,并且代码的结构比较清晰,但是创建类的数量比较多,系统开销稍微大一些。 下面详细进行一下介绍 : Timer 类是一个定时器,可以每隔一段固定的时间做一件事情,而且可以很方便的停止这些动作。 依次为:构造对象: Timer timer = new Timer(); 对象创建以后,可以使用其中的 schedule 或者是 scheduleAtFixedRate 方法起启动一个任务 (Task)动作。 需要停止时,可以调用 Timer 对象的 cancel 方法实现,该方法可以停止该 Timer 启动的所有任务 (Task)。 TimerTask 类是一个线程类,所有线程的动作代码都写在该类内部。 TimerTask是一个抽象类,在实际使用过程中,一般是继承 TimerTask类,然后实现实际的操作,停止 TimerTask 可以使用 TimerTask 对象里面的 cancel方法。 ● 线程 通过 Thread 类或 Runnable 接口 实现类的多线程操作控制循环 , 游戏使用了 Runnable接口: ()方法使得线程方法更容易在游戏中控制稳定的帧率。 将帧速率控制程序段加入到 Frogger 类 中: //设置游戏每秒钟最大循环次数为 30 private final static int MAX_FRAMES_PER_SECOND = 30。 17 //计算每秒钟循环的时间为 1000/30 =33ms private final static int TIME_PER_FRAME = 1000 / MAX_FRAMES_PER_SECOND。 //在主循环中控制游戏的帧速率 public void run() { long lastCycleTime = ()。 long cycleStartTime。 while (!) { //标记循环开始时间 cycleStartTime = ()。 // move players and actors: int keyState = getKeyStates()。 if (keyState != 0) { //处理按键 } lastCycleTime = ()。 // 绘制脱机屏幕 : (, 0, 0 )。 // 刷新屏幕 : flushGraphics()。 // 计算需要 sleep()的时间 : long timeForFrame = () cycleStartTime。 if (timeForFrame TIME_PER_FRAME ) { try { ( TIME_PER_FRAME timeForFrame )。 } catch (InterruptedException e) { } } } } 制作二进制数组地图 、关卡初始化文件 由于 《青蛙远行》 是一款关卡类游戏, 每进入一关都存在大量的可重用的初始化代码,考虑将这些数据放入二进制文件。 这样每进入一关只需要读取 相应的初始化文件进行关卡初始化即可,如地图的创建、玩家坐标等等 [6]。 这样的设计为游戏节约了大量的代码段中间 ,即所有的关卡只需要一份代码,而且关卡的编辑和调试也相当简单:不需要修改任何代码,只要修改被读如的文件即可。 18 图 12 用二进制编辑器编辑 level1 的关卡数据 本游戏使用 J2ME Polish binaryeditor 进行编辑,将关卡地图和其它只读数据都采用这种灵活的方式存储: 定义每关公有的初始化数据,如重试次数、青蛙跳跃距离等 level[关卡序号 ].data 定义每关特有的初始化。
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。