MIDP 2.0 提供 LayerManager 視窗機制輕鬆實現大地圖捲動。MIDP 1.0 雖無此 API,但利用 Graphics.translate(x, y) 平移座標系,同樣能以極簡代碼實現流暢捲動。本文解析原理並提供完整可運行範例。
Graphics.translate(dx, dy) 將繪圖原點 (0,0) 移動至 (dx, dy)。後續所有繪圖座標均相對新原點。若固定在 (0,0) 繪製背景圖,並隨按鍵修改 translate 參數,視覺上圖片即產生移動感覺。
translateX 減小 (負值增大)translateX 增大 (向 0 接近)public class TranslateDemo extends MIDlet {
private Display display;
private TranslateCanvas canvas;
public TranslateDemo() {
display = Display.getDisplay(this);
canvas = new TranslateCanvas(this);
}
protected void startApp() { display.setCurrent(canvas); }
protected void pauseApp() {}
protected void destroyApp(boolean u) {}
public void exitMIDlet() { destroyApp(true); notifyDestroyed(); }
}
class TranslateCanvas extends Canvas implements CommandListener {
private TranslateDemo midlet;
private Image bgImage;
private int translateX = 0, translateY = 0; // 當前平移量
private static final int STEP = 2; // 單步像素
public TranslateCanvas(TranslateDemo midlet) {
this.midlet = midlet;
addCommand(new Command("Exit", Command.EXIT, 1));
setCommandListener(this);
try { bgImage = Image.createImage("/bg.png"); }
catch (IOException e) { System.err.println("Load bg failed"); }
}
protected void paint(Graphics g) {
if (bgImage == null) return;
g.setColor(0xFFFFFF);
g.fillRect(0, 0, getWidth(), getHeight());
// 關鍵:平移座標系
g.translate(translateX, translateY);
// 永遠在 (0,0) 畫圖,視覺上圖片隨座標系移動
g.drawImage(bgImage, 0, 0, Graphics.LEFT | Graphics.TOP);
}
public void commandAction(Command c, Displayable d) {
if (c.getCommandType() == Command.EXIT) midlet.exitMIDlet();
}
protected void keyPressed(int keyCode) {
int action = getGameAction(keyCode);
int imgW = bgImage.getWidth();
int imgH = bgImage.getHeight();
int scrW = getWidth();
int scrH = getHeight();
switch (action) {
case LEFT: // 向左捲動:顯示圖片更右側 → translateX 變更負
if (translateX + imgW > scrW) // 圖片右邊界未超出螢幕右邊
translateX -= STEP;
break;
case RIGHT: // 向右捲動:顯示圖片更左側 → translateX 向 0 回復
if (translateX < 0) translateX += STEP;
break;
case UP:
if (translateY + imgH > scrH) translateY -= STEP;
break;
case DOWN:
if (translateY < 0) translateY += STEP;
break;
}
repaint(); // 觸發重繪
}
}
| 方向 | 條件判斷 | 含義 |
|---|---|---|
| LEFT | translateX + imgW > scrW | 圖片右邊界 (translateX+imgW) 尚未超出螢幕右邊 (scrW),可繼續左移 |
| RIGHT | translateX < 0 | 座標系尚未平移回原點,可繼續右移 |
| UP | translateY + imgH > scrH | 圖片下邊界未超出螢幕底部 |
| DOWN | translateY < 0 | 座標系未回原點 |
注意:translate 值通常為負數 (向左/上平移),邊界判斷邏輯以「圖片邊界相對螢幕」思考最直觀。
translate 與瓦片索引計算:tileX = (screenX - translateX) / tileWMIDP 1.0 畫面捲動核心就是 Graphics.translate() + 邊界裁剪。代碼量極小 (核心 < 30 行),效能極高 (單次繪圖呼叫),是早期 J2ME 遊戲大地圖、背景滾動的標準解法。理解座標系變換本質,舉一反三可應用於縮放、旋轉等仿射變換模擬。