遊戲開發中將零散小圖(數字、精靈幀、UI 圖示)合併為單一大圖(Sprite Sheet),可減少 JAR 體積、降低類載入數量、提升載入速度。運行時需將大圖分割為獨立 Image 物件以供高頻繪製。
不建立新 Image,每幀透過 setClip 只繪製大圖對應區域。
// 繪製第 3 個數字 (假設每個 10x15)
g.setClip(50, 50, 10, 15);
g.drawImage(numberSheet, 50 - 2*10, 50, Graphics.LEFT | Graphics.TOP);
g.setClip(0, 0, getWidth(), getHeight());
setClip 呼叫,CPU 開銷較大Image[] digits = new Image[10];
Image sheet = Image.createImage("/res/digits.png"); // 100x15
for (int i = 0; i < 10; i++) {
digits[i] = Image.createImage(10, 15); // 可變動圖片
Graphics g = digits[i].getGraphics();
g.drawImage(sheet, -i * 10, 0, Graphics.LEFT | Graphics.TOP);
}
Image.createImage(w, h) 建立的可變動圖片在 MIDP 1.0 上不支援透明通道,貼上含透明像素的源圖會導致透明區變黑/白。
| 方案 | 代碼 | 相容性 | 優點 | 缺點 |
|---|---|---|---|---|
| 堅持 setClip | 見方案一 | 全裝置 | 零記憶體、保留透明 | 繪製較慢 |
| Nokia 專用 API | DirectUtils.createImage(w, h, 0) | 僅 Nokia | 效能佳、保留透明 | 廠商鎖定 |
| MIDP 2.0 標準 API | Image.createImage(src, x, y, w, h, transform) | MIDP 2.0+ | 標準、效能佳、保留透明 | 需 MIDP 2.0 |
public static Image[] splitSheet(Image sheet, int cols, int rows, int fw, int fh) {
Image[] frames = new Image[cols * rows];
boolean isMIDP2 = System.getProperty("microedition.profiles").contains("MIDP-2");
boolean isNokia = System.getProperty("microedition.platform").toLowerCase().contains("nokia");
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
int idx = r * cols + c;
int sx = c * fw, sy = r * fh;
if (isMIDP2) {
// 標準 MIDP 2.0 方案(最佳)
frames[idx] = Image.createImage(sheet, sx, sy, fw, fh, Sprite.TRANS_NONE);
} else if (isNokia) {
// Nokia MIDP 1.0 方案
try {
Class> du = Class.forName("com.nokia.mid.ui.DirectUtils");
java.lang.reflect.Method m = du.getMethod("createImage", int.class, int.class, int.class);
frames[idx] = (Image) m.invoke(null, fw, fh, 0); // 0 = 透明
Graphics g = frames[idx].getGraphics();
g.drawImage(sheet, -sx, -sy, Graphics.LEFT | Graphics.TOP);
} catch (Exception e) {
// 回退 setClip 方案
frames[idx] = null; // 標記需用 setClip
}
} else {
// 通用回退:標記需用 setClip
frames[idx] = null;
}
}
}
return frames;
}
void drawFrame(Graphics g, Image[] frames, int index, int x, int y) {
Image img = frames[index];
if (img != null) {
g.drawImage(img, x, y, Graphics.LEFT | Graphics.TOP);
} else {
// 回退 setClip 方案(需知道源座標)
int fw = 10, fh = 15; // 已知幀尺寸
int sx = (index % 10) * fw;
g.setClip(x, y, fw, fh);
g.drawImage(sheet, x - sx, y, Graphics.LEFT | Graphics.TOP);
g.setClip(0, 0, getWidth(), getHeight());
}
}
現代 J2ME 開發(MIDP 2.0+)應優先使用 Image.createImage(src, x, y, w, h, transform) 進行標準化分割;維護舊專案(MIDP 1.0)時,採用運行期檢測 + 多方案回退策略,可在保證相容性的前提下最大化效能。