科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道MIDP 2.0开发J2ME游戏起步之一

MIDP 2.0开发J2ME游戏起步之一

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

MIDP2.0(Mobile Internet Device Profile)技术进行游戏开发中用到的最重要的包是:javax.microedition.lcdui.game,本文通过对样例游戏Tumbleweed的代码分析,将展示MIDP2.0技术的几个主要部分。

作者:马岩编译 来源:天极网 2007年9月4日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共3页)

线程类Thread的使用

游戏中仅仅涉及了线程类Thread的最简单应用,在这个最简单的例子中,有几点是需要特别说明的。

本例中,随时发起一个新线程是很必要的。例如游戏的背景动画,即使玩家没有触发任何按钮,它也一直处于移动状态,所以程序必须必须有一个循环逻辑来一直不停重复刷新屏幕,直到游戏结束。游戏设计的逻辑是不能让这个显示循环线程作为主线程,因为主线程必须是系统管理软件可以调用来控制游戏运行或者退出。在对决状态时测试游戏,我发现如果我用循环显示线程做主线程,对手就很难对按键做出及时反应。当然,通常当你计划进入一个将在代码运行整个生命周期做重复展示的循环时,发起一个新线程是一个很好的方法。

请看我的Thread子类的运行逻辑:一旦线程被发起,立刻进入主循环(while代码块)中。

第一个步骤是检查Jump类是否在上一次循环后调用了requestStop(),如果是,循环中断,返回运行run()方法。

否则,如果玩家没有暂停游戏,你要激发GameCanvas响应玩家的击键事件,接着继续游戏的动画效果,这时你需要循环线程一毫秒的暂停。这事实上会引起一帧画面在下一帧展示前会暂时停滞(1毫秒),但这可以使击键事件轮巡任务正常进行。

如上提及,玩家击键信息将被另一个线程修改,所以游戏显示循环需要设置一个短暂的等待,确保这个修改线程排队进入,有机会在极短的一瞬修改按键的状态值。这可以保证玩家按下键盘时得到迅速的响应,这就是游戏设计中常用到的1毫秒的把戏。

Listing 2 是GameThread.java源码。

Listing 2. GameThread.java

package net.frog_parrot.jump;

/**

* This class contains the loop that keeps the game running.

*

* @author Carol Hamer

*/

public class GameThread extends Thread {

//---------------------------------------------------------

// Fields

/**

* Whether the main thread would like this thread

* to pause.

*/

private boolean myShouldPause;

/**

* Whether the main thread would like this thread

* to stop.

*/

private boolean myShouldStop;

/**

* A handle back to the graphical components.

*/

private JumpCanvas myJumpCanvas;

//----------------------------------------------------------

// Initialization

/**

* Standard constructor.

*/

GameThread(JumpCanvas canvas) {

myJumpCanvas = canvas;

}

//----------------------------------------------------------

// Actions

/**

* Pause the game.

*/

void pauseGame() {

myShouldPause = true;

}

/**

* Restart the game after a pause.

*/

synchronized void resumeGame() {

myShouldPause = false;

notify();

}

/**

* Stops the game.

*/

synchronized void requestStop() {

myShouldStop = true;

notify();

}

/**

* Start the game.

*/

public void run() {

 // Flush any keystrokes that occurred before the

 // game started:

 myJumpCanvas.flushKeys();

 myShouldStop = false;

 myShouldPause = false;

 while(true) {

if(myShouldStop) {

 break;

}

synchronized(this) {

 while(myShouldPause) {

 try {

wait();

 } catch(Exception e) {}

}

 }

 myJumpCanvas.checkKeys();

 myJumpCanvas.advance();

 // You do a short pause to allow the other thread

 // to update the information about which keys are pressed:

 synchronized(this) {

try {

 wait(1);

} catch(Exception e) {}

 }

}

}

}



GameCanvas类

GameCanvas类主要是用来刷新屏幕显示自己设计的游戏背景图象。

GameCanvas类与Canvas类的不同

GameCanvas类能描绘设备分配给你的屏幕的所有区域。javax.microedition.lcdui.game.GameCanvas类不同于它的超类javax.microedition.lcdui.Canvas在于两个重要的方面:图形缓存和轮巡键值的能力。这两个变化给了游戏开发人员面对需要处理诸如击键事件、屏幕刷新事件时需要的更强大、精确的控制手段。

图形缓存的好处是它可以使图形对象在后端逐渐生成,然而在生成时可以瞬间显示,这样动画显示将会更加平滑。在Listing 3中的advance()方法中可以看到如何使用图形缓存。

(请回想方法advance()是在GameThread对象的主循环中被调用)。注意对于调整屏幕显示和重画屏幕,你所要做只是调用paint(getGraphics()),然后再调用flushGraphics().

为了使程序更有效率,如果你知道需要重画的只是屏幕的一部分,你可以使用flushGraphics()方法的另一个版本。作为一种经验,我尝试过用对repaint()方法的调用来替代对paint(getGraphics())和flushGraphics()的调用,再接着调用serviceRepaints()来实现屏幕重画,注意调用serviceRepaints()的前提是你的类必须是从Canvas类扩展而来,而不是GameCanvas。在本例简单的游戏调用来看,性能差别并不大,但如果你的游戏有大量复杂的图形,GameCanvas的使用毫无疑问将极大地增强性能。

轮巡按键状态的技巧对于游戏进程的管理是很重要的。你可以直接扩展Canvas类,同时如果你的游戏支持键盘操作,你必须实现keyPressed(int keyCode)接口。

接着玩家击键事件促使应用管理软件调用这个方法。但如果你的程序完全运行在自己的线程里,该方法可能根据游戏规则在任何点被调用。如果你忽略了样例中的同步处理代码块,这可能导致潜在的错误发生,例如一个线程正在修改与游戏当前状态值相关的数据而同时另一个线程正在利用这些数据进行计算的情况。样例程序很简单,你可以很容易跟踪到当你调用GameCanvas方法getKeyStates()时,是否获得了击键信息。

getKeystates()方法的一个额外利用是它可以告诉你是否多键被同时按下。一次仅有一个键值码被传入keyPressed(int keyCode)方法中,所以即使玩家同时按下多个键,对它来说也只是增加被调用的次数而不是一次传递多个键值。

在一个游戏中,每一次按键的精确时刻常常是非常重要的数据,所以Canvas类的keyPressed()方法其实缺失了很多有价值的信息。注意Listing 3中的checkKeys()方法,你可以看到getKeystates()方法的返回值中包含了所有按键信息。

你所要做的是将getKeyStates()方法的返回值和一个给定键值比如GameCanvas.LEFT_PRESSED进行“与”(&)运算,借此判断是否给定键值被按下。这是一个庞大的代码段,但是你可以找到它的主要逻辑脉络是,首先,主循环GameThread类告诉GameCanvas子类JumpCanvas去轮巡按键状态(细节请见Listing 3中的JumpCanvas.checkKeys()方法),接着一旦按键事件处理完毕,主循环GameThread类再调用JumpCanvas.advance()方法告诉LayerManager对图形做出相应的修改并最终在屏幕上画出来。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章