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

Java Swing 圖形界面入門實戰:從零手寫貪吃蛇遊戲完整教學

     編輯:Java 綜合教學

Java Swing 圖形界面入門實戰:從零手寫貪吃蛇遊戲完整教學

本文以經典「貪吃蛇」為例,帶領初學者逐步掌握 Java Swing 核心組件:JFrame 視窗框架、JPanel 繪圖面板、KeyListener 鍵盤事件、Runnable/Thread 遊戲迴圈、雙緩衝繪圖技巧,並附完整專案結構與代碼片段。

專案架構概覽

  • SnakeFrame:繼承 JFrame,負責視窗初始化 (標題、尺寸、置中、關閉操作、不可縮放)。
  • SnakePanel:繼承 JPanel,核心繪圖邏輯 (paintComponent)、控制按鈕、分數顯示、鍵盤監聽註冊。
  • SnakeControl:實作 KeyListener,處理方向鍵輸入,防止 180° 反向移動。
  • Snake / Food / Coordination:遊戲領域模型,封裝蛇身座標、食物生成、碰撞判斷邏輯。
  • GameThread (Runnable) + SnakeThread (Thread):雙執行緒架構,分別負責倒計時/啟動流程與蛇身移動主迴圈。

核心組件詳細實作

1. JFrame 視窗框架 (SnakeFrame)

public class SnakeFrame extends JFrame {
    private static final long serialVersionUID = 1L;
    private final int WIDTH = 530, HEIGHT = 450;

    public SnakeFrame() {
        setTitle("貪吃蛇 v1.0");
        setSize(WIDTH, HEIGHT);
        setLocationRelativeTo(null); // 畫面置中
        setDefaultCloseOperation(EXIT_ON_CLOSE); // 關閉視窗結束程式
        setResizable(false);       // 禁止縮放
        setLayout(null);           // 絕對佈局,由 Panel 內部管理
        setVisible(true);
    }
}

2. JPanel 繪圖面板 (SnakePanel) - 核心

初始化 UI 控制項
private JLabel lblScoreText; // "得分:"
private JButton btnScore;    // 顯示分數 (不可編輯)
private JButton btnStart;    // 開始按鈕
private JButton btnAbout;    // 關於按鈕

private void initUI() {
    setLayout(null);
    lblScoreText = new JLabel("得分:");
    lblScoreText.setFont(new Font("Dialog", Font.BOLD, 20));
    lblScoreText.setBounds(420, 100, 80, 60);
    add(lblScoreText);

    btnScore = new JButton("0");
    btnScore.setBounds(480, 100, 50, 60);
    btnScore.setEnabled(false); // 僅顯示
    add(btnScore);

    btnStart = new JButton("開始遊戲");
    btnStart.setBounds(420, 250, 90, 30);
    btnStart.addActionListener(e -> startGame());
    add(btnStart);

    btnAbout = new JButton("關於遊戲");
    btnAbout.setBounds(420, 300, 90, 30);
    add(btnAbout);

    requestFocusInWindow(); // 獲取鍵盤焦點
}
繪圖邏輯 (paintComponent) - 雙緩衝防閃爍
@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g); // 清屏、重繪背景與子元件

    Graphics2D g2d = (Graphics2D) g;
    // 開啟抗鋸齒
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    drawGrid(g2d);           // 畫網格
    if (isGameOver) drawGameOver(g2d);
    if (isStarted) {
        drawSnake(g2d);      // 畫蛇身 (頭/身/尾區分圖片)
        drawFood(g2d);       // 畫食物
        if (countdown > -1) drawCountdown(g2d); // 倒計時
    }
}
遊戲主迴圈雙執行緒設計

3. 鍵盤事件處理 (SnakeControl implements KeyListener)

public class SnakeControl implements KeyListener {
    private SnakePanel panel;
    private Snake.Direction nextDir = Snake.Direction.UP;

    public SnakeControl(SnakePanel panel) { this.panel = panel; }

    @Override
    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_UP:    if (nextDir != Snake.Direction.DOWN) nextDir = Snake.Direction.UP; break;
            case KeyEvent.VK_DOWN:  if (nextDir != Snake.Direction.UP)   nextDir = Snake.Direction.DOWN; break;
            case KeyEvent.VK_LEFT:  if (nextDir != Snake.Direction.RIGHT) nextDir = Snake.Direction.LEFT; break;
            case KeyEvent.VK_RIGHT: if (nextDir != Snake.Direction.LEFT) nextDir = Snake.Direction.RIGHT; break;
        }
        panel.getSnake().setNextDirection(nextDir);
    }
    @Override public void keyReleased(KeyEvent e) {}
    @Override public void keyTyped(KeyEvent e) {}
}

在 SnakePanel 建構子註冊:addKeyListener(new SnakeControl(this));

4. 遊戲領域模型 (座標、蛇、食物)

    技術點說明
    paintComponent vs paint覆寫 paintComponent 只負責繪圖區域,配合 super.paintComponent(g) 清屏,避免重繪邊框/子元件。
    雙緩衝Swing 預設開啟雙緩衝,直接在 paintComponent 畫即可;若自行管理 BufferedImage 需手動 g.drawImage(buffer, 0, 0, null)。
    repaint() 非同步呼叫 repaint() 只排程重繪,不立即執行;遊戲迴圈 sleep 控制幀率。
    焦點問題JPanel 需 setFocusable(true) + requestFocusInWindow() 才能接收鍵盤事件。
    執行緒安全遊戲狀態變數 (isStarted, isGameOver, paused) 需 volatile 或 synchronized 保護。


常見問題與避坑指南

  1. 視窗空白不顯示:Windows 下偶發,確保在 EDT 執行 GUI 建構:SwingUtilities.invokeLater(() -> new SnakeFrame())。
  2. 圖片路徑失效:用 getClass().getResource("/images/head.png") 載入 classpath 資源,打包成 JAR 也能正常讀取。
  3. 鍵盤無反應:檢查 requestFocusInWindow()、setFocusable(true)、是否有其他元件搶焦點。
  4. 蛇身重疊/穿牆判斷錯誤:座標系統原點 (0,0) 在左上角,x 向右、y 向下;牆壁邊界為 [0, 39]。

擴充練習建議

  • 加入等級系統:分數達標縮短 sleep 時間、增加障礙物。
  • 實作暫停/繼續功能 (已在代碼預留 pauseLock 機制)。
  • 引入高分榜:用 Preferences 或 SQLite 本地持久化。
  • 嘗試 JavaFX 重寫:體驗現代宣告式 UI、CSS 樣式、動畫 API。

結語

貪吃蛇雖小,却涵蓋了 Swing 開發的核心知識點:視窗管理、自定義繪圖、事件驅動、多執行緒協作、遊戲迴圈設計。建議初學者手敲一遍,再嘗試加入新功能,將被動閱讀轉為主動掌握。

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