本範例實現人機對戰九宮格遊戲,展示:高低級 UI 組件混用、多螢幕切換、命令處理、動態適配螢幕尺寸、鍵盤事件處理。玩家先選棋子(圓/叉),先手隨機決定,每步檢查勝負平,即時顯示雙方得分,支援新遊戲與退出。圖 2 為遊戲螢幕流程圖。

圖 3 為類圖。啟動時創建閃屏與首個遊戲螢幕 ChoosePieceScreen,4 秒後顯示選棋螢幕。玩家選擇後按 OK,觸發回調 choosePieceScreenDone() 創建並顯示主遊戲螢幕 GameScreen。

ChoosePieceScreen 使用高級 API List 實現(圖 4)。

玩家回合時用方向鍵與 Select 鍵選格,每回合檢查遊戲狀態。Quit 命令調用 quit() 終止 MIDlet,New 命令重新開始。遊戲邏輯封裝於獨立 Game 類,本文聚焦圖形設計,邏輯詳見參考鏈接。
GameScreen 基於低級 Canvas、Graphics、Image 實現。初始化時根據畫布尺寸適配顯示面板,支援不同設備。用 Image 表示遊戲面板,依玩家選擇分配棋子,隨機決定先手。為移植性,將鍵盤代碼映射為遊戲動作(Up、Down、Left、Right、Fire)。keyPressed() 判斷方向鍵移動光標、Select 鍵落子,檢測結束條件並宣佈結果(圖 5)。

處理生命週期、創建螢幕、處理回調:
package example.tictactoe;
import java.io.IOException;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
public class TicTacToeMIDlet extends MIDlet {
private ChoosePieceScreen choosePieceScreen;
private GameScreen gameScreen;
public void startApp() {
Displayable current = Display.getDisplay(this).getCurrent();
if (current == null) {
Image logo = null;
try { logo = Image.createImage("/tictactoe.png"); } catch (IOException e) {}
Alert splash = new Alert(null, "Tic-Tac-Toe\nForum Nokia", logo, AlertType.INFO);
splash.setTimeout(4000);
choosePieceScreen = new ChoosePieceScreen(this);
Display.getDisplay(this).setCurrent(splash, choosePieceScreen);
} else {
Display.getDisplay(this).setCurrent(current);
}
}
public void pauseApp() {}
public void destroyApp(boolean unconditional) {}
public void quit() { destroyApp(false); notifyDestroyed(); }
public void choosePieceScreenDone(boolean isPlayerCircle) {
gameScreen = new GameScreen(this, isPlayerCircle);
Display.getDisplay(this).setCurrent(gameScreen);
}
}
高級 List 螢幕,讓玩家選圓/叉,按 OK 回調處理:
package example.tictactoe;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.io.*;
public class ChoosePieceScreen extends List implements CommandListener {
private static final String CIRCLE_TEXT = "Circle";
private static final String CROSS_TEXT = "Cross";
private final TicTacToeMIDlet midlet;
private final Command quitCommand;
public ChoosePieceScreen(TicTacToeMIDlet midlet) {
super("Choose your piece", List.IMPLICIT);
this.midlet = midlet;
append(CIRCLE_TEXT, loadImage("/circle.png"));
append(CROSS_TEXT, loadImage("/cross.png"));
quitCommand = new Command("Quit", Command.EXIT, 2);
addCommand(quitCommand);
setCommandListener(this);
}
public void commandAction(Command c, Displayable d) {
boolean isPlayerCircle = getString(getSelectedIndex()).equals(CIRCLE_TEXT);
if (c == List.SELECT_COMMAND) {
midlet.choosePieceScreenDone(isPlayerCircle);
} else { midlet.quit(); }
}
private Image loadImage(String file) {
try { return Image.createImage(file); } catch (Exception e) { return null; }
}
}