使用Java制作贪吃蛇小游戏

发布于:2025-05-26 ⋅ 阅读:(254) ⋅ 点赞:(0)

在这篇文章中,我将带你一步步实现一个经典的贪吃蛇小游戏。我们将使用Java语言和Swing库来构建这个游戏,它包含了贪吃蛇游戏的基本功能:蛇的移动、吃食物、计分以及游戏结束判定。

游戏设计思路

贪吃蛇游戏的基本原理是:玩家控制一条蛇在屏幕上移动,蛇会吃随机出现的食物,每吃一次食物蛇就会变长一节,同时玩家得分增加。如果蛇撞到墙壁或自己的身体,游戏就结束。

我们将使用面向对象的方法设计这个游戏,主要包含以下几个类:

  • SnakeGame:游戏主类,负责初始化游戏窗口和游戏循环
  • GamePanel:游戏面板类,继承自JPanel,负责绘制游戏界面和处理游戏逻辑
  • Snake:蛇类,管理蛇的位置、移动和状态
  • Food:食物类,管理食物的位置和生成

下面让我们开始实现这个游戏吧!

第一步:创建游戏主类

首先,我们需要创建一个主类来启动游戏。这个类将设置游戏窗口并启动游戏循环。

import javax.swing.JFrame;

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();
    }
}

这个类很简单,它创建了一个JFrame窗口,并将游戏面板添加到窗口中。然后设置窗口的基本属性,最后调用游戏面板的startGame()方法来启动游戏。

第二步:创建游戏面板类

接下来,我们创建游戏面板类,它将继承自JPanel,并实现游戏的主要逻辑和绘制功能。

