分享
 
 
 

J2ME Game开发笔记(整编版)

王朝java/jsp·作者佚名  2006-05-12
窄屏简体版  字體: |||超大  

J2ME Game开发笔记(整编版)

2006.5重贴于CSDN BLOG

注:我从2004年9月份到2005年8月份在csdn blog上断断续续记录的开发笔记,并在www.j2medev.com上发表过三篇整理版的笔记。现在将这些笔记重新分类整理。

如果有人转载这篇东西,请包含所有内容,不要删改!我的Emai:happyfirecn@yahoo.com.cn

---------------一般类问题------------------

1 J2ME中查表法使用三角函数

CLDC和MIDP都没有提供三角函数,而且CLDC1.0中也没有浮点数,所以我们的选择是查表。使用8位定点数的sin和cos表。下面是wtk自带demo中的代码,只提供了有限的几个角度,实际使用时根据需要细化角度值。

// sines of angles 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, all *256

private static final int[] SINES =

{ 0, 44, 88, 128, 165, 196, 222, 241, 252, 256 };

// angle is in degrees/10, i.e. 0..36 for full circle

private static int sineTimes256(int angle)

{

angle %= 36; // 360 degrees

if (angle <= 9) // 0..90 degrees

{

return SINES[angle];

}

else if (angle <= 18) // 90..180 degrees

{

return SINES[18-angle];

}

else if (angle <= 27) // 180..270 degrees

{

return -SINES[angle-18];

}

else // 270..360 degrees

{

return -SINES[36-angle];

}

}

// angle is in degrees/10, i.e. 0..36 for full circle

private static int cosineTimes256(int angle)

{

return sineTimes256(angle + 9); // i.e. add 90 degrees

}

(2006.5 注:有一些算法可以生成三角函数值,这样只要在游戏载入时生成一下函数表即可,节省一些数据)

2 J2ME中使用随机数

产生0~n之间的随机数:

(ran.nextInt()>>>1)%n

(ran.nextInt()&0x7FFFFFFF)%n

产生-n~0之间的随机数:

(ran.nextInt() | 0x80000000 )%n

3 尝试IO优化

正在开发的一个游戏,由于读地图的时候做了图片切割,所以速度比较慢。(在我开发上一个游戏的时候,读取地图时没有装载切割图片,速度非常快,看来IO操作的速度和createImage,drawImage相比是微不足道的)对于IO的优化也许根本不会明显的提高速度,但我还是试了一下。

分析了一下代码,在最初的代码中为了比较方便的读取各种类型的数据,使用DataInputStream套接InputStream。可是我仔细看了一下我读取得数据,居然都是byte,唯一的一个char也是被我用两个byte手工组装起来的。这下,DataInputStream看来是不需要了。于是我做了个实验,没改动之前读取地图耗时1242ms,将DataInputStream去掉直接使用InputStream耗时1065ms,虽然每次试验的结果都稍有不同,但大概还是节约了200ms左右。

还能再加快点吗?再观察一下代码,我发现数据是通过多次的read操作读取进来的。太过频繁的io操作会不会降低速度呢?如果用一个字节数组作缓冲一次性将数据都读进来会不会快点?嗯,试一试才知道。但是我怎么知道一个流的大小呢?InputStream的avaliable方法总是返回-1啊!打开两次流,第一次先计算大小?对了,还有一个方法。直接将文件大小写到文件前面。地图文件是用自己的编辑器生成的,知道大小很容易。于是我在文件前面用两个byte纪录了文件的大小,先从流中读取2个byte,得到文件大小后,再用read(byte[],int,int)方法将整个流读取到缓冲中。然后,我的所有数据操作都从缓冲中读取。好,试验一下,结果是:1154ms。阿? 慢了近100ms。事实证明了这个猜想是错误的。原因?也许只有了解KVM的机制才知道。

弄完速度的问题,我又觉得读取文件的try块太大了,因为是边读边处理数据,所以try块变得很大。try块太大会增加class文件的大小。于是我用一个方法将读取byte的操作封装起来,当然这个方法是声明为private static的,但究竟能不能内联,只有编译器和kvm才知道。在这个方法内部从流中读取一个字节的时候采用了try,catch结构,这就使一个大try块分散成若干小try块。试验了一下,耗时1089ms,诶,还是慢了点。现在对于速度的要求比空间更高,更何况减小try块节省的10几个字节打包后基本忽略不计了。所以这个优化又失败了。

