利用人眼視覺暫留(約 1/24 秒),快速切換靜態畫面產生動態錯覺。J2ME 無系統級動畫引擎,需自行實作遊戲迴圈:
flushGraphics())。Thread.sleep)。public class BlinkCanvas extends Canvas implements Runnable {
private boolean show = true;
private Thread animator;
public BlinkCanvas() {
animator = new Thread(this);
animator.start();
}
protected void paint(Graphics g) {
g.setColor(0xFFFFFF); g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0x000000);
if (show) g.drawString("閃爍文字", 50, 50, Graphics.TOP|Graphics.LEFT);
}
public void run() {
while (true) {
try { Thread.sleep(200); } // 5 FPS
catch (InterruptedException e) {}
show = !show;
repaint(); // 排程 paint()
}
}
}
public class WalkCanvas extends GameCanvas implements Runnable {
private Image spriteSheet; // 4 幀橫向排列
private int frameW, frameH, currentFrame = 0;
private int x = 10, y = 50, speed = 2;
public WalkCanvas() throws IOException {
super(true); // 啟用雙緩衝
spriteSheet = Image.createImage("/walk.png");
frameW = spriteSheet.getWidth() / 4;
frameH = spriteSheet.getHeight();
new Thread(this).start();
}
protected void paint(Graphics g) { /* GameCanvas 不需 override paint */ }
public void run() {
Graphics g = getGraphics();
while (true) {
long t0 = System.currentTimeMillis();
// 邏輯更新
x += speed;
if (x > getWidth()) x = -frameW;
currentFrame = (currentFrame + 1) % 4;
// 繪製
g.setColor(0xFFFFFF); g.fillRect(0,0,getWidth(),getHeight());
g.drawRegion(spriteSheet, currentFrame*frameW, 0, frameW, frameH,
Sprite.TRANS_NONE, x, y, Graphics.TOP|Graphics.LEFT);
flushGraphics();
// 幀率控制
long dt = System.currentTimeMillis() - t0;
if (dt < 100) { // 10 FPS
try { Thread.sleep(100 - dt); } catch (Exception e) {}
}
}
}
}
| 技術 | 說明 |
|---|---|
GameCanvas | 內建雙緩衝、getKeyStates() 非阻塞鍵盤查詢,適合遊戲。 |
drawRegion | 從大圖裁剪單一幀繪製,避免載入多張小圖。 |
| 幀率獨立移動 | 位移量 = 速度 × Δtime,避免不同裝置速度差異。 |
| 記憶體管理 | 結束時 spriteSheet=null; System.gc(); 釋放影像記憶體。 |
paint/run 建立新物件(String、Image、Array)→ GC 卡頓。預先建立並重用。Thread.sleep 參數過小(<10ms)導致忙碌等待,耗電且不準確。掌握遊戲迴圈、雙緩衝與幀動畫技巧,即可在 J2ME 上實作流暢的 2D 遊戲畫面,為豐富互動體驗奠基。