天天看點

J2ME遊戲引擎程式結構

 
 

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

    }

}

 

繼續閱讀