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

Java 手機遊戲開發:MIDP 圖形編程實戰——九宮格遊戲完整代碼(下)

     編輯:Java 程式設計入門

GameScreen 完整源碼深度解析

本文提供 GameScreen 完整實現,涵蓋棋盤自適應、雙緩衝繪圖優化、光標閃爍、玩家/AI 走子、勝負判斷、戰績統計、命令處理等核心模塊,是 MIDP 遊戲開發的參考範本。

類結構與關鍵字段

class GameScreen extends Canvas implements CommandListener {
    // 顏色常量
    private static final int BLACK = 0x000000, WHITE = 0x00FFFFFF, RED = 0x00FF0000, BLUE = 0x000000FF;
    // 遊戲狀態
    private final TicTacToeMIDlet midlet;
    private final Game game; // 邏輯封裝類
    private final Random random = new Random();
    // 棋盤幾何
    private int screenWidth, screenHeight, boardCellSize, boardSize, boardTop, boardLeft;
    // 棋子屬性
    private boolean playerIsCircle, computerIsCircle;
    // 光標與走子
    private int preCursorPosition, cursorPosition;
    private int computerMove = NO_MOVE, playerMove = NO_MOVE;
    // 戰績
    private int computerGamesWonTally = 0, playerGamesWonTally = 0;
    private boolean isRestart;
    // 命令
    private final Command exitCommand, newGameCommand;
}

初始化與棋盤佈局

public GameScreen(TicTacToeMIDlet midlet, boolean playerIsCircle) {
    this.midlet = midlet; this.playerIsCircle = playerIsCircle;
    computerIsCircle = !playerIsCircle;
    game = new Game(random);
    initializeBoard(); // 動態計算幾何參數
    exitCommand = new Command("Exit", Command.EXIT, 1);
    newGameCommand = new Command("New", Command.SCREEN, 2);
    addCommand(exitCommand); addCommand(newGameCommand);
    setCommandListener(this);
    initialize(); // 開始首局
}
private void initializeBoard() {
    screenWidth = getWidth(); screenHeight = getHeight();
    if (screenWidth > screenHeight) { // 橫屏
        boardCellSize = (screenHeight - 2) / 3;
        boardLeft = (screenWidth - boardCellSize * 3) / 2;
        boardTop = 1;
    } else { // 豎屏
        boardCellSize = (screenWidth - 2) / 3;
        boardLeft = 1;
        boardTop = (screenHeight - boardCellSize * 3) / 2;
    }
}

遊戲輪次初始化

private void initialize() {
    game.initialize();
    preCursorPosition = cursorPosition = 0;
    playerMove = NO_MOVE;
    boolean computerFirst = ((random.nextInt() & 1) == 0); // 隨機先手
    if (computerFirst) computerMove = game.makeComputerMove();
    else computerMove = NO_MOVE;
    isRestart = true;
    repaint();
}

核心繪製邏輯

public void paint(Graphics g) {
    if (game.isGameOver()) paintGameOver(g);
    else paintGame(g);
}
private void paintGame(Graphics g) {
    if (isRestart) { // 首幀全繪
        g.setColor(WHITE); g.fillRect(0, 0, screenWidth, screenHeight);
        drawBoard(g); isRestart = false;
    }
    drawCursor(g); // 光標閃爍:擦除舊位置(白框)、繪製新位置(黑框)
    if (playerMove != NO_MOVE) drawPiece(g, playerIsCircle, playerMove);
    if (computerMove != NO_MOVE) drawPiece(g, computerIsCircle, computerMove);
}
private void paintGameOver(Graphics g) {
    String statusMsg = game.isComputerWinner() ? "I win !" : 
                       game.isPlayerWinner() ? "You win" : "Stalemate";
    if (game.isComputerWinner()) computerGamesWonTally++;
    else if (game.isPlayerWinner()) playerGamesWonTally++;
    String tallyMsg = "You:" + playerGamesWonTally + " Me:" + computerGamesWonTally;
    // 居中繪製結果文本
    Font font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM);
    int strHeight = font.getHeight();
    int x = (screenWidth - Math.max(font.stringWidth(statusMsg), font.stringWidth(tallyMsg))) / 2;
    x = x < 0 ? 0 : x;
    int y = (screenHeight - 2 * strHeight) / 2; y = y < 0 ? 0 : y;
    g.setColor(WHITE); g.fillRect(0, 0, screenWidth, screenHeight); // 清屏
    g.setColor(BLACK);
    g.drawString(statusMsg, x, y, Graphics.TOP | Graphics.LEFT);
    g.drawString(tallyMsg, x, y + 1 + strHeight, Graphics.TOP | Graphics.LEFT);
}

輸入處理:鍵盤映射與走子邏輯

