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

J2ME 遊戲開發實戰(三):華容道核心邏輯完整實現

     編輯:Java 程式設計入門

繼前兩篇完成需求分析與詳細設計後,本文呈現《華容道》遊戲核心顯示類 Displayable1 的完整實現代碼,涵蓋遊戲初始化、地圖載入、觸控/按鍵交互、繪圖渲染、移動邏輯驗證、勝利判定等全流程。代碼基於 MIDP 2.0 / CLDC 1.1 規範,適用於功能機時代的 J2ME 遊戲開發參考。

核心類結構概覽

package huarongroad;

import javax.microedition.lcdui.*;

public class Displayable1 extends Canvas implements CommandListener {
    // 狀態欄位
    private int[] loc = new int[2];           // 光標位置 [x, y]
    private int[] selectArea = new int[4];    // 選中區域 [x, y, w, h]
    private int[] moveArea = new int[4];      // 目標移動區域
    private Map myMap = new Map();            // 地圖模型
    private boolean selected = false;         // 是否已選中待移動塊
    private int level = 1;                    // 當前關卡

    // 構造器、初始化、命令處理、繪圖、邏輯方法...
}

關鍵邏輯模組解析

1. 遊戲初始化與資源載入

private void jbInit() throws Exception {
    selected = false;
    level = 1;
    Images.init(); // 載入圖片資源(單例模式)
    initGame();
    setCommandListener(this);
    addCommand(new Command("Exit", Command.EXIT, 1));
}

private void initGame() {
    loc = myMap.readMap(level); // 載入關卡地圖,返回曹操初始位置
    selectArea[0] = loc[0]; selectArea[1] = loc[1];
    selectArea[2] = 1; selectArea[3] = 1; // 預設選中 1x1
    moveArea[0] = -1; moveArea[1] = -1;   // 目標區域無效標記
    moveArea[2] = 0; moveArea[3] = 0;
}

2. 繪圖渲染管線

protected void paint(Graphics g) {
    try {
        // 1. 繪製背景框架
        g.drawImage(Images.imageFrame, 0, 0, Graphics.TOP | Graphics.LEFT);
        // 2. 繪製地圖所有塊
        myMap.drawMap(g);
        // 3. 繪製選中框(綠色)
        if (selected) g.setColor(0, 255, 0);
        g.drawRect(selectArea[0]*UNIT+LEFT, selectArea[1]*UNIT+TOP, 
                   selectArea[2]*UNIT, selectArea[3]*UNIT);
        g.setColor(255, 255, 255);
        // 4. 繪製目標移動框(洋紅)
        if (selected) {
            g.setColor(255, 0, 255);
            g.drawRect(moveArea[0]*UNIT+LEFT, moveArea[1]*UNIT+TOP,
                       moveArea[2]*UNIT, moveArea[3]*UNIT);
            g.setColor(255, 255, 255);
        }
    } catch (Exception ex) { /* 靜默吞沒,避免繪圖崩潰 */ }
    // 記憶體監控(調試用)
    System.out.println(Runtime.getRuntime().freeMemory());
}

3. 光標移動與區域計算

setRange():根據光標位置計算實際選中塊的邊界(處理 1x2、2x1、2x2 不同尺寸塊)

setMoveRange():驗證目標位置是否可移動(邊界檢查、碰撞檢查、空白格檢查)

private boolean setMoveRange() {
    // 遍歷選中區域所有格子
    for (int i = 0; i < selectArea[2]; i++) {
        for (int j = 0; j < selectArea[3]; j++) {
            int tx = loc[0] + i, ty = loc[1] + j;
            // 越界或目標非空白且非選中區域內部 → 不可移動
            if (ty >= HEIGHT || tx >= WIDTH || 
                (!isInRange(tx, ty) && myMap.grid[ty][tx] != BLANK)) {
                return false;
            }
        }
    }
    // 記錄合法目標區域
    moveArea[0] = loc[0]; moveArea[1] = loc[1];
    moveArea[2] = selectArea[2]; moveArea[3] = selectArea[3];
    return true;
}