小结:能使用简单流的时候就不要使用复杂流,不要太相信理论上的说法,只有试了才知道。

注:试验数据是Nokia3100手机的实机测试数据,在Nokia 3300上这个数据更小些,最快约800多ms

4 压缩还是不压缩

做J2ME的都知道Midlet Suite的容量实在太小了,于是不免想做点压缩。前些天,我就尝试了一次压缩。我自己定义的地图文件里有3层数据,其中2,3层有大片连续分布的相同的值。 唉?我一琢磨,使用一个简单的行长编码压缩,仅对这个值进行行长编码,算法很简单速度又不慢,却可以大大减小地图文件的大小。看起来真的很不错诶!说干就干,忙了半天,又改地图编辑器,又改游戏中读地图的代码。总算搞定,试了一下,原来2.23k的一个文件被压缩到900多字节。好像很不错啊,接着我打了个jar包,却突然发现这个jar文件好像并没有比原来小阿!似乎还大了点。我连忙找出备份的代码,果然原来的jar更小点!怎么回事啊??我突然想到,jar本身就是压缩格式的。难道。。。我赶快用winrar打开两次的jar文件观察。~~~~~原来如此!原来的jar中,2.23k的文件的包大小为185字节,而我现在的jar中,900多字节的文件的包大小为216字节。也就是说,我自己先压缩一遍的文件打包后还不如不压缩的小!

看来自己做压缩之前,一定要先看看你想压缩的文件在包里面的大小。还有对于png文件,使用某些工具优化后,在包里面的大小却变大了。这个还真是要注意阿~!

(05.12.31注:某些压缩算法确实比zip压缩效率要高,可以使用,不过副作用是解压导致loading时间变长)

(2006.5注:有些时候,需要节省一下内存,可以将数据打包压缩一下,package & compress模式,存在内存中,需要时解压)

5 同时多处异常

程序出现exception时,在一个外包函数处捕获到了,显示为函数a出现异常,然后去a中捕获却没捕获成功,但是仍然发生了异常.

原来是外包函数中调用的另一个函数b也产生了同样的异常.

同时多处异常-小心!

----------------开发工具问题-----------------

1 Eclipse Tips

1.在工具条上有个文本形象的按钮"show source of selected element only".当编辑类的某个成员(方法或域)时,按下这个按钮,则当前窗口会只显示你正在编辑的类成员.再按一下则恢复.

2.显示java文件行号.菜单中选择Window->Preferences打开Preferences窗口后选择Java->Editor,在右边的选项中选中Show line numbers.

显示非java文件行号.在Preferences窗口中选择Workbench->Editors->Text Editor,同样右边的选项中选中Show line numbers.

3.编辑代码时,按ctrl+/可以注释当前行或选中的多行代码;按Atrl+/可以显示自动完成代码的提示。

4.选中代码,按 ctrl+shift+F 格式化代码

5.输入syso,按atrl+/可出来 System.out.println("") ;

2 运行Nokia模拟器的一个注意事项

这是一个老问题了,原来用WTK的时候就有,在WTK中启动Nokia的模拟器,如果先前已经打了包,那么运行的是打包的程序,想当年经常会很郁闷为什么改动了没效果,后来养成一个习惯,将jar装到手机测试后随手删除。

今天用JBuilder的时候又碰到了这个问题,也是Nokia的模拟器,如果已经建立了一个archive,那么Nokia模拟器运行的总是包,呵呵,所以要么将archive从project中remove,要么每次都rebuilder这个archive。

3 Eclipse集成Motorola模拟器

在Eclipse的菜单/工具条中选择Run->External Tools,打开面板后,选择program,然后new一个新的配置

1 在Location中填入Moto模拟器的路径,如:C:\Program Files\Motorola\SDK v4.2 for J2ME\EmulatorA.1\bin\emujava.exe,Moto的不同模拟器支持n种不同机型,需要看moto sdk的文档才知道。

2 在Arguments里填入执行的参数,包括jad路径,模拟器使用的机型。如:"${project_loc}\deployed\${project_name}.jad" -deviceFile Resources\V600.props

我是让模拟器执行deployed里面的jad/jar,${project_loc}是工程路径,${project_name}是工程名。这里选择的机型是V600.

