## 一、项目简介这是一个基于 **Java Swing** 开发的经典贪吃蛇游戏采用 **MVC架构** 设计支持三种难度选择、MySQL排行榜存储、音效系统和多线程优化。该项目适合Java初学者学习GUI开发、设计模式和数据库操作。## 二、功能特性- **完整游戏逻辑**蛇的移动、吃食物、碰撞检测、游戏结束判定- ⚡ **三种难度选择**简单250ms/帧、中等150ms/帧、困难80ms/帧- **分数系统**实时分数显示、本地文件存储最高分- **MySQL排行榜**支持全服排行榜和各难度排行榜- **音效系统**开始游戏、吃食物、碰撞、游戏结束等音效- **现代化界面**圆润的蛇设计、苹果食物、渐变背景、半透明遮罩- ⏸️ **暂停/继续**支持游戏暂停和继续功能## 三、技术栈- **语言**: Java SE 17- **GUI框架**: Java Swing- **设计模式**: MVCModel-View-Controller- **数据库**: MySQL 8.0- **多线程**: SwingWorker- **数据结构**: LinkedList## 四、架构设计### MVC模式本项目采用经典的MVC架构模式将游戏逻辑、界面渲染和用户交互分离┌─────────────────────────────────────────────────────────┐│ View ││ GameWindow GamePanel ││ (界面渲染、用户输入、音效播放) │└───────────────────┬─────────────────────────────────────┘│ 更新界面│ 获取输入▼┌─────────────────────────────────────────────────────────┐│ Controller ││ GameController ││ (协调模型和视图、处理游戏逻辑) │└───────────────────┬─────────────────────────────────────┘│ 更新状态│ 获取数据▼┌─────────────────────────────────────────────────────────┐│ Model ││ Snake food GameState ││ (数据模型、业务逻辑、状态管理) │└─────────────────────────────────────────────────────────┘### 核心类职责| 类名 | 职责 | 所属层 ||------|------|--------|| GameController | 游戏核心逻辑处理键盘事件 | Controller || GameWindow | 主窗口管理界面切换 | View || GamePanel | 游戏画布渲染蛇和食物 | View || Snake | 蛇的数据模型和移动逻辑 | Model || food | 食物生成和位置管理 | Model || GameState | 游戏状态封装 | Model || GameWorker | 后台线程游戏循环 | Controller |## 五、核心代码解析### 1. 游戏主循环SwingWorker优化使用 SwingWorker 进行多线程优化游戏逻辑在后台线程执行UI更新在事件调度线程执行javapublic class GameWorker extends SwingWorkerGameState, GameState {private final GameController controller;private volatile boolean running true;Overrideprotected GameState doInBackground() throws Exception {while (running !isCancelled()) {if (controller.isGameRunning()) {controller.update();publish(new GameState(controller.getSnake().getBody(),controller.getFood().getPosition(),controller.getScore(),controller.isGameOver()));}Thread.sleep(controller.getDifficulty().getDelay());}return null;}Overrideprotected void process(ListGameState chunks) {for (GameState state : chunks) {controller.getGamePanel().updateState(state);}}}**设计思路**doInBackground() 在后台线程执行游戏逻辑process() 在EDT线程更新UI避免界面卡顿。### 2. 蛇的移动逻辑使用 LinkedList 实现蛇身的高效增删操作javapublic void move(Direction direction) {Node head snakeBody.getFirst();Node newHead new Node(head.getX() direction.getX(),head.getY() direction.getY());snakeBody.addFirst(newHead);if (isFoodEaten(newHead, food)) {score difficulty.getScorePerFood();food.generateNewPosition(snakeBody);} else {snakeBody.removeLast();}}**技术亮点**- LinkedList.addFirst() 和 removeLast() 时间复杂度均为 O(1)- 蛇身增长时只添加头部不删除尾部- 正常移动时添加头部并删除尾部### 3. 碰撞检测实现蛇与墙壁、蛇与自身的碰撞检测javapublic boolean checkCollision() {Node head snakeBody.getFirst();// 边界碰撞if (head.getX() 0 || head.getX() WIDTH ||head.getY() 0 || head.getY() HEIGHT) {return true;}// 自身碰撞for (int i 1; i snakeBody.size(); i) {Node bodyPart snakeBody.get(i);if (head.getX() bodyPart.getX() head.getY() bodyPart.getY()) {return true;}}return false;}### 4. MySQL数据库操作使用 PreparedStatement 防止SQL注入javapublic void saveScore(String playerName, int score, Difficulty difficulty) {String insertSQL INSERT INTO high_scores (player_name, score, difficulty, date_time) VALUES (?, ?, ?, NOW());try (PreparedStatement pstmt connection.prepareStatement(insertSQL)) {pstmt.setString(1, playerName);pstmt.setInt(2, score);pstmt.setString(3, difficulty.name());pstmt.executeUpdate();} catch (SQLException e) {System.err.println(保存分数失败: e.getMessage());}}**安全措施**- 使用 PreparedStatement 预编译语句- 配置文件读取数据库密码不硬编码- .gitignore 排除敏感配置文件### 5. 音效系统使用 Java Sound API 生成音效javapublic void playEatSound() {try {AudioFormat format new AudioFormat(44100, 16, 1, true, false);SourceDataLine line AudioSystem.getSourceDataLine(format);line.open(format);line.start();byte[] sound new byte[44100 / 50];for (int i 0; i sound.length; i) {sound[i] (byte) (Math.sin(i * 440 * 2 * Math.PI / 44100) * 127);}line.write(sound, 0, sound.length);line.stop();line.close();} catch (Exception e) {e.printStackTrace();}}## 六、数据库设计### 表结构sqlCREATE TABLE high_scores (id INT AUTO_INCREMENT PRIMARY KEY,player_name VARCHAR(50) NOT NULL,score INT NOT NULL,difficulty VARCHAR(20) NOT NULL,date_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP);### 配置方式创建 db.properties 文件propertiesdb.passwordyour_mysql_password **注意**db.properties 文件已加入 .gitignore不会被提交到版本控制。## 七、运行说明### 环境要求- JDK 17- MySQL 8.0可选用于排行榜功能### 运行方式**方式一使用批处理脚本**bash双击 run_game.bat**方式二手动编译运行**bashjavac -encoding UTF-8 -d out/production/snakeGrme src/com/zut/*.javajava -Dfile.encodingUTF-8 -cp out/production/snakeGrme;lib/mysql-connector-java-8.3.0.jar com.zut.main### 操作说明| 按键 | 功能 ||------|------|| ↑ ↓ ← → | 控制蛇的移动方向 || P | 暂停 / 继续游戏 || R | 游戏结束后重新开始 || ← 返回按钮 | 返回主菜单 |
Java Swing贪吃蛇游戏完整实现(MVC架构+MySQL排行榜+音效系统)
## 一、项目简介这是一个基于 **Java Swing** 开发的经典贪吃蛇游戏采用 **MVC架构** 设计支持三种难度选择、MySQL排行榜存储、音效系统和多线程优化。该项目适合Java初学者学习GUI开发、设计模式和数据库操作。## 二、功能特性- **完整游戏逻辑**蛇的移动、吃食物、碰撞检测、游戏结束判定- ⚡ **三种难度选择**简单250ms/帧、中等150ms/帧、困难80ms/帧- **分数系统**实时分数显示、本地文件存储最高分- **MySQL排行榜**支持全服排行榜和各难度排行榜- **音效系统**开始游戏、吃食物、碰撞、游戏结束等音效- **现代化界面**圆润的蛇设计、苹果食物、渐变背景、半透明遮罩- ⏸️ **暂停/继续**支持游戏暂停和继续功能## 三、技术栈- **语言**: Java SE 17- **GUI框架**: Java Swing- **设计模式**: MVCModel-View-Controller- **数据库**: MySQL 8.0- **多线程**: SwingWorker- **数据结构**: LinkedList## 四、架构设计### MVC模式本项目采用经典的MVC架构模式将游戏逻辑、界面渲染和用户交互分离┌─────────────────────────────────────────────────────────┐│ View ││ GameWindow GamePanel ││ (界面渲染、用户输入、音效播放) │└───────────────────┬─────────────────────────────────────┘│ 更新界面│ 获取输入▼┌─────────────────────────────────────────────────────────┐│ Controller ││ GameController ││ (协调模型和视图、处理游戏逻辑) │└───────────────────┬─────────────────────────────────────┘│ 更新状态│ 获取数据▼┌─────────────────────────────────────────────────────────┐│ Model ││ Snake food GameState ││ (数据模型、业务逻辑、状态管理) │└─────────────────────────────────────────────────────────┘### 核心类职责| 类名 | 职责 | 所属层 ||------|------|--------|| GameController | 游戏核心逻辑处理键盘事件 | Controller || GameWindow | 主窗口管理界面切换 | View || GamePanel | 游戏画布渲染蛇和食物 | View || Snake | 蛇的数据模型和移动逻辑 | Model || food | 食物生成和位置管理 | Model || GameState | 游戏状态封装 | Model || GameWorker | 后台线程游戏循环 | Controller |## 五、核心代码解析### 1. 游戏主循环SwingWorker优化使用 SwingWorker 进行多线程优化游戏逻辑在后台线程执行UI更新在事件调度线程执行javapublic class GameWorker extends SwingWorkerGameState, GameState {private final GameController controller;private volatile boolean running true;Overrideprotected GameState doInBackground() throws Exception {while (running !isCancelled()) {if (controller.isGameRunning()) {controller.update();publish(new GameState(controller.getSnake().getBody(),controller.getFood().getPosition(),controller.getScore(),controller.isGameOver()));}Thread.sleep(controller.getDifficulty().getDelay());}return null;}Overrideprotected void process(ListGameState chunks) {for (GameState state : chunks) {controller.getGamePanel().updateState(state);}}}**设计思路**doInBackground() 在后台线程执行游戏逻辑process() 在EDT线程更新UI避免界面卡顿。### 2. 蛇的移动逻辑使用 LinkedList 实现蛇身的高效增删操作javapublic void move(Direction direction) {Node head snakeBody.getFirst();Node newHead new Node(head.getX() direction.getX(),head.getY() direction.getY());snakeBody.addFirst(newHead);if (isFoodEaten(newHead, food)) {score difficulty.getScorePerFood();food.generateNewPosition(snakeBody);} else {snakeBody.removeLast();}}**技术亮点**- LinkedList.addFirst() 和 removeLast() 时间复杂度均为 O(1)- 蛇身增长时只添加头部不删除尾部- 正常移动时添加头部并删除尾部### 3. 碰撞检测实现蛇与墙壁、蛇与自身的碰撞检测javapublic boolean checkCollision() {Node head snakeBody.getFirst();// 边界碰撞if (head.getX() 0 || head.getX() WIDTH ||head.getY() 0 || head.getY() HEIGHT) {return true;}// 自身碰撞for (int i 1; i snakeBody.size(); i) {Node bodyPart snakeBody.get(i);if (head.getX() bodyPart.getX() head.getY() bodyPart.getY()) {return true;}}return false;}### 4. MySQL数据库操作使用 PreparedStatement 防止SQL注入javapublic void saveScore(String playerName, int score, Difficulty difficulty) {String insertSQL INSERT INTO high_scores (player_name, score, difficulty, date_time) VALUES (?, ?, ?, NOW());try (PreparedStatement pstmt connection.prepareStatement(insertSQL)) {pstmt.setString(1, playerName);pstmt.setInt(2, score);pstmt.setString(3, difficulty.name());pstmt.executeUpdate();} catch (SQLException e) {System.err.println(保存分数失败: e.getMessage());}}**安全措施**- 使用 PreparedStatement 预编译语句- 配置文件读取数据库密码不硬编码- .gitignore 排除敏感配置文件### 5. 音效系统使用 Java Sound API 生成音效javapublic void playEatSound() {try {AudioFormat format new AudioFormat(44100, 16, 1, true, false);SourceDataLine line AudioSystem.getSourceDataLine(format);line.open(format);line.start();byte[] sound new byte[44100 / 50];for (int i 0; i sound.length; i) {sound[i] (byte) (Math.sin(i * 440 * 2 * Math.PI / 44100) * 127);}line.write(sound, 0, sound.length);line.stop();line.close();} catch (Exception e) {e.printStackTrace();}}## 六、数据库设计### 表结构sqlCREATE TABLE high_scores (id INT AUTO_INCREMENT PRIMARY KEY,player_name VARCHAR(50) NOT NULL,score INT NOT NULL,difficulty VARCHAR(20) NOT NULL,date_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP);### 配置方式创建 db.properties 文件propertiesdb.passwordyour_mysql_password **注意**db.properties 文件已加入 .gitignore不会被提交到版本控制。## 七、运行说明### 环境要求- JDK 17- MySQL 8.0可选用于排行榜功能### 运行方式**方式一使用批处理脚本**bash双击 run_game.bat**方式二手动编译运行**bashjavac -encoding UTF-8 -d out/production/snakeGrme src/com/zut/*.javajava -Dfile.encodingUTF-8 -cp out/production/snakeGrme;lib/mysql-connector-java-8.3.0.jar com.zut.main### 操作说明| 按键 | 功能 ||------|------|| ↑ ↓ ← → | 控制蛇的移动方向 || P | 暂停 / 继续游戏 || R | 游戏结束后重新开始 || ← 返回按钮 | 返回主菜单 |