import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Timer;

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 = 20;
    // 游戏区域的单元数量
    private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);
    // 游戏速度控制
    private static final int DELAY = 75;
    
    // 蛇的身体部分位置数组
    private final int[] x = new int[GAME_UNITS];
    private final int[] y = new int[GAME_UNITS];
    // 蛇的初始长度
    private int bodyParts = 6;
    // 吃掉的食物数量
    private int applesEaten;
    // 食物的位置
    private int appleX;
    private int appleY;
    // 蛇的移动方向
    private char direction = 'R'; // 初始向右移动
    private boolean running = false;
    private Timer timer;
    
    public GamePanel() {
        // 设置面板属性
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setBackground(Color.BLACK);
        setFocusable(true);
        
        // 添加键盘监听器
        addKeyListener(this);
        
        // 初始化游戏
        initGame();
    }
    
    public void initGame() {
        // 初始化蛇的位置
        for (int i = 0; i < bodyParts; i++) {
            x[i] = 100 - i * UNIT_SIZE;
            y[i] = 50;
        }
        
        // 生成第一个食物
        newApple();
        
        // 启动游戏
        running = true;
        timer = new Timer(DELAY, this);
        timer.start();
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        draw(g);
    }
    
    public void draw(Graphics g) {
        if (running) {
            // 绘制网格(可选,仅用于辅助查看)
            for (int i = 0; i < HEIGHT / UNIT_SIZE; i++) {
                g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, HEIGHT);
                g.drawLine(0, i * UNIT_SIZE, WIDTH, i * UNIT_SIZE);
            }
            
            // 绘制食物
            g.setColor(Color.RED);
            g.fillOval(appleX, appleY, UNIT_SIZE, UNIT_SIZE);
            
            // 绘制蛇
            for (int i = 0; i < bodyParts; i++) {
                if (i == 0) {
                    // 蛇头
                    g.setColor(Color.GREEN);
                } else {
                    // 蛇身
                    g.setColor(new Color(45, 180, 0));
                    // 或者使用不同颜色创建渐变效果
                    // g.setColor(new Color((int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255)));
                }
                g.fillRect(x[i], y[i], UNIT_SIZE, UNIT_SIZE);
            }
            
            // 绘制分数
            g.setColor(Color.WHITE);
            g.setFont(new Font("Ink Free", Font.BOLD, 40));
            FontMetrics metrics = getFontMetrics(g.getFont());
            g.drawString("分数: " + applesEaten, (WIDTH - metrics.stringWidth("分数: " + applesEaten)) / 2, g.getFont().getSize());
        } else {
            gameOver(g);
        }
    }
    
    public void newApple() {
        // 随机生成食物位置
        appleX = (int)(Math.random() * (WIDTH / UNIT_SIZE)) * UNIT_SIZE;
        appleY = (int)(Math.random() * (HEIGHT / UNIT_SIZE)) * UNIT_SIZE;
        
        // 确保食物不会出现在蛇身上
        for (int i = 0; i < bodyParts; i++) {
            if ((x[i] == appleX) && (y[i] == appleY)) {
                newApple();
            }
        }
    }
    
    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] = y[0] - UNIT_SIZE;
                break;
            case 'D':
                y[0] = y[0] + UNIT_SIZE;
                break;
            case 'L':
                x[0] = x[0] - UNIT_SIZE;
                break;
            case 'R':
                x[0] = x[0] + UNIT_SIZE;
                break;
        }
    }
    
    public void checkApple() {
        // 检查蛇头是否碰到食物
        if ((x[0] == appleX) && (y[0] == appleY)) {
            bodyParts++;
            applesEaten++;
            newApple();
        }
    }
    
    public void checkCollisions() {
        // 检查蛇头是否碰到自己的身体
        for (int i = bodyParts; i > 0; i--) {
            if ((x[0] == x[i]) && (y[0] == y[i])) {
                running = false;
            }
        }
        
        // 检查蛇头是否碰到左边界
        if (x[0] < 0) {
            running = false;
        }
        
        // 检查蛇头是否碰到右边界
        if (x[0] >= WIDTH) {
            running = false;
        }
        
        // 检查蛇头是否碰到上边界
        if (y[0] < 0) {
            running = false;
        }
        
        // 检查蛇头是否碰到下边界
        if (y[0] >= HEIGHT) {
            running = false;
        }
        
        // 如果游戏结束,停止计时器
        if (!running) {
            timer.stop();
        }
    }
    
    public void gameOver(Graphics g) {
        // 绘制游戏结束文本
        g.setColor(Color.RED);
        g.setFont(new Font("Ink Free", Font.BOLD, 75));
        FontMetrics metrics1 = getFontMetrics(g.getFont());
        g.drawString("游戏结束", (WIDTH - metrics1.stringWidth("游戏结束")) / 2, HEIGHT / 2 - 50);
        
        // 绘制最终分数
        g.setColor(Color.WHITE);
        g.setFont(new Font("Ink Free", Font.BOLD, 40));
        FontMetrics metrics2 = getFontMetrics(g.getFont());
        g.drawString("分数: " + applesEaten, (WIDTH - metrics2.stringWidth("分数: " + applesEaten)) / 2, HEIGHT / 2 + 50);
        
        // 绘制重新开始提示
        g.setColor(Color.WHITE);
        g.setFont(new Font("Ink Free", Font.BOLD, 20));
        FontMetrics metrics3 = getFontMetrics(g.getFont());
        g.drawString("按空格键重新开始", (WIDTH - metrics3.stringWidth("按空格键重新开始")) / 2, HEIGHT / 2 + 100);
    }
    
    public void startGame() {
        initGame();
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        if (running) {
            move();
            checkApple();
            checkCollisions();
        }
        repaint();
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        
        // 根据按键改变蛇的移动方向,但不能直接反向移动
        switch (key) {
            case KeyEvent.VK_LEFT:
                if (direction != 'R') {
                    direction = 'L';
                }
                break;
            case KeyEvent.VK_RIGHT:
                if (direction != 'L') {
                    direction = 'R';
                }
                break;
            case KeyEvent.VK_UP:
                if (direction != 'D') {
                    direction = 'U';
                }
                break;
            case KeyEvent.VK_DOWN:
                if (direction != 'U') {
                    direction = 'D';
                }
                break;
            case KeyEvent.VK_SPACE:
                if (!running) {
                    startGame();
                }
                break;
        }
    }
    
    @Override
    public void keyReleased(KeyEvent e) {}
    
    @Override
    public void keyTyped(KeyEvent e) {}
}