protected void keyPressed(int keyCode) {
    if (game.isGameOver()) return;
    int action = getGameAction(keyCode);
    switch (action) {
        case FIRE: doPlayerMove(); break;
        case RIGHT: doMoveCursor(1, 0); break;
        case DOWN: doMoveCursor(0, 1); break;
        case LEFT: doMoveCursor(-1, 0); break;
        case UP: doMoveCursor(0, -1); break;
    }
}
private void doPlayerMove() {
    if (game.isFree(cursorPosition)) {
        playerMove = cursorPosition; // 記錄玩家落子位置供繪圖
        // AI 走子
        if (!game.isGameOver()) computerMove = game.makeComputerMove();
        repaint();
    }
}
private void doMoveCursor(int dx, int dy) {
    int newPos = cursorPosition + dx + 3 * dy;
    if (newPos >= 0 && newPos < 9) {
        preCursorPosition = cursorPosition;
        cursorPosition = newPos;
        repaint();
    }
}

棋子與棋盤繪製細節

private void drawPiece(Graphics g, boolean isCircle, int pos) {
    int x = (pos % 3) * boardCellSize + 3;
    int y = (pos / 3) * boardCellSize + 3;
    if (isCircle) drawCircle(g, x, y);
    else drawCross(g, x, y);
}
private void drawCircle(Graphics g, int x, int y) {
    g.setColor(BLUE);
    g.fillArc(x + boardLeft, y + boardTop, boardCellSize - 4, boardCellSize - 4, 0, 360);
    g.setColor(WHITE);
    g.fillArc(x + 4 + boardLeft, y + 4 + boardTop, boardCellSize - 12, boardCellSize - 12, 0, 360);
}
private void drawCross(Graphics g, int x, int y) {
    g.setColor(RED);
    for (int i = 0; i < 4; i++) {
        g.drawLine(x + 1 + i + boardLeft, y + boardTop, 
                   x + boardCellSize - 8 + i + boardLeft, y + boardCellSize - 5 + boardTop);
        g.drawLine(x + 1 + i + boardLeft, y + boardCellSize - 5 + boardTop,
                   x + boardCellSize - 8 + i + boardLeft, y + boardTop);
    }
}
private void drawCursor(Graphics g) {
    // 擦除舊光標
    g.setColor(WHITE);
    g.drawRect((preCursorPosition%3)*boardCellSize+2+boardLeft, 
               (preCursorPosition/3)*boardCellSize+2+boardTop, 
               boardCellSize-3, boardCellSize-3);
    // 繪製新光標
    g.setColor(BLACK);
    g.drawRect((cursorPosition%3)*boardCellSize+2+boardLeft,
               (cursorPosition/3)*boardCellSize+2+boardTop,
               boardCellSize-3, boardCellSize-3);
}
private void drawBoard(Graphics g) {
    g.setColor(WHITE); g.fillRect(0, 0, screenWidth, screenHeight);
    g.setColor(BLACK);
    for (int i = 0; i < 4; i++) {
        g.fillRect(boardLeft, boardCellSize*i + boardTop, boardCellSize*3+2, 2); // 橫線
        g.fillRect(boardCellSize*i + boardLeft, boardTop, 2, boardCellSize*3); // 豎線
    }
}

命令處理

public void commandAction(Command c, Displayable d) {
    if (c == exitCommand) midlet.quit();
    else if (c == newGameCommand) initialize();
}

Game 邏輯類接口(供參考)

class Game {
    private final Random random;
    private byte[] board = new byte[9]; // 0=空, 1=玩家, 2=電腦
    public Game(Random random) { this.random = random; }
    public void initialize() { Arrays.fill(board, (byte)0); }
    public boolean isFree(int pos) { return board[pos] == 0; }
    public int makeComputerMove() { /* Minimax 或啟發式算法 */ }
    public boolean isGameOver() { /* 檢查八條勝負線 + 平局 */ }
    public boolean isComputerWinner() { ... }
    public boolean isPlayerWinner() { ... }
}

性能與優化要點

  • 部分重繪:paintGame 僅在 isRestart 時全屏清屏,平時只繪製光標與新落子
  • 雙緩衝隱式支持:MIDP 實現通常自動雙緩衝,無需手動創建 Offscreen Image
  • 對象復用:Random、Font、Command 僅創建一次
  • 避免對象分配:繪圖循環中不創建新對象,基本類型運算
  • 內存監控:代碼中保留 Runtime.getRuntime().freeMemory() 打印,便於調試

移植性檢查清單

項目處理方式
屏幕尺寸getWidth/Height 動態佈局
鍵盤差異getGameAction 統一映射
顏色深度使用系統默認調色盤,避免依賴真彩色
字體大小Font.getHeight() 計算文本佈局
繪製性能最小化重繪區域,避免浮點運算

總結

GameScreen 展示了 MIDP 遊戲開發的最佳實踐:邏輯與視圖分離、動態適配、事件驅動、部分重繪、標準命令映射。此代碼可直接作為其他回合制遊戲(五子棋、翻棋、數獨)的框架基礎。下一階段可擴展:網絡對戰、AI 難度選擇、主題皮膚、觸屏支持(MIDP 3.0/LCDUI 扩展)。

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