在这篇文章中,我将带你一步步实现一个经典的贪吃蛇小游戏。我们将使用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) {}
}
这个类是游戏的核心部分,它处理了游戏的主要逻辑:
- 游戏面板的初始化和设置
- 游戏循环的控制(通过Timer实现)
- 游戏元素的绘制(蛇、食物和分数)
- 蛇的移动和方向控制
- 食物的生成和检测
- 碰撞检测(包括边界和自身)
- 游戏结束的处理
第三步:改进游戏结构(可选)
上面的实现已经可以运行一个简单的贪吃蛇游戏了,但代码结构还可以进一步优化。我们可以将蛇和食物单独封装成类,使代码更加模块化。
以下是优化后的代码结构:
// 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;
}
}
如何运行游戏
- 将上面的代码复制到四个Java文件中:
SnakeGame.java,GamePanel.java,Snake.java, 和Food.java - 确保所有文件在同一个目录下
- 使用Java编译器编译这些文件:
javac SnakeGame.java - 运行编译后的程序:
java SnakeGame
游戏操作说明
- 使用方向键(上、下、左、右)控制蛇的移动方向
- 吃到红色的食物会增加分数并让蛇变长
- 如果蛇撞到边界或自己的身体,游戏结束
- 游戏结束后按空格键可以重新开始
游戏改进建议
- 添加难度级别:随着分数增加,蛇的移动速度加快
- 添加不同类型的食物:有些食物提供额外分数,有些食物让蛇加速或减速
- 添加音效:吃到食物、游戏结束等事件添加音效
- 实现高分榜:记录最高分并显示在游戏界面
希望这篇文章能帮助你理解如何使用Java制作一个简单的贪吃蛇游戏!如果你有任何问题或建议,欢迎留言讨论。