这个类是游戏的核心部分,它处理了游戏的主要逻辑:

  1. 游戏面板的初始化和设置
  2. 游戏循环的控制(通过Timer实现)
  3. 游戏元素的绘制(蛇、食物和分数)
  4. 蛇的移动和方向控制
  5. 食物的生成和检测
  6. 碰撞检测(包括边界和自身)
  7. 游戏结束的处理

第三步:改进游戏结构(可选)

上面的实现已经可以运行一个简单的贪吃蛇游戏了,但代码结构还可以进一步优化。我们可以将蛇和食物单独封装成类,使代码更加模块化。

以下是优化后的代码结构:

// Snake.java
public class Snake {
    private int[] x;
    private int[] y;
    private int bodyParts;
    private char direction;
    
    public Snake() {
        x = new int[GamePanel.GAME_UNITS];
        y = new int[GamePanel.GAME_UNITS];
        bodyParts = 6;
        direction = 'R';
        
        // 初始化蛇的位置
        for (int i = 0; i < bodyParts; i++) {
            x[i] = 100 - i * GamePanel.UNIT_SIZE;
            y[i] = 50;
        }
    }
    
    // Getters and setters
    public int[] getX() { return x; }
    public int[] getY() { return y; }
    public int getBodyParts() { return bodyParts; }
    public char getDirection() { return direction; }
    public void setDirection(char direction) { this.direction = direction; }
    
    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] = y[0] - GamePanel.UNIT_SIZE;
                break;
            case 'D':
                y[0] = y[0] + GamePanel.UNIT_SIZE;
                break;
            case 'L':
                x[0] = x[0] - GamePanel.UNIT_SIZE;
                break;
            case 'R':
                x[0] = x[0] + GamePanel.UNIT_SIZE;
                break;
        }
    }
    
    public void grow() {
        bodyParts++;
    }
    
    public boolean checkSelfCollision() {
        // 检查蛇头是否碰到自己的身体
        for (int i = bodyParts; i > 0; i--) {
            if ((x[0] == x[i]) && (y[0] == y[i])) {
                return true;
            }
        }
        return false;
    }
    
    public boolean checkBoundaryCollision() {
        // 检查蛇头是否碰到边界
        return x[0] < 0 || x[0] >= GamePanel.WIDTH || y[0] < 0 || y[0] >= GamePanel.HEIGHT;
    }
}

// Food.java
import java.util.Random;

public class Food {
    private int x;
    private int y;
    private Random random;
    
    public Food() {
        random = new Random();
        newPosition();
    }
    
    public void newPosition() {
        // 随机生成食物位置
        x = random.nextInt(GamePanel.WIDTH / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;
        y = random.nextInt(GamePanel.HEIGHT / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;
    }
    
    // Getters
    public int getX() { return x; }
    public int getY() { return y; }
    
    public boolean isEaten(Snake snake) {
        // 检查食物是否被蛇吃掉
        return snake.getX()[0] == x && snake.getY()[0] == y;
    }
}

使用这些类重构后的GamePanel类:

// 优化后的GamePanel.java
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Timer;

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 = 20;
    private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);
    private static final int DELAY = 75;
    
    private Snake snake;
    private Food food;
    private int applesEaten;
    private boolean running = false;
    private Timer timer;
    
    public GamePanel() {
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setBackground(Color.BLACK);
        setFocusable(true);
        
        addKeyListener(this);
        initGame();
    }
    
    public void initGame() {
        snake = new Snake();
        food = new Food();
        applesEaten = 0;
        running = true;
        timer = new Timer(DELAY, this);
        timer.start();
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        draw(g);
    }
    