说明:这种方法的局限在于只能执行jar,所以每次运行前必须打包。实际使用前需要为没种机型配置一个run,由于使用了通配参数,所以所有的工程都可以使用一个配置

(05.12.31注:现在某些MotoSDK已经可以和Eclipse集成了!)

4 初次使用JBuilder 7-若干小问题

(1) MobileSet问题

JBuilder7需另外安装MobileSet, Mobileset自带了一个WTK. 如果不安装MobileSet,JB7配置JDK时不能自动识别WTK,安装MobileSet后,可以通过配置JDK的方法加入新的WTK

(2) 资源文件问题

JBuilder的所有源文件都应该放在source path中,可以在工程属性中设置source path,资源文件也一样。既可以和源文件放在一个source path(即文件夹)中,也可以放在另外的source path中。需要注意的是,JBuilder只默认识别一定数量的后缀,如png,如果你使用了其他后缀的资源文件,如dat,bin,需要先把该文件通过add files加入到工程中,选择文件属性,设置为copy,这样该后缀的文件就被识别为资源文件了。

(3) 光标不对问题

最简单的办法-改字体,我改成了第一种字体(JB7中),感觉和默认字体没什么不同。至于这个问题的根本解决方法网上有文论述。

(4) 鼠标滚轮无效问题

据说这个问题只在JB7和以下版本中存在,原因是只有J2SDK1.4以上才支持滚轮,所以需要将JB7的JDK改成1.4的. 方法是修改JBuilder7\bin\jdk.config文件,将javapath和addpath两行修改,例如:

# javapath ../jdk1.3.1/jre/bin/hotspot/jvm.dll

javapath Y:\j2sdk1.4.2\jre\bin\server\jvm.dll

# addpath ../jdk1.3.1/lib/tools.jar

addpath Y:\j2sdk1.4.2\lib\tools.jar

5 百宝箱应用编译打包事宜

1 编译时,设置javac 的target vm为1.1即可通过移动检测。wtk中无法实现。在Eclipse中可以在java-compiler-Compliance and Classfiles中做以下设置:

Compiler compliance level: 1.4

Generated .class files compatibility: 1.1

Source compatibility: 1.3

(2005.12.31注:JBuilder中也有类似的选项,如果使用命令行或Ant,都只要将javac的targetVm参数设置为 target 1.1)

2 用eclispe打混淆包。但eclipse编写jad中文会出现乱码,所以用wtk编写正确的jad,然后用wtk打包(注意不能覆盖eclispe打的包),这是为了用wtk获得正确的jad和manifest文件。将elcipse打包出的jar解压,用wtk生成的mainifest代替原jar中的mainifest文件,然后用winrar打包(zip格式,可选最大压缩,注意要选择所有的文件后打包,不要将外面的整个目录打包).最后将jad中的jar size改为这个最新的jar的字节数。

(2005.12.31注:我不用eclipse很多年,据说现在的eclipse me新版没这问题了,我当时用的时候eclipse me的版本才0.4.6)

另:1. Nokia S60,SE k700机器中显示的游戏名字为MIDlet-1中的名字,而Nokia40为MIDlet-Name中的名字

2. 根据sp提供的资料Nokia 7650 游戏不能用中文名(其实NGageQD可以)

----------------机型相关问题-----------------

1 Nokia S60 IO操作内存泄漏不可不察

Nokia7650,3650

游戏运行过程中,有时会出现“存储已满”的对话框,出现的位置不固定

游戏运行过程中,有时出现“应用程序错误 NullPointerExcept”,“程序已关闭 MidpUi”的对话框

游戏运行过程中,有时会出现“程序已关闭 MidpUi ViewSrv 9”的对话框,出现的位置不固定

其实这个问题是由S60的getResourceAsStream方法内存泄漏的bug引起的,由于每次切换地图时io操作都要读取大量数据,内存泄漏积累到一定程度就引起了“存储已满”,白屏,死机,进而会引起null pointer异常等。解决方法是尽量减少io操作的次数。如果内存够大就一次将资源读入。

2 NokiaS60模拟器异常退出

症状:模拟器自动关闭,没提示任何错误

原因:使用了Nokia UI API中的灯光或振动控制,而Nokia S60部分机型和对应的模拟器不支持这两个特性.

3 NokiaS60 UI API bug

1 旋转后,并以clip的方式向缓冲上贴图,clip无效

2 无法创建透明muttable Image

此两点,致命伤,带来许多不变

