游戲引擎的結構很多,不過基本上都是在一個游戲主循環內實現。程序裡面的主循環包含了程序框架的最主要的結構體。J2ME的程序一般都包含兩個class文件,一個是MIDlet,一個是Displayable。一般我都是把游戲的主要代碼放在Displayable這個類裡面。這個類是基於事件驅動的程序,有三個主要相應函數void paint(Graphics g),void keyPressed(int keyCode),void keyReleased(int keyCode)。
1. 使用Runnable和創建線程的主循環
一般主體的做法就是讓Displayable這個類實現Runnable這個接口,然後在其構造函數中創建一個線程,啟動其run()函數,而run函數裡面就包含了游戲的主循環。下面是我在仙劍裡面的片斷代碼。
public class GameMIDlet extends MIDlet {
static GameMIDlet instance;
Display display;
GameDisplayable displayable = null;
public GameMIDlet() {
instance = this;
display = Display.getDisplay(this);
displayable = new GameDisplayable();
}
public void startApp() {
display.setCurrent(displayable);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
displayable.running = false;
}
public static void quitApp() {
instance.destroyApp(true);
instance.notifyDestroyed();
instance = null;
}
}
public class GameDisplayable extends FullCanvas implements Runnable {
/** 主控制線程 */
Thread MainThread = null;
/** 游戲時鐘間隔 毫秒為單位 */
public static long timeinterval = 20;
public static boolean Isstable = true;
/* 用於游戲時鐘的變量 */
public static long timeold = 0;
public static long timenow = 0;
public long interval = 0;
public static long frames_per_second = 0;
int count = 0;
long second = 0;
public static boolean running = true;
public GameDisplayable() {
// 開始主線程
Thread MainThread = new Thread(this);
MainThread.start();
}
public void run() {
while (running) {
timenow = System.currentTimeMillis();
interval = timenow - timeold;
if (interval >= timeinterval) {
timeold = timenow;
Game_Process();
if (second != (System.currentTimeMillis() / 1000)) {
second = System.currentTimeMillis() / 1000;
frames_per_second = count;
count = 1;
}
else
count++;
}
lib.sleep(30);
}
}
其中關於控制主循環速度的代碼可以不要,但是lib.sleep(30)必須保留,因為在Nokia 60的手機上,如果去除了sleep(30),那麼游戲將無法切換回來。同時,在游戲中任何一個內部循環中,也必須加入sleep(30)這個等待,才能讓游戲可以切換回來,至於為什麼這樣做,我暫時還不清楚。30ms是我測試過沒有問題的數值,可能比30ms還小的值也是沒有問題的。
同時,在MOTO的手機上,必須將游戲的主循環放在一個線程中,游戲才能切換回來,不過可以不加上面說的sleep(30)延時。
2. 不使用線程的主循環辦法
這個辦法只能在Nokia的平台上實現,而我只建議在Nokia 40的平台上做,這樣不需要線程,道理上來說節約了一些內存,如果不是內存很緊張的機型,那麼最好還是使用上一種辦法。
游戲的主循環放在MIDlet的class裡面,具體做法如下:
public class GameMIDlet extends MIDlet {
GameDisplayable displayable = null;
/** 游戲時鐘間隔 毫秒為單位 */
public static long timeinterval = 0;
//用於游戲時鐘的變量
public static long timeold = 0;
public static long timenow = 0;
public long interval = 0;
public static long frames_per_second=0;
int count=0;
long second =0;
public static boolean running = false;
static boolean exitApp =false;
public GameMIDlet() {
displayable = new GameDisplayable();
running =true;
}
public void startApp() {
running =true;
Display.getDisplay(this).setCurrent(displayable);
while(running) {
timenow = System.currentTimeMillis();
interval = timenow - timeold;
if (interval >= timeinterval) {
timeold = timenow;
displayable.Game_Process();
if(second != (System.currentTimeMillis() /1000)){
second = System.currentTimeMillis()/1000;
frames_per_second = count;
count = 1;
}else
count ++;
}
}
if(exitApp) {
destroyApp(true);
notifyDestroyed();
}
}
public void pauseApp() {
running =false;
}
public void destroyApp(boolean unconditional) {
running = false;
}
public static void quitApp() {
running =false;
exitApp =true;
}
}