我将为您提供一个完整的 Java 贪吃蛇游戏实现代码,基于 Swing 图形界面库开发。这个实现包含了游戏的所有核心功能,包括蛇的移动、食物生成、碰撞检测和分数计算等。
完整贪吃蛇游戏代码实现
1. 主程序入口类 (SnakeGame.java)
import javax.swing.*; /** * 贪吃蛇游戏主类 * 负责创建游戏窗口和启动游戏 */ public class SnakeGame { public static void main(String[] args) { // 创建游戏窗口 JFrame frame = new JFrame("贪吃蛇游戏"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setResizable(false); // 创建游戏面板 GamePanel gamePanel = new GamePanel(); frame.add(gamePanel); // 自动调整窗口大小 frame.pack(); frame.setLocationRelativeTo(null); // 窗口居中显示 frame.setVisible(true); // 启动游戏 gamePanel.startGame(); } }2. 游戏面板类 (GamePanel.java)
import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.LinkedList; import java.util.Random; /** * 游戏主面板类 * 处理游戏逻辑和图形绘制 */ public class GamePanel extends JPanel implements ActionListener, KeyListener { // 游戏常量 private static final int WIDTH = 600; private static final int HEIGHT = 600; private static final int UNIT_SIZE = 25; private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE); private static final int DELAY = 75; // 蛇的身体坐标 private final LinkedList<Point> snakeBody = new LinkedList<>(); private int snakeLength = 3; // 食物坐标 private Point food; // 移动方向 private char direction = 'R'; // R:右, L:左, U:上, D:下 private char lastDirection = 'R'; // 游戏状态 private boolean running = false; private boolean paused = false; private int score = 0; // 定时器 private Timer timer; private Random random; public GamePanel() { random = new Random(); this.setPreferredSize(new Dimension(WIDTH, HEIGHT)); this.setBackground(Color.BLACK); this.setFocusable(true); this.addKeyListener(this); initGame(); } /** * 初始化游戏 */ public void initGame() { // 清空蛇身 snakeBody.clear(); // 初始化蛇的位置(在屏幕中央) int startX = WIDTH / 2 / UNIT_SIZE * UNIT_SIZE; int startY = HEIGHT / 2 / UNIT_SIZE * UNIT_SIZE; // 创建初始蛇身(3个单位长度) for (int i = 0; i < snakeLength; i++) { snakeBody.add(new Point(startX - i * UNIT_SIZE, startY)); } // 生成第一个食物 generateFood(); // 重置游戏状态 direction = 'R'; lastDirection = 'R'; score = 0; running = true; paused = false; } /** * 开始游戏 */ public void startGame() { if (timer == null) { timer = new Timer(DELAY, this); } timer.start(); } /** * 生成食物 */ private void generateFood() { int x = random.nextInt(WIDTH / UNIT_SIZE) * UNIT_SIZE; int y = random.nextInt(HEIGHT / UNIT_SIZE) * UNIT_SIZE; food = new Point(x, y); // 确保食物不会生成在蛇身上 while (snakeBody.contains(food)) { x = random.nextInt(WIDTH / UNIT_SIZE) * UNIT_SIZE; y = random.nextInt(HEIGHT / UNIT_SIZE) * UNIT_SIZE; food = new Point(x, y); } } /** * 移动蛇 */ private void move() { if (!running || paused) return; // 获取蛇头位置 Point head = snakeBody.getFirst(); Point newHead = new Point(head); // 根据方向移动蛇头 switch (direction) { case 'U': // 上 newHead.y -= UNIT_SIZE; break; case 'D': // 下 newHead.y += UNIT_SIZE; break; case 'L': // 左 newHead.x -= UNIT_SIZE; break; case 'R': // 右 newHead.x += UNIT_SIZE; break; } // 检查碰撞 if (checkCollision(newHead)) { running = false; timer.stop(); return; } // 添加新的蛇头 snakeBody.addFirst(newHead); // 检查是否吃到食物 if (newHead.equals(food)) { score += 10; generateFood(); } else { // 如果没有吃到食物,移除蛇尾 snakeBody.removeLast(); } lastDirection = direction; } /** * 检查碰撞 */ private boolean checkCollision(Point head) { // 检查墙壁碰撞 if (head.x < 0 || head.x >= WIDTH || head.y < 0 || head.y >= HEIGHT) { return true; } // 检查自身碰撞(从第二个节点开始检查,避免与头部比较) for (int i = 1; i < snakeBody.size(); i++) { if (head.equals(snakeBody.get(i))) { return true; } } return false; } /** * 绘制游戏界面 */ @Override protected void paintComponent(Graphics g) { super.paintComponent(g); draw(g); } /** * 绘制游戏元素 */ private void draw(Graphics g) { if (running) { // 绘制网格(可选) drawGrid(g); // 绘制食物 g.setColor(Color.RED); g.fillOval(food.x, food.y, UNIT_SIZE, UNIT_SIZE); // 绘制蛇 for (int i = 0; i < snakeBody.size(); i++) { Point point = snakeBody.get(i); if (i == 0) { // 蛇头 g.setColor(Color.GREEN); } else { // 蛇身 g.setColor(new Color(45, 180, 0)); } g.fillRect(point.x, point.y, UNIT_SIZE, UNIT_SIZE); // 蛇身边框 g.setColor(Color.BLACK); g.drawRect(point.x, point.y, UNIT_SIZE, UNIT_SIZE); } // 绘制分数 drawScore(g); // 如果游戏暂停,显示暂停信息 if (paused) { drawPauseMessage(g); } } else { // 游戏结束画面 gameOver(g); } } /** * 绘制网格 */ private void drawGrid(Graphics g) { g.setColor(Color.DARK_GRAY); for (int i = 0; i < WIDTH / UNIT_SIZE; i++) { g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, HEIGHT); g.drawLine(0, i * UNIT_SIZE, WIDTH, i * UNIT_SIZE); } } /** * 绘制分数 */ private void drawScore(Graphics g) { g.setColor(Color.WHITE); g.setFont(new Font("Arial", Font.BOLD, 20)); g.drawString("得分: " + score, 10, 25); } /** * 绘制暂停信息 */ private void drawPauseMessage(Graphics g) { g.setColor(Color.YELLOW); g.setFont(new Font("Arial", Font.BOLD, 40)); String message = "游戏暂停"; FontMetrics metrics = getFontMetrics(g.getFont()); g.drawString(message, (WIDTH - metrics.stringWidth(message)) / 2, HEIGHT / 2); g.setFont(new Font("Arial", Font.PLAIN, 20)); String subMessage = "按空格键继续"; metrics = getFontMetrics(g.getFont()); g.drawString(subMessage, (WIDTH - metrics.stringWidth(subMessage)) / 2, HEIGHT / 2 + 40); } /** * 游戏结束画面 */ private void gameOver(Graphics g) { // 游戏结束文字 g.setColor(Color.RED); g.setFont(new Font("Arial", Font.BOLD, 50)); String message = "游戏结束"; FontMetrics metrics = getFontMetrics(g.getFont()); g.drawString(message, (WIDTH - metrics.stringWidth(message)) / 2, HEIGHT / 2 - 50); // 显示最终分数 g.setColor(Color.WHITE); g.setFont(new Font("Arial", Font.BOLD, 30)); String scoreMessage = "最终得分: " + score; metrics = getFontMetrics(g.getFont()); g.drawString(scoreMessage, (WIDTH - metrics.stringWidth(scoreMessage)) / 2, HEIGHT / 2); // 重新开始提示 g.setFont(new Font("Arial", Font.PLAIN, 20)); String restartMessage = "按 R 键重新开始游戏"; metrics = getFontMetrics(g.getFont()); g.drawString(restartMessage, (WIDTH - metrics.stringWidth(restartMessage)) / 2, HEIGHT / 2 + 50); } /** * 定时器事件处理 */ @Override public void actionPerformed(ActionEvent e) { if (running) { move(); repaint(); } } /** * 键盘按下事件处理 */ @Override public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_LEFT: if (lastDirection != 'R') direction = 'L'; break; case KeyEvent.VK_RIGHT: if (lastDirection != 'L') direction = 'R'; break; case KeyEvent.VK_UP: if (lastDirection != 'D') direction = 'U'; break; case KeyEvent.VK_DOWN: if (lastDirection != 'U') direction = 'D'; break; case KeyEvent.VK_SPACE: // 空格键暂停/继续游戏 if (running) { paused = !paused; repaint(); } break; case KeyEvent.VK_R: // R键重新开始游戏 if (!running) { initGame(); startGame(); } break; } } // 其他键盘事件方法(必须实现) @Override public void keyTyped(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) {} }游戏功能特性说明
核心游戏机制
| 功能模块 | 实现方式 | 技术要点 |
|---|---|---|
| 蛇移动 | 使用 LinkedList 存储坐标,定时更新 | 方向控制、防反向移动 |
| 食物生成 | 随机坐标生成,避免与蛇身重叠 | Random 类使用、碰撞检测 |
| 碰撞检测 | 边界检测 + 自身碰撞检测 | 坐标比较算法 |
| 分数系统 | 吃到食物加分 | 简单的累加计分 |
| 游戏状态 | 运行/暂停/结束状态管理 | 布尔标志位控制 |
游戏操作说明
// 键盘控制映射表 方向键控制:↑↓←→ 控制蛇的移动方向 空格键:暂停/继续游戏 R 键:游戏结束后重新开始技术实现亮点
- 图形界面:使用 Swing 的 JPanel 和 Graphics 进行图形绘制
- 事件处理:通过 KeyListener 实现键盘控制
- 定时更新:使用 Timer 实现游戏循环
- 数据结构:LinkedList 高效管理蛇身坐标
- 碰撞检测:精确的边界和自身碰撞判断
运行说明
要运行这个贪吃蛇游戏,您需要:
- 将上述两个类文件保存为
SnakeGame.java和GamePanel.java - 使用 Java 编译器编译:
javac *.java - 运行主程序:
java SnakeGame
这个实现包含了贪吃蛇游戏的所有核心功能,代码结构清晰,注释详细,适合学习和进一步扩展 。您可以根据需要调整游戏速度、界面大小或添加更多功能如关卡系统、特殊食物等。
参考来源
- Java实现贪吃蛇大作战小游戏(完整版)
- Java实现贪吃蛇小游戏
- JavaSE项目 | 纯Java实现贪吃蛇小游戏
- Java实现贪吃蛇游戏
- Java贪吃蛇全代码