4 Nokia S60的几个问题

(1) 不能每帧调用 System.gc(),否则严重降低fps

(2) Nokia S60机器的不同机型对于translate 和 setClip的处理不一样。在Nokia N-Gage QD等机型中,setClip是相对于translate以后的坐标计算的,而在Nokia 6600,6670等机型中,setClip不受translate的影响,永远只相对于屏幕左上角(0,0)点计算。所以如果在Nokia6670中,使用先translate再setClip的方法画子图,则会出现错误。为了统一代码,在Nokia S60中不要使用translate,即使用,两次translate之间不要进行setClip.修改后的画子图函数为:

public static void drawSubImg(Graphics g,Image img,int x,int y,int sx,int sy,int swidth,int sheight)

{

g.setClip(x,y,swidth,sheight);

g.drawImage(img,x-sx,y-sy,GLT) ;

g.setClip(0,0,width,height) ;

}

(3) 部分Nokia机型(6600,6670等)退出后报错null pointer exception的解决方法

不要在在主while循环中调用destroyApp,而改成检测一个标志,退出主循环后再调用destroyApp

boolean exit ;

...

while(!exit){

...

if(...){

exit = true ;

}

...

}

destroyApp(true);

注:可在destroyApp内部调用notifyDestroyed

5 Nokia"不能运行应用程序"错误新解

Nokia手机运行J2ME程序的时候出现“不能运行应用程序”的错误,一般都是内存不足引起的,但今天遇到这样的错误,却发现是另一个原因。即当使用nokia的UI API,DirectGraphics的drawImage时,如果旋转参数设置不当,也会出现“不能运行应用程序”的错误。

6 Nokia系统bug两则

(1) Nokia7650(V4.46)应用程序目录显示bug

应用程序安装后,打开应用程序目录,显示错误提示:

"程序已关闭 MidpUi USER9",应用程序目录无法进入。

分析后发现,原来是新安装的应用程序没有在mainfest.mf中的

midlet-1属性中指定应用程序图标,导致程序目录无法显示图标。

在我所见到NokiaS40机器上和NGageQD上,如果图标没指定或指定了但

不存在,将显示默认的图标。

此bug对于其它版本的7650或者其他机型是否存在尚不得知。

解决方法:使用seleQ将7650c:\system\midp中刚安装的程序目录删掉,即可正常进入应用程序目录。

在应用中使用自己的应用程序图标,并正确设置,以避免让用户遭遇到此bug。

(2) Nokia3100(v3.10)游戏目录振动设置与应用程序中使用振动冲突的bug

在Nokia3100等机型中,提供了一个游戏目录管理游戏类应用。该目录

可以设置目录中的游戏运行时是否发声,振动和使用网络。对于

Nokia3100(V3.10)如果将振动设置关掉,而在应用程序中使用了振动,则

会产生一个异常。此bug是在10个月之前发现的,记不清是哪个异常了。

此bug对于其它版本的3100或者其他机型是否存在尚不得知。

解决方法:在应用程序中使用振动的地方增加异常处理。

7 Motorola手机J2ME应用问题

(1) 应用程序图标

必须在jad 文件Midlet-Icon属性中指定图标文件,Midlet-1中指定的图标无效

Moto V系列图标大小应为15*15,其他尺寸无法显示。

(2) 左右软键问题

Motorola手机操作系统设定是:右软键确认,左软键取消。所以,我们的程序应该和这个习惯保持一致。

(3) Key Code

Moto V的key code不同于其他Midp2.0机器

左软键:21

右软键: 22

中键: 20

up: 1

down: 6

left: 2

right: 5

(2005.12.31注:在遇到新机型时,先测试一下keyCode比较好)

8 MIDP2.0 Canvas全屏问题

MIDP2.0 Canvas可以调用setFullScreenMode(true)将Canvas设置成全屏,但设置成全屏后新的Canvas width & height的获得对于不同手机却并不一样。

(1) MotoV系列

调用setFullScreenMode(true)后,将触发sizeChanged事件,此事件从系统接受两个参数,即为Canvas全屏后的width & height,通过这个事件可以获得新的宽高。

protected void sizeChanged(int w, int h)

{

width = w ;

height = h ;

}

但要注意,此事件并不是同步的,就是说如果你调用了setFullScreenMode(true)之后,立即使用新的width,height,有可能获得错误的结果。

