Java Swing 经典贪吃蛇游戏从零开发
基于 Java Swing 框架实现经典贪吃蛇游戏,涵盖环境配置、项目结构、核心逻辑流程及分步代码实现。重点讲解定时器驱动循环、事件监听、碰撞检测及面向对象设计模式,提供完整可运行源码与调试技巧,适合 Java GUI 入门学习。

基于 Java Swing 框架实现经典贪吃蛇游戏,涵盖环境配置、项目结构、核心逻辑流程及分步代码实现。重点讲解定时器驱动循环、事件监听、碰撞检测及面向对象设计模式,提供完整可运行源码与调试技巧,适合 Java GUI 入门学习。

贪吃蛇作为编程入门的经典实战案例,不仅能巩固面向对象编程思想,还能深入理解 Java Swing GUI 开发、事件监听、定时器控制、碰撞检测等核心技术。本文将基于 Java Swing 框架,从零拆解贪吃蛇游戏的开发全流程,提供逐行代码解析及调试技巧,帮助新手快速上手。
本文适用于 Java 8 及以上版本,无需额外依赖(基于 JDK 原生 Swing 库),全程采用面向对象设计,代码结构清晰、注释详尽,可直接复制运行。
javax.swing 和 java.awt 包实现 GUI 与绘图功能为保证代码可读性与可维护性,采用模块化设计,核心类分工如下:
SnakeGame/
├─ src/
│ ├─ GameFrame.java // 主窗口类(负责创建游戏窗口、加载面板)
│ ├─ GamePanel.java // 游戏核心面板(绘图、逻辑、事件监听)
│ ├─ Direction.java // 方向枚举类(规范蛇的移动方向)
│ └─ SnakeMain.java // 程序入口类(启动游戏)
贪吃蛇游戏的核心是'定时器驱动循环 + 事件响应 + 状态更新 + 碰撞检测 + 图形渲染',整体逻辑闭环如下:
LinkedList 存储蛇身坐标(每个节点为 Point 对象),移动时通过'添加新头部 + 删除尾部'实现,吃到食物时不删除尾部即实现增长,效率高于数组操作。Direction 规范方向(上/下/左/右),禁止反向移动(如向右时不能直接向左),避免蛇自撞。javax.swing.Timer 触发游戏循环,通过调整定时器延迟时间控制蛇的移动速度(延迟越小,速度越快)。按'枚举定义→主窗口→游戏面板→程序入口'的顺序实现,每个类都标注详细注释,核心逻辑逐行解析。
用枚举规范蛇的移动方向,避免使用魔法值(数字/字符),提升代码可读性与可维护性。
/**
* 方向枚举类:规范蛇的移动方向
*/
public enum Direction {
UP, // 上
DOWN, // 下
LEFT, // 左
RIGHT // 右
}
负责创建游戏主窗口,设置窗口属性(大小、标题、关闭行为),并将游戏面板加载到窗口中。
import javax.swing.JFrame;
/**
* 游戏主窗口类:承载游戏面板,设置窗口基础属性
*/
public class GameFrame extends JFrame {
// 游戏窗口尺寸常量(像素)
public static final int WIDTH = 600;
public static final int HEIGHT = 480;
public GameFrame() {
// 初始化窗口属性
initFrame();
// 加载游戏面板
GamePanel gamePanel = new GamePanel(this);
this.add(gamePanel);
// 窗口自适应面板大小(避免内容被截断)
this.pack();
// 窗口居中显示
this.setLocationRelativeTo(null);
// 窗口大小固定(禁止用户拉伸,保证游戏体验)
this.setResizable(false);
}
/**
* 初始化窗口核心属性
*/
private void initFrame() {
// 设置窗口标题
this.setTitle("Java 贪吃蛇 | 方向键控制 | P 暂停 | R 重启");
// 设置窗口关闭行为(关闭窗口时终止程序)
.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
.setSize(WIDTH, HEIGHT);
}
}
游戏的核心类,集成绘图、事件监听、逻辑处理、定时器控制等功能,实现 ActionListener(定时器事件)和 KeyListener(键盘事件)接口。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.LinkedList;
import java.util.Random;
/**
* 游戏核心面板类:负责绘图、事件监听、游戏逻辑处理
*/
public class GamePanel extends JPanel implements ActionListener, KeyListener {
// 网格大小(蛇身/食物的基础单位,像素)
private static final int GRID_SIZE = 20;
// 定时器延迟(毫秒),值越小速度越快(初始速度适中)
private static final int TIMER_DELAY = 150;
// 颜色常量(RGB 值,提升游戏视觉体验)
private static final Color BG_COLOR = new Color(30, 30, 30); // 深色背景
private static final Color SNAKE_HEAD_COLOR = new Color(, , );
(, , );
(, , );
(, , );
GameFrame frame;
LinkedList<Point> snake;
Point food;
Direction direction;
Timer timer;
score;
isPaused;
isGameOver;
Random random;
{
.frame = frame;
initGame();
initPanel();
}
{
snake = <>();
frame.WIDTH / / GRID_SIZE;
frame.HEIGHT / / GRID_SIZE;
snake.add( (startX, startY));
snake.add( (startX - , startY));
snake.add( (startX - , startY));
direction = Direction.RIGHT;
score = ;
isPaused = ;
isGameOver = ;
random = ();
generateFood();
timer = (TIMER_DELAY, );
timer.start();
}
{
.setPreferredSize( (frame.WIDTH, frame.HEIGHT));
.setBackground(BG_COLOR);
.addKeyListener();
.setFocusable();
.setDoubleBuffered();
}
{
() {
random.nextInt(frame.WIDTH / GRID_SIZE);
random.nextInt(frame.HEIGHT / GRID_SIZE);
food = (x, y);
(!snake.contains(food)) {
;
}
}
}
{
.paintComponent(g);
drawSnake(g);
drawFood(g);
drawUI(g);
}
{
( ; i < snake.size(); i++) {
snake.get(i);
point.x * GRID_SIZE;
point.y * GRID_SIZE;
(i == ) {
g.setColor(SNAKE_HEAD_COLOR);
} {
g.setColor(SNAKE_BODY_COLOR);
}
g.fillRoundRect(x, y, GRID_SIZE - , GRID_SIZE - , , );
}
}
{
food.x * GRID_SIZE;
food.y * GRID_SIZE;
g.setColor(FOOD_COLOR);
g.fillOval(x, y, GRID_SIZE - , GRID_SIZE - );
}
{
g.setColor(TEXT_COLOR);
g.setFont( (, Font.BOLD, ));
g.drawString( + score, , );
g.setFont( (, Font.PLAIN, ));
g.drawString(, frame.WIDTH - , );
g.drawString(, frame.WIDTH - , );
g.drawString(, frame.WIDTH - , );
(isPaused && !isGameOver) {
g.setFont( (, Font.BOLD, ));
;
(frame.WIDTH - g.getFontMetrics().stringWidth(pauseText)) / ;
frame.HEIGHT / ;
g.drawString(pauseText, textX, textY);
}
(isGameOver) {
g.setFont( (, Font.BOLD, ));
+ score;
;
(frame.WIDTH - g.getFontMetrics().stringWidth(overText1)) / ;
(frame.WIDTH - g.getFontMetrics().stringWidth(overText2)) / ;
frame.HEIGHT / - ;
frame.HEIGHT / + ;
g.drawString(overText1, textX1, textY1);
g.drawString(overText2, textX2, textY2);
}
}
{
snake.getFirst();
(head);
(direction) {
UP:
newHead.y--;
;
DOWN:
newHead.y++;
;
LEFT:
newHead.x--;
;
RIGHT:
newHead.x++;
;
}
(checkCollision(newHead)) {
isGameOver = ;
timer.stop();
;
}
snake.addFirst(newHead);
(newHead.equals(food)) {
score += ;
generateFood();
} {
snake.removeLast();
}
}
{
(newHead.x < || newHead.x >= frame.WIDTH / GRID_SIZE || newHead.y < || newHead.y >= frame.HEIGHT / GRID_SIZE) {
;
}
( ; i < snake.size(); i++) {
(newHead.equals(snake.get(i))) {
;
}
}
;
}
{
(!isPaused && !isGameOver) {
moveSnake();
}
repaint();
}
{
e.getKeyCode();
(isGameOver) {
(keyCode == KeyEvent.VK_R) {
initGame();
}
;
}
(isPaused) {
(keyCode == KeyEvent.VK_P) {
isPaused = ;
}
;
}
(keyCode) {
KeyEvent.VK_UP:
(direction != Direction.DOWN) {
direction = Direction.UP;
}
;
KeyEvent.VK_DOWN:
(direction != Direction.UP) {
direction = Direction.DOWN;
}
;
KeyEvent.VK_LEFT:
(direction != Direction.RIGHT) {
direction = Direction.LEFT;
}
;
KeyEvent.VK_RIGHT:
(direction != Direction.LEFT) {
direction = Direction.RIGHT;
}
;
KeyEvent.VK_P:
isPaused = ;
;
KeyEvent.VK_R:
initGame();
;
}
}
{}
{}
}
简洁的入口类,负责启动游戏(创建主窗口并显示),符合 Java 程序设计规范。
import javax.swing.SwingUtilities;
/**
* 程序入口类:启动贪吃蛇游戏
* 用 SwingUtilities.invokeLater 确保 UI 组件在 EDT 线程(事件调度线程)中创建,避免线程安全问题
*/
public class SnakeMain {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
GameFrame gameFrame = new GameFrame();
gameFrame.setVisible(true); // 显示主窗口
});
}
}
SnakeMain.java 的 main 方法,即可启动游戏。setFocusable(true),确保面板获取焦点;若仍无效,可在 GameFrame 初始化后调用 gamePanel.requestFocus() 强制获取焦点。setDoubleBuffered(true)),若仍有闪烁,可检查是否在 paintComponent 外执行绘图操作(必须在该方法内绘图)。TIMER_DELAY 常量(值越小速度越快,建议范围 100-200ms)。generateFood() 方法中的循环逻辑,确保食物位置不在蛇身链表中才退出循环。基础版本实现后,可添加以下功能提升游戏体验,适合进一步练手巩固 Java 知识点:
java.applet.AudioClip 类添加吃食物、碰撞、游戏开始的音效,提升沉浸感。BufferedWriter/BufferedReader)将最高分保存到本地文件,启动时读取并显示历史最高分。本文基于 Java Swing 框架实现了经典贪吃蛇游戏,核心在于掌握'定时器驱动循环 + 事件监听 + 状态管理'的 GUI 开发模式,同时通过面向对象设计将复杂逻辑拆解为独立模块(窗口、面板、方向枚举),提升代码可读性与可扩展性。
通过本次实战,不仅能熟练掌握 Swing 的核心用法(窗口创建、绘图、事件处理、定时器),还能深入理解碰撞检测、坐标转换、链表操作等通用编程思想,为后续开发更复杂的 Java GUI 程序(如计算器、记事本、小游戏)打下坚实基础。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online