J2ME 遊戲開發中最常見的性能陷阱:模擬器運行絲滑,真機卻嚴重掉幀甚至崩潰。根因多數在於 paint(Graphics g) 方法的不當實現。由於低端設備 CPU 頻率不足 20MHz、內存不足 100KB,paint() 的高頻調用(動畫每幀必調)極易成為性能瓶頸。本文總結六大優化法則,助你構建高性能渲染引擎。
反例:每幀創建圖片對象
public void paint(Graphics g) {
try {
Image img = Image.createImage("/back.png"); // 每幀 IO 讀取 + 解碼!
g.drawImage(img, 0, 0, Graphics.TOP | Graphics.LEFT);
} catch (Exception e) {}
}
正例:初始化階段預載資源
private Image bgImage;
public void init() {
try { bgImage = Image.createImage("/back.png"); } catch (Exception e) {}
}
public void paint(Graphics g) {
if (bgImage != null) g.drawImage(bgImage, 0, 0, Graphics.TOP | Graphics.LEFT);
}
原則:Image.createImage()、文件讀取、網絡請求等 IO 操作只在初始化執行一次。
方法一:Clip 矩形裁剪
public void paint(Graphics g) {
g.setClip(10, 10, 50, 50); // 僅繪製 (10,10) 50x50 區域
g.drawImage(sprite, 10, 10, Graphics.TOP | Graphics.LEFT);
}
方法二:repaint(x, y, w, h) 指定區域重繪
// 遊戲邏輯中僅標記髒矩形
repaint(charX, charY, charW, charH); // 內部自動設置 Clip
效果:將全屏繪製 (176×208) 減少為角色移動區域 (32×32),像素處理量降低 97%。
repaint()boolean needsRepaint 標誌,邏輯更新時置 true,渲染循環中判斷後重置反例:paint 中混雜計算
public void paint(Graphics g) {
int x = (int)(Math.sin(System.currentTimeMillis()/100.0) * 50); // 三角函數計算
g.drawImage(ball, x, 100, 0);
}
正例:邏輯層預計算,paint 純渲染
private int ballX;
public void updateLogic(long timestamp) {
ballX = (int)(Math.sin(timestamp/100.0) * 50); // 邏輯幀計算
}
public void paint(Graphics g) {
g.drawImage(ball, ballX, 100, 0); // 純繪製
}
利用 Image.createImage(w, h) 創建可變圖像作為離屏緩衝:
private Image offscreen;
private Graphics offGraphics;
public void init() {
offscreen = Image.createImage(getWidth(), getHeight());
offGraphics = offscreen.getGraphics();
}
public void renderOffscreen() {
// 在邏輯線程中繪製到離屏緩衝,不阻塞 paint()
offGraphics.setColor(0xFFFFFF);
offGraphics.fillRect(0, 0, getWidth(), getHeight());
offGraphics.drawImage(bg, 0, 0, 0);
offGraphics.drawImage(player, px, py, 0);
// ... 其他繪製操作
}
public void paint(Graphics g) {
// paint 僅負責將離屏圖像一次性繪製到屏幕
g.drawImage(offscreen, 0, 0, Graphics.TOP | Graphics.LEFT);
}
public void paint(Graphics g) {
// 保存當前平移
int tx = g.getTranslateX();
int ty = g.getTranslateY();
// 設置地圖偏移
g.translate(-cameraX, -cameraY);
g.drawImage(mapImage, 0, 0, Graphics.TOP | Graphics.LEFT);
g.drawImage(player, playerX, playerY, Graphics.TOP | Graphics.LEFT);
// 恢復平移
g.translate(tx, ty);
// 繪製 UI(不受攝像機影響)
g.drawString("Score: " + score, 5, 5, 0);
}
| 優化手段 | 適用場景 | 典型性能提升 | 實現難度 |
|---|---|---|---|
| 資源預載 | 所有項目 | 消除幀率抖動 | ★ |
| 降低色深 | 美術資源階段 | 解碼速度 2-5x | ★★ |
| 局部刷新 | 動畫/遊戲 | 像素處理量 90%+ ↓ | ★★ |
| 減少 repaint | 靜態界面為主 | CPU 佔用 50%+ ↓ | ★ |
| 計算剝離 | 複雜動畫/物理 | paint 耗時 80% ↓ | ★★ |
| 離屏緩衝 | 複雜場景/滾動 | 幀率穩定性質變 | ★★★ |
J2ME 繪圖優化的核心哲學是:「能不畫就不畫,能少畫就少畫,能預先畫好就預先畫好」。將這六大法則內化為編碼習慣,你的遊戲將在諾基亞 S40、S60、Moto 等主流機型上實現流暢運行。