    public void draw(Graphics g) {
        if (running) {
            // 绘制网格
            for (int i = 0; i < HEIGHT / UNIT_SIZE; i++) {
                g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, HEIGHT);
                g.drawLine(0, i * UNIT_SIZE, WIDTH, i * UNIT_SIZE);
            }
            
            // 绘制食物
            g.setColor(Color.RED);
            g.fillOval(food.getX(), food.getY(), UNIT_SIZE, UNIT_SIZE);
            
            // 绘制蛇
            int[] snakeX = snake.getX();
            int[] snakeY = snake.getY();
            for (int i = 0; i < snake.getBodyParts(); i++) {
                if (i == 0) {
                    g.setColor(Color.GREEN);
                } else {
                    g.setColor(new Color(45, 180, 0));
                }
                g.fillRect(snakeX[i], snakeY[i], UNIT_SIZE, UNIT_SIZE);
            }
            
            // 绘制分数
            g.setColor(Color.WHITE);
            g.setFont(new Font("Ink Free", Font.BOLD, 40));
            FontMetrics metrics = getFontMetrics(g.getFont());
            g.drawString("分数: " + applesEaten, (WIDTH - metrics.stringWidth("分数: " + applesEaten)) / 2, g.getFont().getSize());
        } else {
            gameOver(g);
        }
    }
    
    public void gameOver(Graphics g) {
        // 绘制游戏结束文本
        g.setColor(Color.RED);
        g.setFont(new Font("Ink Free", Font.BOLD, 75));
        FontMetrics metrics1 = getFontMetrics(g.getFont());
        g.drawString("游戏结束", (WIDTH - metrics1.stringWidth("游戏结束")) / 2, HEIGHT / 2 - 50);
        
        // 绘制最终分数
        g.setColor(Color.WHITE);
        g.setFont(new Font("Ink Free", Font.BOLD, 40));
        FontMetrics metrics2 = getFontMetrics(g.getFont());
        g.drawString("分数: " + applesEaten, (WIDTH - metrics2.stringWidth("分数: " + applesEaten)) / 2, HEIGHT / 2 + 50);
        
        // 绘制重新开始提示
        g.setColor(Color.WHITE);
        g.setFont(new Font("Ink Free", Font.BOLD, 20));
        FontMetrics metrics3 = getFontMetrics(g.getFont());
        g.drawString("按空格键重新开始", (WIDTH - metrics3.stringWidth("按空格键重新开始")) / 2, HEIGHT / 2 + 100);
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        if (running) {
            snake.move();
            checkFood();
            checkCollisions();
        }
        repaint();
    }
    
    public void checkFood() {
        if (food.isEaten(snake)) {
            snake.grow();
            applesEaten++;
            food.newPosition();
        }
    }
    
    public void checkCollisions() {
        if (snake.checkSelfCollision() || snake.checkBoundaryCollision()) {
            running = false;
        }
        
        if (!running) {
            timer.stop();
        }
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        
        switch (key) {
            case KeyEvent.VK_LEFT:
                if (snake.getDirection() != 'R') {
                    snake.setDirection('L');
                }
                break;
            case KeyEvent.VK_RIGHT:
                if (snake.getDirection() != 'L') {
                    snake.setDirection('R');
                }
                break;
            case KeyEvent.VK_UP:
                if (snake.getDirection() != 'D') {
                    snake.setDirection('U');
                }
                break;
            case KeyEvent.VK_DOWN:
                if (snake.getDirection() != 'U') {
                    snake.setDirection('D');
                }
                break;
            case KeyEvent.VK_SPACE:
                if (!running) {
                    initGame();
                }
                break;
        }
    }
    
    @Override
    public void keyReleased(KeyEvent e) {}
    
    @Override
    public void keyTyped(KeyEvent e) {}
}

完整代码

下面是完整的贪吃蛇游戏代码,包含了所有类的实现:

// SnakeGame.java
import javax.swing.JFrame;

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();
    }
}