(2) SE K700

调用setFullScreenMode(true)后,不会触发sizeChanged,而是通过getWidth和getHeight获得新的宽高。SE的setFullScreenMode调用后是立即返回的,所以可以获得正确的width & height

对于其他机型暂时还不了解

----------------移植问题-------------------

1 键盘响应

不同的机型对于键盘事件的响应不一样。经过我的测试,Nokia 7210,3100一次只能接受一个按键信息。(我写了个测试程序,发现如果一个键被按下后没有松开,则KeyPressed事件不会再产生,即其他键的按下操作无效)所以,用缓冲处理控制精灵运动时,如果规定只能四方向运动。如果up已按下,再按下left,精灵的运动方向并不会改变。不过将按键缓冲。按下up,按下left不释放,松开up---精灵就会向左运动。(在松开up后产生了left的KeyPressed事件!奇怪吗?松开up后我并没有进行"按下"left这个动作--left键在up松开前就被按下了且没有松开。似乎机器一直在监测键盘上各键的状态,并且有一个等待队列。)

在wtk的标准模拟器上就不同了。它可以接受多个按键“同时”按下的事件。所以如果用四个并列的if处理,精灵是可以斜着运动的。如果用if else处理,则如果已经按下一个方向键,然后再按下另一个,是否能改变方向受到if else 语句中顺序的影响。即,如果是 if(up) else if(left),则会先检查up键,所以如果已经按下了left,再按up是可以向上运动的,反过来就不行了。(这个自然:)

其它的机型由于手头没有机器,我也没试过。应该也是如此吧。

2 多机型移植经验谈

开发的时候平台是Nokia 40,然后移植到Nokia 60, Moto V, SE等,总结一下大概需要几个版本。

1。 Nokia 40版, 使用Midp1.0+Nokia UI API

2。 Nokia 60版, 使用Midp1.0+NOkia UI API

3. Nokia Midp2.0版,如6600,7610,使用Midp2.0

4。Moto V版,使用Midp2.0

5。 SE版,使用Midp2.0

6. 三星s100,s200,c100,使用Midp2.0

几点开发经验:

1。各机型之间最大的差别就是屏幕大小不同。所以游戏中要能自适应屏幕大小

2。不使用Midp2.0的GameAPI会比较方便移植,只要自己封装切图,旋转等函数即可。NokiaUI API和Midp2。0都支持图片选转。2.0支持的更好。注意Nokia 60不支持创建可变的透明图片,所以要用其他方法代替。

3。NOkia 6600,7610的UI API有问题(图片旋转),所以用了Midp2.0代替

4。支持MIDP2。0的机器程序大致相同,其中MOto,SE,SX都差不多。但也有细微差别。如SE不支持全屏。所以screenSizeChanged方法无效。

5。说说声音播放。NOkia s40上我坚决不用声音,一是容量限制,二是太难听。其他机型都可以支持midi和wav.不过没有发现可以同时播放2个midi的机型,moto v和se都可以同时播放midi和wav,nokia则不行。

3 移植一法

近日观察某些游戏的源代码(反编译后的),发现有个方法挺方便游戏的移植的。定义一个接口(比如stringTable)将游戏中所用到的静态字符串都定义为接口的常量。然后,让使用到这些字符串的类实现stringTable接口。这样移植的时候只要修改接口里面的字符串就行了。当然,对于游戏中坐标的定位,最好使用getWidth(),getHeight()还有Font类的方法stringWidth,不要定死了。这样的话,移植工作就比较轻松了。

4 检测机型

在J2ME开发中,往往遇到根据不同机型做不同事情的情况,比如Nokia3650的键盘比较特殊,Nokia7650不支持mmapi,所以需要获得机型信息。

下面是一段简单的代码

public static void checkPlatform()

{

String platform = System.getProperty("microedition.platform") ;

String tmp = null ;

if(platform.length()==9)

tmp = platform ;

else if(platform.length()>9){

tmp = platform.substring(0,9) ;

}

if(tmp!=null){

if(tmp.equals("Nokia3650")){

is3650 = true ;

}

else if(tmp.equals("Nokia7650")){

is7650 = true ;

}

}

}

获得机型信息还包括版本号等等,所以要截取前面的几个字符比较。

不过得到的机型字符串有时并不保险,如早期的Nokia N-Gage获得得并不是N-Gage,不过3650和7650还是可以的

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有