Java ME (Micro Edition) 在功能機時代是行動遊戲開發的主流平台。受限於記憶體 (通常 1-2MB 堆)、CPU 效能、螢幕解析度碎片化、鍵盤輸入差異,J2ME 遊戲開發需要極度精簡、高效的框架設計。本文基於 MIDP 2.0 / CLDC 1.1 規範,解析一個採用單例模式、固定幀率遊戲迴路、鍵盤狀態機的核心 GameCanvas 框架實現。
public class MyGameCanvas extends GameCanvas
implements Runnable, CommandListener { ... }
getGraphics() 繪離屏、flushGraphics() 翻頁)、鍵盤狀態查詢 (getKeyStates())。
private static MyGameCanvas instance;
protected MyGameCanvas() { ... } // 私有建構子
synchronized public static MyGameCanvas getInstance() {
if (instance == null) instance = new MyGameCanvas();
return instance;
}
public static void cleanJob() { instance = null; } // 釋放參考供 GC
理由:GameCanvas 持有離屏緩衝圖像,佔用大量堆記憶體。單例確保同一時間僅存在一個實例,避免 OOM。
public void run() {
long st, et, diff;
int rate = 50; // 目標幀時間 ms (約 20 FPS)
while (running) {
st = System.currentTimeMillis();
gameInput(); // 1. 處理輸入
gameMain(); // 2. 更新邏輯 + 繪圖
et = System.currentTimeMillis();
diff = et - st;
if (diff < rate) {
try { Thread.sleep(rate - diff); } catch (InterruptedException ignored) {}
} else {
// 幀處理超時,記錄或跳過睡眠
}
}
}
關鍵點:
J2ME 無事件式鍵盤監聽,需輪詢 getKeyStates() 位元遮罩。框架實現「按下持續」與「單次點擊」雙模式檢測:
private void gameInput() {
if (!allowInput) return;
int state = getKeyStates();
keyEvent = false;
// 方向鍵處理範例 (UP)
if ((state & UP_PRESSED) != 0) { // 按下中
keyUp = true; keyEvent = true;
// 持續觸發邏輯 (如持續移動)
} else if (keyUp) { // 釋放瞬間 (上一幀按下,這幀釋放)
keyUp = false;
// 單次點擊邏輯 (如跳躍、確認)
}
// DOWN, LEFT, RIGHT, FIRE 同理...
}
位元遮罩常數 (GameCanvas 定義):UP_PRESSED=2, DOWN_PRESSED=4, LEFT_PRESSED=8, RIGHT_PRESSED=16, FIRE_PRESSED=32。
public void commandAction(Command c, Displayable d) {
String cmd = c.getLabel();
if ("start".equals(cmd)) {
gameInit(); start();
removeCommand(startCmd); addCommand(restartCmd);
} else if ("restart".equals(cmd)) {
stop(); while (thread.isAlive()) {}; // 等待執行緒安全結束
gameInit(); start();
} else if ("exit".equals(cmd)) {
stop(); midlet.destroyApp(false); midlet.notifyDestroyed();
}
}
private void gameMain() {
// 1. 取得離屏 Graphics
Graphics g = getGraphics();
// 2. 清屏 (黑色背景)
g.setColor(0, 0, 0);
g.fillRect(0, 0, getWidth(), getHeight());
// 3. 繪製遊戲物件 (精靈、背景、文字...)
// drawSprites(); drawBackground(); drawUI();
// 4. 翻頁顯示
flushGraphics();
}
Image.createImage("/res/img.png") 載入,**啟動時一次性載入**並快取,遊戲中不可重複載入。String 不可變,頻繁拼接產生大量垃圾。用 StringBuffer 或預先格式化。J2ME 遊戲框架的核心在於在極度受限資源下實現流暢的固定幀率遊戲迴路。單例模式控制記憶體、雙緩衝消除閃爍、位元遮罩鍵盤狀態機、時間切片主迴路、物件池減輕 GC,每一項設計都直指嵌入式 Java 開發的痛點。雖然 J2ME 已成歷史,但這些「在約束中優化」的工程思維——資源池化、固定時間步長、狀態機輸入、單例資源控制——在現代嵌入式、物聯網、遊戲引擎底層開發中依然閃耀著智慧的光芒。