首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

J2ME 2D 遊戲入門之旅(二):周邊工具類構建(圖片、GameObject、圖集字體)

     編輯:J2ME

工具類設計哲學:小而專、零依賴、可複用

MIDP 2.0 雖提供 Sprite、Graphics,但實戰中仍需資源載入保護、實體狀態封裝、高效文字渲染三大基建。本文構建三個核心工具類。

1. ImageTools:安全載入守護者

public class ImageTools {
    private ImageTools() {}  // 工具類禁用實例化

    public static Image getImage(String path) {
        try {
            return Image.createImage(path);
        } catch (Exception ex) {
            System.out.println("Load image failed: " + path + " - " + ex);
            return null;  // 呼叫端需檢查 null,實現優雅降級
        }
    }
}

用法:Image img = ImageTools.getImage("/res/bg.png"); 失敗返回 null,不拋異常、不中斷流程。

2. GameObject:Sprite 的狀態容器

為什麼不直接用 Sprite? 一張 Sprite 圖集常被多個實體共用(如多架同型敵機),每個實體需獨立:位置、幀序、存活、生命週期、動畫速度。GameObject 即為「實體實例」,Sprite 為「模板」。

public class GameObject {
    public Sprite sprite;      // 共用模板
    public boolean alive;      // 存活標記
    private int lifeCount;     // 生命週期計數器
    public int lifetime;       // 總壽命(幀數),0=永久
    public int speed;          // 動畫速度(幀間隔),0=每幀更新
    private int animCount;     // 動畫計數器

    public GameObject(Image img, int frameW, int frameH) {
        sprite = new Sprite(img, frameW, frameH);
        reset();
    }

    public void move(int dx, int dy) { sprite.move(dx, dy); }
    public void moveTo(int x, int y) { sprite.setPosition(x, y); }

    public void update() {
        if (!alive) return;
        if (++animCount > speed) {
            animCount = 0;
            sprite.nextFrame();
            if (lifetime != 0 && ++lifeCount > lifetime) alive = false;
        }
    }

    public void paint(Graphics g) {
        if (alive) sprite.paint(g);
    }

    public void reset() {
        alive = true;
        lifeCount = 0;
        animCount = 0;
        sprite.setFrame(0);
    }
}

3. Font:圖集字體高效渲染器

痛點:Graphics.drawString 字體光柵化極慢、無法自定義風格、不支援換行。解法:美術製字體圖集(等寬/等高),程式建立 char[] → frameIndex 映射,繪製時 O(1) 定幀 + drawRegion。

public class Font {
    private Sprite sprite;           // 字體圖集
    private int charW, charH;        // 單字尺寸
    private int[] charMap;           // ASCII 0-127 映射表,-1=無此字
    private Graphics g;              // 目標繪圖面

    public Font(Graphics g, Image img, int charW, int charH, char[] chars) {
        this.g = g;
        this.charW = charW; this.charH = charH;
        sprite = new Sprite(img, charW, charH);
        charMap = new int[128];
        for (int i = 0; i < 128; i++) charMap[i] = -1;
        for (int i = 0; i < chars.length; i++) {
            charMap[chars[i]] = i;  // Character.hashCode() == ASCII for 0-127
        }
    }

    public void drawChar(char ch, int x, int y) {
        int idx = (ch < 128) ? charMap[ch] : -1;
        if (idx >= 0) {
            sprite.setPosition(x, y);
            sprite.setFrame(idx);
            sprite.paint(g);
        }
    }

    public void drawString(String str, int x, int y) {
        int len = str.length();
        for (int i = 0; i < len; i++) {
            drawChar(str.charAt(i), x + charW * i, y);
        }
    }
}

使用範例

// 初始化(通常在遊戲啟動時)
Image fontImg = ImageTools.getImage("/font.png");  // 16x16 像素/字,含 0-9 A-Z 符號
char[] fontChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.:-+*/".toCharArray();
Font gameFont = new Font(g, fontImg, 16, 16, fontChars);

// 繪製分數
gameFont.drawString("SCORE: 12345", 10, 10);

// 繰製生命值
gameFont.drawString("LIFE: 3", getWidth() - 80, 10);

進階擴展建議

  • 變寬字體:charMap 儲存 short[] {frameIndex, charWidth},drawString 累加寬度而非固定 charW。
  • 自動換行:drawString(str, x, y, maxWidth) 遇界換行,支援 \n 硬換行。
  • 對齊方式:LEFT/CENTER/RIGHT,計算總寬度後調整起始 x。
  • 顏色標記:字體圖集含白色字形,sprite.setColor (MIDP 3.0) 或預製多色圖集切換。
  • 文字特效:陰影(偏移 1,1 再畫黑)、描邊、閃爍、逐字彈出動畫。

效能對比

結語

三個工具類 < 3 KB,卻解決了資源載入脆弱、實體狀態混亂、文字渲染低效三大痛點。這就是 J2ME 遊戲開發的「基建思維」:**在寫第一行遊戲邏輯前,先把鐵路鋪好。**

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案繪製 20 字耗時JAR 增量靈活度
drawString~45 ms0低(系統字體唯一)
Font (本文)~8 ms~2 KB + 字體圖集高(任意風格、顏色、特效)
預渲染整句圖片~1 ms大(每句一圖)極低(動態內容不可用)