本文將引導你使用 Java Swing 庫從零構建一款經典的「貪吃蛇」遊戲極速版。涵蓋遊戲主循環、雙緩衝繪圖、鍵盤事件監聽、碰撞檢測及分數統計等核心遊戲開發技術。
JFrame,遊戲主窗口。JPanel,核心繪圖與邏輯面板,實現 Runnable 和 KeyListener。public class GamePanel extends JPanel implements Runnable, KeyListener {
private final int WIDTH = 800;
private final int HEIGHT = 600;
private final int UNIT_SIZE = 20; // 每個格子大小
private final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);
private final int DELAY = 75; // 極速版:刷新間隔 75ms
private int[] x = new int[GAME_UNITS]; // 蛇身 X 座標數組
private int[] y = new int[GAME_UNITS]; // 蛇身 Y 座標數組
private int bodyParts = 6; // 初始長度
private int applesEaten = 0;
private int appleX, appleY;
private char direction = 'R'; // 初始向右
private boolean running = false;
private Thread gameThread;
private Image offScreenImage; // 雙緩衝圖像
public GamePanel() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(Color.BLACK);
setFocusable(true);
addKeyListener(this);
startGame();
}
public void startGame() {
newApple();
running = true;
gameThread = new Thread(this);
gameThread.start();
}
// ...
}
@Override
public void run() {
while (running) {
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (running) {
move(); // 移動蛇身
checkApple(); // 檢測吃食物
checkCollisions(); // 檢測碰撞
}
repaint(); // 觸發 paintComponent 重繪
}
}
public void move() {
// 身體跟隨頭部移動(從尾部向前更新座標)
for (int i = bodyParts; i > 0; i--) {
x[i] = x[i - 1];
y[i] = y[i - 1];
}
// 根據方向更新頭部座標
switch (direction) {
case 'U': y[0] -= UNIT_SIZE; break;
case 'D': y[0] += UNIT_SIZE; break;
case 'L': x[0] -= UNIT_SIZE; break;
case 'R': x[0] += UNIT_SIZE; break;
}
}
public void checkCollisions() {
// 撞牆檢測
if (x[0] < 0 || x[0] >= WIDTH || y[0] < 0 || y[0] >= HEIGHT) {
running = false;
}
// 撞自己檢測
for (int i = bodyParts; i > 0; i--) {
if (x[0] == x[i] && y[0] == y[i]) {
running = false;
break;
}
}
if (!running) gameThread.interrupt();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
private void doDrawing(Graphics g) {
if (offScreenImage == null) {
offScreenImage = createImage(WIDTH, HEIGHT);
}
Graphics gOff = offScreenImage.getGraphics();
// 繪製背景網格、食物、蛇身、分數...
gOff.setColor(Color.RED);
gOff.fillOval(appleX, appleY, UNIT_SIZE, UNIT_SIZE);
for (int i = 0; i < bodyParts; i++) {
gOff.setColor(i == 0 ? Color.GREEN : new Color(45, 180, 0));
gOff.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
}
g.drawImage(offScreenImage, 0, 0, this); // 將離屏圖像一次性繪到屏幕
}
@Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
// 防止 180 度掉頭
if ((key == KeyEvent.VK_LEFT || key == KeyEvent.VK_A) && direction != 'R') direction = 'L';
else if ((key == KeyEvent.VK_RIGHT || key == KeyEvent.VK_D) && direction != 'L') direction = 'R';
else if ((key == KeyEvent.VK_UP || key == KeyEvent.VK_W) && direction != 'D') direction = 'U';
else if ((key == KeyEvent.VK_DOWN || key == KeyEvent.VK_S) && direction != 'U') direction = 'D';
}
// keyReleased, keyTyped 留空
public class SnakeGameMain {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Java 貪吃蛇極速版");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(new GamePanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
BufferStrategy 替代手動雙緩衝,性能更強。通過約 200 行核心代碼,我們實現了流暢的「貪吃蛇」極速版。此項目是理解 Java 遊戲循環、Swing 繪圖機制、事件驅動編程的絕佳入門實踐。