原文:http://blog.sina.com.cn/s/blog_56dee71a010007n8.html
下午闲着没事,就看前段时间买的《Java手机游戏实例手册》,还到书上介绍的网站去下载了源代码。可是下载的源代码并不完整,例如第六章的源代码就只有第二节的那个程序,没有后面几节的程序;而且也没有后面讲解中用到的图片。于是只好自己在网上找图片,并且改写例子程序。本来我不太瞧得起这本书的,觉得它太简单了,买它只是想在无聊的时候打发下时间的,但是经过自己改写程序,才发现,要真正动手,才会注意到一些细节问题的;要做多了,才会熟悉。
虽然这个程序在高手看来是过于简单的,但是这个是我学习Java手机游戏编程的第一个自己写的程序,我也不用怕被人笑话,把这么简单的东西放到博客上来,因为学习总是有个过程的嘛。
功能很简单,仅仅是赵云骑着马不停地从屏幕左边走到右边。背景是用小图片拼接起来的,因为我把原图片处理得不好,所以上边一点还看得过去,下边就不对了。
程序由两个文件组成:MyCartoonMidlet.java和MainCanvas.java。
这是MyCartoonMidle.java的内容:
package mycartoon; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; import javax.microedition.lcdui.Display; public class MyCartoonMidlet extends MIDlet { public MainCanvas m_canvas; public MyCartoonMidlet() { super(); } protected void destroyApp(boolean arg0) throws MIDletStateChangeException { // TODO 自动生成方法存根 } protected void pauseApp() { } protected void startApp() throws MIDletStateChangeException { m_canvas = new MainCanvas(); if (null != m_canvas) { Display.getDisplay(this).setCurrent(m_canvas); while (true) { try { Thread.sleep(100); m_canvas.repaint(); } catch (Exception e) {} } } } }
这是MainCanvas.java的内容:
package mycartoon; import java.io.IOException; import javax.microedition.lcdui.*; import javax.microedition.lcdui.game.*; public class MainCanvas extends Canvas { public Sprite m_sprite; public TiledLayer m_bk; public LayerManager m_manager; MainCanvas() { Image image; try { /* 创建精灵并居中显示*/ image = Image.createImage("/zhao_yun.png"); m_sprite = new Sprite(image, 160, 120); m_sprite.setFrame(0); int x = 0; int y = getHeight() / 2 - 60; m_sprite.setPosition(x, y); /* 创建背景图层*/ image = Image.createImage("/bk.jpg"); m_bk = new TiledLayer(4, 8, image, 60, 40); m_bk.setPosition(0, 0); setCells(); } catch (IOException e) { e.printStackTrace(); } m_manager = new LayerManager(); m_manager.append(m_sprite); m_manager.append(m_bk); } /* 设置背景图层的各单元格*/ private void setCells() { int x, y; m_bk.setCell(0, 0, 2); m_bk.setCell(1, 0, 3); m_bk.setCell(2, 0, 4); m_bk.setCell(3, 0, 5); for (y = 1; y < 8; y++) { for (x = 0; x < 4; x++) { m_bk.setCell(x, y, 6); } } } protected void paint(Graphics g) { int n, x; n = m_sprite.getFrame(); n = (n + 1) % 6; m_sprite.setFrame(n); x = m_sprite.getX() + 10; if (x > 240) { x = -160; } m_sprite.setPosition(x, m_sprite.getY()); /* m_bk.paint(g); m_sprite.paint(g); */ m_manager.paint(g, 0, 0); } }说明:
这是一个简单的Java Midlet 程序。Mid代表Mobile Information Device。Midlet这个名字大概跟Java Applet的命名类似。Applet程序都需要一个继承自Applet类的类,其中包含init(),destroy()等方法,Midlet程序也很类似地有一个继承自Midlet的类,其中含有startApp(),pauseApp(),destroyApp()等供系统回调的函数。这个还是比较容易理解的。
第23到26行:创建一个MainCanvas对象,并将它设置为当前显示对象。
第27到35行:每隔100毫秒进行一次刷新,实现动画效果。书上用的是while(true),作者实在是水平不咋的啊,难道不知道这样会不必要地使 CPU占用率很高的吗。说句题外话,这书是“‘十一五’全国计算机应用与软件技术专业领域技能型紧缺人才培养培训教材”,我看这书的这种等级刚好适合很多计算机专业刚毕业的学生。如果各种收费很高的IT培训就是用这个作为教材的话,吾窃以为,不值得花钱去参加培训,买本书自学好了。
第17到24行:创建精灵对象(骑马的赵云)并且设置其位置在画布中央。
J2ME提供了Sprite类表示游戏中的精灵对象。Sprite类可以利用一幅图片生成活动的精灵对象。当然,这幅图像就是把动画的各帧放在一起了, Sprite类可以较方便地管理各帧。为了准备这幅图片,我还费了点心思的。
(1) 先从网上找到了一个骑马的赵云的gif动画,第一个问题就是怎么把各帧提取出来,合并成一张图片。在网上搜索了一阵子,发现了一个实用的小工具:png超级伴侣pngmate。它可以提取gif动画的各帧,组合成一张图片,还可以方便地进行各种设置。可惜是个控制台程序。我打算有空的时候为它写一个简单的界面,把它包装起来。
(2) 用pngmate把gif动画转换成一张图片后,先把显示精灵部分的程序写好,运行起来后才发现,精灵的白色背景没有去掉,显示效果不好。在网上搜索了好一阵子,也没有找到合适的工具。最后才发现,原来我一直用的TotalCmd文件管理器就有这个功能,我是有点舍近求远了。
第27到30行:创建背景图层。m_bk = new TiledLayer(4,8,image,60,40);这句中前两个参数是图层的列数和行数,后两个参数是cell的宽度和高度,开始的时候我写好了程序,运行的效果却始终跟我想想的不一样。后来看了Java无线工具包文档才发现是参数的次序写错了。42行的setCells()函数设置各个cell 显示的tiled的编号。Java WTK提供的这个TiledLayer还真是比较好用,实用的。
第37到39行:创建图层管理器,将精灵对象和背景图层加入到图层管理器中。注意添加的次序,是从前往后依次添加的。如果说Z方向是沿屏幕向外的(向着人盯着屏幕看的眼睛,与视线方向相反),也就是沿Z轴负方向的次序依次添加。(这会儿发觉“视线”这个词好像跟“心理学”一样,虽然不正确,但是已经约定俗成了^_^)。
第69到73行:注释掉的部分是不使用图层管理器时候的绘制代码。这个绘制次序跟把对象(图层)添加到图层管理器的次序相反。