// GamePanel.java
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.Timer;

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 = 20;
    private static final int GAME_UNITS = (WIDTH * HEIGHT) / (UNIT_SIZE * UNIT_SIZE);
    private static final int DELAY = 75;
    
    private Snake snake;
    private Food food;
    private int applesEaten;
    private boolean running = false;
    private Timer timer;
    
    public GamePanel() {
        setPreferredSize(new Dimension(WIDTH, HEIGHT));
        setBackground(Color.BLACK);
        setFocusable(true);
        
        addKeyListener(this);
        initGame();
    }
    
    public void initGame() {
        snake = new Snake();
        food = new Food();
        applesEaten = 0;
        running = true;
        timer = new Timer(DELAY, this);
        timer.start();
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        draw(g);
    }
    
    public void draw(Graphics g) {
        if (running) {
            // 绘制网格
            for (int i = 0; i < HEIGHT / UNIT_SIZE; i++) {
                g.drawLine(i * UNIT_SIZE, 0, i * UNIT_SIZE, HEIGHT);
                g.drawLine(0, i * UNIT_SIZE, WIDTH, i * UNIT_SIZE);
            }
            
            // 绘制食物
            g.setColor(Color.RED);
            g.fillOval(food.getX(), food.getY(), UNIT_SIZE, UNIT_SIZE);
            
            // 绘制蛇
            int[] snakeX = snake.getX();
            int[] snakeY = snake.getY();
            for (int i = 0; i < snake.getBodyParts(); i++) {
                if (i == 0) {
                    g.setColor(Color.GREEN);
                } else {
                    g.setColor(new Color(45, 180, 0));
                }
                g.fillRect(snakeX[i], snakeY[i], UNIT_SIZE, UNIT_SIZE);
            }
            
            // 绘制分数
            g.setColor(Color.WHITE);
            g.setFont(new Font("Ink Free", Font.BOLD, 40));
            FontMetrics metrics = getFontMetrics(g.getFont());
            g.drawString("分数: " + applesEaten, (WIDTH - metrics.stringWidth("分数: " + applesEaten)) / 2, g.getFont().getSize());
        } else {
            gameOver(g);
        }
    }
    
    public void gameOver(Graphics g) {
        // 绘制游戏结束文本
        g.setColor(Color.RED);
        g.setFont(new Font("Ink Free", Font.BOLD, 75));
        FontMetrics metrics1 = getFontMetrics(g.getFont());
        g.drawString("游戏结束", (WIDTH - metrics1.stringWidth("游戏结束")) / 2, HEIGHT / 2 - 50);
        
        // 绘制最终分数
        g.setColor(Color.WHITE);
        g.setFont(new Font("Ink Free", Font.BOLD, 40));
        FontMetrics metrics2 = getFontMetrics(g.getFont());
        g.drawString("分数: " + applesEaten, (WIDTH - metrics2.stringWidth("分数: " + applesEaten)) / 2, HEIGHT / 2 + 50);
        
        // 绘制重新开始提示
        g.setColor(Color.WHITE);
        g.setFont(new Font("Ink Free", Font.BOLD, 20));
        FontMetrics metrics3 = getFontMetrics(g.getFont());
        g.drawString("按空格键重新开始", (WIDTH - metrics3.stringWidth("按空格键重新开始")) / 2, HEIGHT / 2 + 100);
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        if (running) {
            snake.move();
            checkFood();
            checkCollisions();
        }
        repaint();
    }
    
    public void checkFood() {
        if (food.isEaten(snake)) {
            snake.grow();
            applesEaten++;
            food.newPosition();
        }
    }
    
    public void checkCollisions() {
        if (snake.checkSelfCollision() || snake.checkBoundaryCollision()) {
            running = false;
        }
        
        if (!running) {
            timer.stop();
        }
    }
    
    public void startGame() {
        initGame();
    }
    
    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        
        switch (key) {
            case KeyEvent.VK_LEFT:
                if (snake.getDirection() != 'R') {
                    snake.setDirection('L');
                }
                break;
            case KeyEvent.VK_RIGHT:
                if (snake.getDirection() != 'L') {
                    snake.setDirection('R');
                }
                break;
            case KeyEvent.VK_UP:
                if (snake.getDirection() != 'D') {
                    snake.setDirection('U');
                }
                break;
            case KeyEvent.VK_DOWN:
                if (snake.getDirection() != 'U') {
                    snake.setDirection('D');
                }
                break;
            case KeyEvent.VK_SPACE:
                if (!running) {
                    initGame();
                }
                break;
        }
    }
    
    @Override
    public void keyReleased(KeyEvent e) {}
    
    @Override
    public void keyTyped(KeyEvent e) {}
}

