J2ME 遊戲為了減少 JAR 體積與降低圖片載入開銷,常將多張小圖(如角色各幀、UI 圖示、數字字型)合併為一張圖集。Graphics.setClip(x, y, width, height) 正是在螢幕上開啟一個「觀察窗」,只繪製圖集中指定矩形區域,實現單一圖檔多重複用。
public void setClip(int x, int y, int width, int height)
| 參數 | 含義 |
|---|---|
| x | 裁切矩形左上角 X 座標(螢幕座標系) |
| y | 裁切矩形左上角 Y 座標 |
| width | 裁切區域寬度 |
| height | 裁切區域高度 |
// 假設 image 是 100x100 的圖集,每個小圖 20x30
// 繪製第 2 行第 1 個小圖 (x=0, y=30, w=20, h=30)
g.setClip(10, 20, 20, 30); // 在螢幕 (10,20) 開 20x30 窗口
g.drawImage(image, 10, 20, Graphics.LEFT | Graphics.TOP); // 圖集左上角對齊窗口
// 繪製完成後**必須恢復**全螢幕裁切區,否則後續繪製受限
g.setClip(0, 0, getWidth(), getHeight());
setClip 定義的矩形區域是螢幕座標系的可繪製區域。呼叫 drawImage(img, x, y, anchor) 時,圖片的 (0,0) 點會對齊到 (x,y)。因此,若要顯示圖集中 (srcX, srcY) 起始的區域,需將圖片繪製座標設為 (screenX - srcX, screenY - srcY),使目標區域落入裁切窗口。
若頻繁繪製同一小圖,預先分割可避免重複 setClip 呼叫,提升效能:
// 分割 10 張 10x15 的數字圖片
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); // 負座標偏移
// 注意:MIDP 1.0 此法會丟失透明通道,見下方補救
}
| 方案 | 適用場景 | 代價 |
|---|---|---|
直接使用 setClip 繪製大圖 | 簡單場景、幀數低 | 每幀額外 setClip 呼叫 |
Nokia 裝置:DirectUtils.createImage(w, h, 0) | Nokia 系列手機 | 非標準 API,僅 Nokia 支援 |
MIDP 2.0:Image.createImage(src, x, y, w, h, transform) | 支援 MIDP 2.0 的裝置 | 標準 API,保留透明度 |
// MIDP 2.0 標準分割法(保留透明度)
Image[] frames = new Image[8];
Image sheet = Image.createImage("/res/sprite_sheet.png");
for (int i = 0; i < 8; i++) {
frames[i] = Image.createImage(sheet, i * 32, 0, 32, 32, Sprite.TRANS_NONE);
}
setClip 後務必呼叫 setClip(0,0,getWidth(),getHeight())。setClip;高頻精靈用預分割;MIDP 2.0 優先用 createImage(src, x, y, w, h, transform)。