4. 按鍵事件處理狀態機

protected void keyPressed(int keyCode) {
    switch (getGameAction(keyCode)) {
        case Canvas.UP:    moveCursor(0, -1); break;
        case Canvas.DOWN:  moveCursor(0, +1); break;
        case Canvas.LEFT:  moveCursor(-1, 0); break;
        case Canvas.RIGHT: moveCursor(+1, 0); break;
        case Canvas.FIRE:  handleFire(); break;
    }
}

private void moveCursor(int dx, int dy) {
    int nx = loc[0] + dx, ny = loc[1] + dy;
    if (nx < 0 || nx >= WIDTH || ny < 0 || ny >= HEIGHT) return;
    
    loc[0] = nx; loc[1] = ny;
    if (!selected) {
        setRange(); // 未選中時:移動光標並重新計算選中區域
    } else {
        if (setMoveRange()) { /* 合法目標 */ } 
        else { loc[0] -= dx; loc[1] -= dy; } // 非法則回退
    }
    repaint();
}

private void handleFire() {
    if (selected) {
        moveBlock(); // 執行移動
        selected = false;
        if (checkWin()) System.out.println("WIN!");
    } else {
        // 未選中時:若光標處非空白則進入選中狀態
        if (myMap.grid[loc[1]][loc[0]] != BLANK) selected = true;
    }
    repaint();
}

5. 方塊移動與勝利判定

private void moveBlock() {
    // 1. 備份選中區域數據
    byte[][] temp = new byte[selectArea[3]][selectArea[2]];
    for (int i = 0; i < selectArea[2]; i++)
        for (int j = 0; j < selectArea[3]; j++)
            temp[j][i] = myMap.grid[selectArea[1]+j][selectArea[0]+i];
    
    // 2. 將選中區域複製到目標區域
    for (int i = 0; i < selectArea[2]; i++)
        for (int j = 0; j < selectArea[3]; j++)
            myMap.grid[moveArea[1]+j][moveArea[0]+i] = temp[j][i];
    
    // 3. 清空選中區域中不在目標區域的殘留格子
    for (int i = 0; i < selectArea[3]; i++)
        for (int j = 0; j < selectArea[2]; j++)
            if (!isInRange2(selectArea[0]+j, selectArea[1]+i))
                myMap.grid[selectArea[1]+i][selectArea[0]+j] = BLANK;
    
    // 4. 重置狀態
    selectArea[0] = moveArea[0]; selectArea[1] = moveArea[1];
    moveArea[0] = -1; moveArea[1] = -1; moveArea[2] = 0; moveArea[3] = 0;
}

private boolean checkWin() {
    // 曹操 (CAOCAO) 到達右下出口位置
    return myMap.grid[HEIGHT-2][WIDTH-3] == CAOCAO;
}

工程化實踐要點

  • 資源管理:Images.init() 集中載入所有 PNG,遊戲結束時釋放
  • 記憶體監控:paint() 中輸出剩餘/總記憶體,針對 500KB-2MB 堆優化
  • 異常防護:繪圖、資源載入外層捕獲,避免單點崩潰
  • 調試輔助:printGrid() 打印地圖矩陣,移動前後對比驗證邏輯
  • 狀態機設計:selected 布爾標誌驅動「選中→移動→釋放」三態流轉

構建與運行

  1. WTK 2.0 KToolbar 建立專案
  2. 源碼置於 src/huarongroad/
  3. 資源檔(PNG、關卡數據)置於 res/
  4. Build → Run,模擟器中方向鍵移動、確認鍵選中/執行移動

總結

本文呈現了 J2ME 遊戲核心邏輯的完整實現:從資源載入、狀態管理、輸入處理、碰撞檢測、繪圖渲染到勝利判定。雖然平台已成歷史,但有限資源下的狀態機設計、繪圖管線優化、記憶體精細控制、邏輯與渲染分離等工程思想,在現代嵌入式、物聯網、WebAssembly 遊戲開發中依然極具參考價值。

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