// Snake.java
public class Snake {
    private int[] x;
    private int[] y;
    private int bodyParts;
    private char direction;
    
    public Snake() {
        x = new int[GamePanel.GAME_UNITS];
        y = new int[GamePanel.GAME_UNITS];
        bodyParts = 6;
        direction = 'R';
        
        // 初始化蛇的位置
        for (int i = 0; i < bodyParts; i++) {
            x[i] = 100 - i * GamePanel.UNIT_SIZE;
            y[i] = 50;
        }
    }
    
    public int[] getX() { return x; }
    public int[] getY() { return y; }
    public int getBodyParts() { return bodyParts; }
    public char getDirection() { return direction; }
    public void setDirection(char direction) { this.direction = direction; }
    
    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] = y[0] - GamePanel.UNIT_SIZE;
                break;
            case 'D':
                y[0] = y[0] + GamePanel.UNIT_SIZE;
                break;
            case 'L':
                x[0] = x[0] - GamePanel.UNIT_SIZE;
                break;
            case 'R':
                x[0] = x[0] + GamePanel.UNIT_SIZE;
                break;
        }
    }
    
    public void grow() {
        bodyParts++;
    }
    
    public boolean checkSelfCollision() {
        // 检查蛇头是否碰到自己的身体
        for (int i = bodyParts; i > 0; i--) {
            if ((x[0] == x[i]) && (y[0] == y[i])) {
                return true;
            }
        }
        return false;
    }
    
    public boolean checkBoundaryCollision() {
        // 检查蛇头是否碰到边界
        return x[0] < 0 || x[0] >= GamePanel.WIDTH || y[0] < 0 || y[0] >= GamePanel.HEIGHT;
    }
}

// Food.java
import java.util.Random;

public class Food {
    private int x;
    private int y;
    private Random random;
    
    public Food() {
        random = new Random();
        newPosition();
    }
    
    public void newPosition() {
        // 随机生成食物位置
        x = random.nextInt(GamePanel.WIDTH / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;
        y = random.nextInt(GamePanel.HEIGHT / GamePanel.UNIT_SIZE) * GamePanel.UNIT_SIZE;
    }
    
    public int getX() { return x; }
    public int getY() { return y; }
    
    public boolean isEaten(Snake snake) {
        // 检查食物是否被蛇吃掉
        return snake.getX()[0] == x && snake.getY()[0] == y;
    }
}

如何运行游戏

  1. 将上面的代码复制到四个Java文件中:SnakeGame.java, GamePanel.java, Snake.java, 和 Food.java
  2. 确保所有文件在同一个目录下
  3. 使用Java编译器编译这些文件:javac SnakeGame.java
  4. 运行编译后的程序:java SnakeGame

游戏操作说明

  • 使用方向键(上、下、左、右)控制蛇的移动方向
  • 吃到红色的食物会增加分数并让蛇变长
  • 如果蛇撞到边界或自己的身体,游戏结束
  • 游戏结束后按空格键可以重新开始

游戏改进建议

  1. 添加难度级别:随着分数增加,蛇的移动速度加快
  2. 添加不同类型的食物:有些食物提供额外分数,有些食物让蛇加速或减速
  3. 添加音效:吃到食物、游戏结束等事件添加音效
  4. 实现高分榜:记录最高分并显示在游戏界面

希望这篇文章能帮助你理解如何使用Java制作一个简单的贪吃蛇游戏!如果你有任何问题或建议,欢迎留言讨论。


微信公众号

今日签到

点亮在社区的每一天
去签到