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

J2ME 執行緒實戰教學:以俄羅斯方塊完整實作掌握 Thread 與 Runnable

     編輯:J2ME

執行緒是 J2ME 遊戲開發核心。本文以完整的俄羅斯方塊為例,從專案建立、Canvas 繼承 Runnable、遊戲迴路、按鍵處理到繪圖優化,完整展示 J2ME 多執行緒實戰模式。

環境與前置知識

  • J2ME 保留 java.lang.Runnable 與 Thread,但無執行緒群組、無 daemon 執行緒
  • 嚴禁使用浮點數:可編譯但無法預驗證,手持裝置無 FPU
  • 記憶體主要佔用於圖片:優先使用 PNG、簡化圖片,背景圖從 5KB 膨脹到 47KB 是典型教訓
  • 大量使用 static final 常數定義座標、顏色、尺寸,利於移植與維護
  • 發布前進行混淆 保護智慧財產權

專案架構


TetrisMidlet (MIDlet) → 啟動顯示 TetrisCanvas
TetrisCanvas (Canvas + Runnable) → 遊戲主邏輯、繪圖、輸入處理

核心程式碼精華

1. MIDlet 啟動器


public class TetrisMidlet extends MIDlet {
    public void startApp() {
        Display.getDisplay(this).setCurrent(new TetrisCanvas());
    }
    public void pauseApp() {}
    public void destroyApp(boolean unconditional) {}
}

2. Canvas 實作 Runnable(關鍵模式)


public class TetrisCanvas extends Canvas implements Runnable {
    private Thread gameThread = null;

    public TetrisCanvas() {
        initGame();
        gameThread = new Thread(this);
        gameThread.start();  // 啟動遊戲迴路
    }

    public void run() {
        while (gameThread != null) {
            // 遊戲邏輯更新
            // repaint() 觸發重繪
            // Thread.sleep() 控制幀率
        }
        gameThread = null;  // 結束標記
    }
    // ...
}

為何不 extends Thread? Java 單一繼承限制,Canvas 已繼承自 Displayable,故採用 implements Runnable + 組合 Thread。

3. 遊戲資料結構


// 方塊定義:[x1,y1,x2,y2,x3,y3,x4,y4, color, 旋轉變體數]
private static final int[][] BLOCK_INFO = {
    {1,0, 1,1, 1,2, 1,3, 0xFF0000, 2},  // I 型
    {0,1, 1,1, 2,1, 3,1, 0xFF0000, 4},
    {0,0, 0,1, 1,1, 1,2, 0x0000FF, 2},  // Z 型
    // ... 共 19 種變體
};

// 遊戲區網格:12寬 x 22高,儲存顏色值(0=空)
private int[][] grid = new int[22][12];

4. 遊戲主迴路


public void run() {
    while (gameThread != null) {
        if (!isBlockLanded) {
            currentY++;  // 方塊下落
            if (!isPositionValid()) {
                isBlockLanded = true; currentY--;
                clearLines();  // 檢查消行
                try { Thread.sleep(400); } catch (Exception e) {}
            } else {
                repaint();
                try { Thread.sleep(950 - 100 * speed); } catch (Exception e) {}
            }
        } else {
            // 方塊落地處理:得分、產生新方塊、檢查遊戲結束
            score += 50;
            if ((score % 2000) < 50) speed++;
            isBlockLanded = false;
            repaint();
            currentBlock = nextBlock;
            nextBlock = random.nextInt(19);
            currentX = 4; currentY = 0;
            if (!isPositionValid()) initGame();  // 遊戲結束重置
        }
    }
}

5. 按鍵處理(使用 getGameAction 跨裝置)


protected void keyPressed(int keyCode) {
    switch (getGameAction(keyCode)) {
        case Canvas.LEFT:  currentX--; if (!valid()) currentX++; break;
        case Canvas.RIGHT: currentX++; if (!valid()) currentX--; break;
        case Canvas.DOWN:  currentY++; if (!valid()) currentY--; speed=9; break; // 快速下落
        case Canvas.FIRE:  rotateBlock(); break;  // 旋轉邏輯
        case Canvas.UP:    /* 保留 */ break;
    }
    repaint();
}

6. 繪圖優化:3D 方塊與背景


private void draw3DBlock(Graphics g, int color, int x, int y, int w, int h) {
    int oldColor = g.getColor();
    g.setColor(0xFFFFFF); g.drawRect(x, y, w, h);      // 高光邊
    g.setColor(color);    g.fillRect(x+1, y+1, w-2, h-2); // 主體
    g.setColor(0x000000);
    g.drawLine(x+w-1, y, x+w-1, y+h-1);  // 右陰影
    g.drawLine(x, y+h-1, x+w-1, y+h-1);  // 底陰影
    g.setColor(oldColor);
}

protected void paint(Graphics g) {
    // 1. 繪製背景圖(若有)
    try { g.drawImage(Image.createImage("/back.png"), 0, 0, Graphics.TOP|Graphics.LEFT); }
    catch (Exception e) { g.setColor(0x89A5D1); g.fillRect(0,0,getWidth(),getHeight()); }

    // 2. 繪製下一個方塊預覽、分數、速度、行數 UI

    // 3. 繪製遊戲區已落地方塊
    for (int r=0; r<21; r++)
        for (int c=1; c<11; c++)
            if (grid[r][c] != 0)
                draw3DBlock(g, grid[r][c], offsetX+c*7, offsetY+r*7, 7, 7);

    // 4. 繪製正在下落的方塊
    if (!isBlockLanded) { /* 依 BLOCK_INFO 繪製 4 個小方塊 */ }
}

關鍵經驗總結

  1. Runnable + Thread 組合 是 J2ME 遊戲迴路標準模式
  2. getGameAction() 抽象化按鍵映射,解決跨裝置相容性
  3. 常數集中管理 尺寸、顏色、座標,移植只需改常數
  4. 繪圖順序優化:背景 → 靜態元素 → 動態元素 → UI,減少過度繪製
  5. 背景圖代價大:無背景 5KB、有背景 47KB,必須權衡視覺與大小
  6. 混淆保護:發布前啟用 Obfuscation,提高逆向難度

這個俄羅斯方塊雖簡單,卻涵蓋了 J2ME 遊戲開發 80% 的核心技術點,是極佳的入門實戰專案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved