遊戲引擎的結構很多,不過基本上都是在一個遊戲主循環内實作。程式裡面的主循環包含了程式架構的最主要的結構體。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; } } |