閃爍成因:畫面顯示的同時程式又在修改像素。雙緩衝在記憶體開闢後台緩衝區,所有繪圖操作在後台完成,一次性複製到前台顯示。
public class GameCanvas extends Canvas implements Runnable {
Graphics bg; // 後台繪圖上下文
Image buffer; // 後台緩衝圖片
int width, height;
public GameCanvas() {
width = getWidth();
height = getHeight();
buffer = Image.createImage(width, height); // 建立緩衝區
bg = buffer.getGraphics(); // 取得後台 Graphics
}
private void drawBlock(int bx, int by) {
int x = getLeft(bx);
int y = getTop(by);
int color = board[bx][by];
bg.drawImage(blockImages[color], x, y, Graphics.TOP | Graphics.LEFT);
}
public void run() {
while (running) {
// 1. 所有繪圖在 bg 上進行
for (int i=0; i
Image buffer + Graphics bg,依螢幕尺寸建立緩衝區。bg。repaint() 觸發系統呼叫 paint(g)。paint(g) 中單純 g.drawImage(buffer, 0, 0, ...) 刷新螢幕。MIDP 2.0 GameCanvas 內建此機制,直接用 getGraphics() 取得後台 Graphics,繪製完呼叫 flushGraphics() 即可。
public class GameCanvas extends Canvas implements Runnable {
private boolean stopFlag = false; // 除錯旗標
public void run() {
// 斷點位置 1
debugBreak("x:" + x + " y:" + y);
// ... 遊戲邏輯 ...
// 斷點位置 2
debugBreak("score:" + score);
}
private void debugBreak(String msg) {
stopFlag = true;
// 畫白底黑字訊息到後台緩衝區
bg.setGrayScale(255); // 白
bg.fillRect(0, 0, fontW, fontH);
bg.setGrayScale(0); // 黑
bg.drawString(msg, 0, 0, Graphics.TOP | Graphics.LEFT);
repaint(); // 刷新顯示
// 死循環等待按鍵
while (stopFlag) {
// 不佔用 CPU?實測 J2ME 中空 while 會佔滿 CPU
// 可加 Thread.yield() 或 sleep(10) 緩解
try { Thread.sleep(10); } catch (Exception e) {}
}
}
public void keyPressed(int keyCode) {
stopFlag = false; // 任意鍵繼續執行
}
}
private boolean paused = false;
public void run() {
while (running) {
if (!paused) {
// 遊戲邏輯
}
// 暫停時只處理重繪與輸入
repaint();
// sleep...
}
}
public void keyPressed(int keyCode) {
int action = getGameAction(keyCode);
if (action == FIRE) paused = !paused; // Fire 鍵切換暫停
}
優於 Thread.sleep(Long.MAX_VALUE):理論上 sleep 無法無限期暫停,且無法即時響應繪圖更新。旗標法完美解決。

圖 1:自訂斷點運行時畫面,白底顯示變數值,按鍵繼續。