在 J2ME 遊戲與應用中,圖片淡入淡出是常見的場景切換特效。本文提供一個開箱即用的 FadingImage 類,核心原理:創建可變圖片,逐幀修改像素 Alpha 通道,再用 drawRGB 刷新顯示。無需額外線程,極低內存佔用,支持單次/循環、淡入/淡出、自定義速度。
getRGB() 取得 ARGB 像素數組。Mutable Image 及其 Graphics。fading():更新當前 Alpha 值 → 遍歷像素數組混合新 Alpha → fillRect 清白底 → drawRGB(..., true) 繪製帶 Alpha 圖片。draw(g) 直接畫最終可變圖片,零開銷。// 單次淡入:0→255,步長 20
new FadingImage("pic.png", false);
// 單次淡出:255→0,步長 -15
new FadingImage("pic.png", false, -15);
// 循環淡入淡出:步長 10
new FadingImage("pic.png", true, 10);
loop:true = 循環往返,false = 單次播放結束停在終值。inc:正數 = 淡入,負數 = 淡出,建議絕對值 5~20。FadingImage fimg = new FadingImage("splash.png", false, 15);
// 在遊戲循環 render 階段
fimg.fading(); // 更新幀
fimg.draw(g); // 繪製到屏幕
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import java.io.*;
class FadingImage {
private Image fadingImage;
private int[] fadingRGB;
private Graphics fadingGraphics;
private boolean needLoop;
private int lowAlpha, highAlpha, nowAlpha, incAlpha;
private void init(String name, boolean loop, int lAlpha, int hAlpha, int now, int inc) {
Image raw = null;
try { raw = Image.createImage(name); }
catch (Exception e) { System.out.println("Load failed: " + name); return; }
fadingRGB = new int[raw.getWidth() * raw.getHeight()];
raw.getRGB(fadingRGB, 0, raw.getWidth(), 0, 0, raw.getWidth(), raw.getHeight());
fadingImage = Image.createImage(raw.getWidth(), raw.getHeight());
fadingGraphics = fadingImage.getGraphics();
raw = null; System.gc();
needLoop = loop;
lowAlpha = lAlpha; highAlpha = hAlpha;
nowAlpha = now; incAlpha = inc;
}
public FadingImage(String name, boolean loop) {
init(name, loop, 0, 255, 0, 20);
}
public FadingImage(String name, boolean loop, int inc) {
if (inc > 0) init(name, loop, 0, 255, 0, inc);
else init(name, loop, 0, 255, 255, inc);
}
public void fading() {
nowAlpha += incAlpha;
boolean atBoundary = false;
if (nowAlpha >= highAlpha) { nowAlpha = highAlpha; atBoundary = true; }
else if (nowAlpha <= lowAlpha) { nowAlpha = lowAlpha; atBoundary = true; }
if (atBoundary) {
if (needLoop) incAlpha = -incAlpha;
else return; // 單次模式到達終點不再更新
}
blend(nowAlpha);
// 白底避免透明疊加殘影
fadingGraphics.setColor(0xFFFFFF);
fadingGraphics.fillRect(0, 0, fadingImage.getWidth(), fadingImage.getHeight());
fadingGraphics.drawRGB(fadingRGB, 0, fadingImage.getWidth(),
0, 0, fadingImage.getWidth(), fadingImage.getHeight(), true);
}
public void draw(Graphics g) {
g.drawImage(fadingImage, 0, 0, 0);
}
private void blend(int alpha) {
blend(alpha, 0xFFFFFFFF, 0xFFFFFFFF);
}
private void blend(int alpha, int maskColor, int dontMaskColor) {
for (int i = 0; i < fadingRGB.length; i++) {
int a = 0;
int rgb = fadingRGB[i] & 0x00FFFFFF;
if (rgb == maskColor) a = 0;
else if (rgb == dontMaskColor) a = 255;
else if (alpha > 0) a = alpha;
fadingRGB[i] = rgb | (a << 24);
}
}
}
blend() 實現「保留某顏色不透明/全透明」(如保留 UI 圖標不參與淡出)。fadingRGB 數組池可減少 GC。GameCanvas 雙緩衝,在 flushGraphics() 前調用 draw()。