今天来具体说说我的课设项目,是使用swing完成的贪吃蛇大作战,在这个项目中遇到了一些困难,最终全部解决。

首先我们要定义一个蛇类,用来绘出蛇的形状和基本的逻辑处理

public class Snake {
private LinkedList<Point> snakeBody;// 蛇身
private Point snakeTail;// 蛇尾
private final Sound sound = new Sound();// 音效
// 方向
final int UP = -1;
final int DOWN = 1;
final int LEFT = -2;
final int RIGHT = 2;
private boolean life;// 生命标记
private int oldDirection;// 原始方向
private int newDirection;// 新方向(按键后的方向)
private Color color;// 蛇身颜色
public Snake() {
init();
}
// 初始化
public void init() {
snakeBody = new LinkedList<>();
snakeTail = new Point();
life = true;
oldDirection = newDirection = RIGHT;
color = Color.YELLOW;
snakeBody.add(new Point(4, 5));
snakeBody.add(new Point(5, 5));
snakeBody.add(new Point(6, 5));
}
// 改变方向
public void changeDeriction(int d) {
newDirection = d;
}
// 蛇移动
public void snakeMove() {
if ((oldDirection + newDirection) != 0) {// 判断是否反方向
oldDirection = newDirection;
}
snakeTail = snakeBody.removeLast();// 蛇尾
int x = snakeBody.getFirst().x;
int y = snakeBody.getFirst().y;
switch (oldDirection) {// 移动方向
case UP:
y--;
isDied();
break;
case DOWN:
y++;
isDied();
break;
case LEFT:
x--;
isDied();
break;
case RIGHT:
x++;
isDied();
break;
}
snakeBody.addFirst(new Point(x, y));
}
// 吃食物
public void eatFood() {
snakeBody.addLast(snakeTail);
}
// 判断蛇是否吃到食物
public boolean isEatFood(Food food) {
if (snakeBody.getFirst().equals(food.getFood())) {
try {
sound.playEatileSound();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
e.printStackTrace();
}
return true;
}
return false;
}
// 判断蛇是否吃到身体
public boolean isEatBody() {
for (int i = 1; i < snakeBody.size(); i++) {
if (snakeBody.get(i).equals(snakeBody.getFirst())) {
return true;
}
}
return false;
}
// 判断是否碰到墙壁
public boolean isMeetWall() {
if (snakeBody.getFirst().x < 0 || snakeBody.getFirst().x > SizeConstants.WIDTH - 1 || snakeBody.getFirst().y < 0
|| snakeBody.getFirst().y > SizeConstants.HEIGHT - 1) {
try {
sound.playMissileSound();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
e.printStackTrace();
}
return true;
}
return false;
}
// 判断是否碰到齿轮
public boolean isMeetGear(Gear gear) {
if (snakeBody.getFirst().x >=gear.getX() &&snakeBody.getFirst().x <=gear.getX()+3&& snakeBody.getFirst().y<= gear.getY()+3&&snakeBody.getFirst().y>=gear.getY()) {
try {
sound.playMissileSound();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
e.printStackTrace();
}
return true;
}
return false;
}
// 画蛇身
public void drawSnake(Graphics g) {
g.setColor(color);
for (Point p : snakeBody) {
g.fill3DRect(p.x * SizeConstants.SIZE, p.y * SizeConstants.SIZE, SizeConstants.SIZE, SizeConstants.SIZE, true);
}
}
// 重新开始
public void againStart() {
snakeBody.clear();
init();
}
// 判断蛇是否死亡
public void isDied() {
if (isEatBody() || isMeetWall()) {
life = false;
}
}
public LinkedList<Point> getSnakeBody() {
return snakeBody;
}
public boolean getLife() {
return life;
}
public void setLife(boolean life) {
this.life = life;
}
public void setColor(Color color) {
this.color = color;
}
}
接下来我们要定义一个食物类:
public class Food {
private Point food;// 食物坐标
private Random rand;// 随机数
private Color color = Color.CYAN;// 食物颜色
public Food() {
rand = new Random();
food = new Point();// 初始化食物坐标
changeColor();// 随机颜色
food.setLocation(randomPoint());// 随机坐标
}
// 产生一个食物
public void createFood(Snake snake) {
Point temPoint = randomPoint();// 随机坐标,tempPoint为食物坐标
for (Point p : snake.getSnakeBody()) {// 判断食物是否与蛇重叠
if (p.equals(temPoint)) {
temPoint = randomPoint();// 重叠后重新产生坐标
}
}
food.setLocation(temPoint);// 设置食物坐标
}
// 画出食物
public void drawFood(Graphics g) {
g.setColor(color);// 设置颜色
g.fill3DRect(food.x * SizeConstants.SIZE, food.y * SizeConstants.SIZE, SizeConstants.SIZE, SizeConstants.SIZE,
true);
}
// 得到食物位置
public Point getFood() {
return food;
}
// 改变颜色
public void changeColor() {
color = randomColor();
}
public Color getColor() {
return color;
}
// 随机坐标
private Point randomPoint() {
int x = rand.nextInt(SizeConstants.WIDTH - 1) + 1;
int y = rand.nextInt(SizeConstants.HEIGHT - 1) + 1;
return new Point(x, y);
}
// 随机颜色
private Color randomColor() {
int r = rand.nextInt(255);
int g = rand.nextInt(255);
int b = rand.nextInt(235);
return new Color(r, g, b);
}
}
这里定义了食物的基本信息,包括食物的产生,状态,位置,颜色等
本来到此javabean就结束了,但是我总感觉太单调。内容不够丰富,于是我又加上了一个挑战模式(齿轮),下面是齿轮的javabean
public class Gear {
private int x;
private int y;
private int width;
private int height;
private int speed;
private int direction; // 方向:0 - 静止,1 - 向右,-1 - 向左
private int type;
public Gear(int x, int y, int width, int height, int speed, int direction, int type) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.speed = speed;
this.direction = direction;
this.type = type;
}
public Gear() {
randomGear();
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public int getDirection() {
return direction;
}
public void setDirection(int direction) {
this.direction = direction;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
// 随机位置生成齿轮
public void randomGear() {
this.x = (int)((Math.random() * SizeConstants.WIDTH / 3) + (Math.random() * SizeConstants.WIDTH / 3));
this.y = (int)((Math.random() * SizeConstants.HEIGHT / 3) + (Math.random() * SizeConstants.HEIGHT / 3));
this.width = SizeConstants.SIZE;
this.height = SizeConstants.SIZE;
this.speed = 1; // 将齿轮移动速度设置为较小值,例如1像素
this.direction = (Math.random() > 0.5) ? 1 : -1; // 随机方向
this.type = (int)(Math.random() * 2); // 随机类型
}
public void move() {
if (direction == 1) {
x += speed;
if (x >= SizeConstants.WIDTH) {
x = 0; // 回到左边
}
} else if (direction == -1) {
x -= speed;
if (x < 0) {
x = SizeConstants.WIDTH; // 回到右边
}
}
}
}

三个javabean到此结束,接下来绘制地图

public final class SizeConstants {
public static final int SIZE = 15;
public static final int WIDTH = 35;
public static final int HEIGHT = 35 ;
private SizeConstants() {
}
}
import javax.swing.*;
import java.awt.*;
public class Game extends JFrame {
private static final Image bgImage = Toolkit.getDefaultToolkit().getImage("src/images/贪吃蛇.jpg");//加载背景图片
private static final int WIDTH = 800;//
private static final int HEIGHT = 450;
private static final int MENU_X_START = 337;
private static final int MENU_X_END = 460;
private static final int START_Y_START = 262;
private static final int START_Y_END = 299;
private static final int ABOUT_Y_START = 323;
private static final int ABOUT_Y_END = 362;
private static final int EXIT_Y_START = 388;
private static final int EXIT_Y_END = 425;
private static final int MUSIC_X_START = 8;
private static final int MUSIC_X_END = 68;
private static final int MUSIC_Y_START = 387;
private static final int MUSIC_Y_END = 437;
private final Sound sound = new Sound();
public Game() {
initGUI();
}
private void initGUI() {
setTitle("贪吃蛇");
setSize(WIDTH, HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setUndecorated(true);
setLocationRelativeTo(null);
setResizable(false);
try {
sound.playBgMusic();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
e.printStackTrace();
}
setVisible(true);
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent event) {//鼠标点击事件
handleMouseClick(event);//处理鼠标点击事件,点击开始游戏,关于,退出游戏
}
});
addMouseMotionListener(new MouseMotionAdapter() {//鼠标移动事件
@Override
public void mouseMoved(MouseEvent event) {
handleMouseMove(event);
}
});
}
private void handleMouseClick(MouseEvent event) {
int x = event.getX();
int y = event.getY();
if (isWithinBounds(x, y, MENU_X_START, MENU_X_END, START_Y_START, START_Y_END)) {
dispose();
new GameFrame();
} else if (isWithinBounds(x, y, MENU_X_START, MENU_X_END, ABOUT_Y_START, ABOUT_Y_END)) {
new AboutDialog();
} else if (isWithinBounds(x, y, MENU_X_START, MENU_X_END, EXIT_Y_START, EXIT_Y_END)) {
int num = JOptionPane.showConfirmDialog(this, "确认退出游戏吗", "退出提示", JOptionPane.CANCEL_OPTION);
if (num == 0) {
System.exit(0);
}
} else if (isWithinBounds(x, y, MUSIC_X_START, MUSIC_X_END, MUSIC_Y_START, MUSIC_Y_END)) {
toggleMusic();
}
}
private void handleMouseMove(MouseEvent event) {
int x = event.getX();
int y = event.getY();
if (isWithinBounds(x, y, MENU_X_START, MENU_X_END, START_Y_START, START_Y_END) ||
isWithinBounds(x, y, MENU_X_START, MENU_X_END, ABOUT_Y_START, ABOUT_Y_END) ||
isWithinBounds(x, y, MENU_X_START, MENU_X_END, EXIT_Y_START, EXIT_Y_END) ||
isWithinBounds(x, y, MUSIC_X_START, MUSIC_X_END, MUSIC_Y_START, MUSIC_Y_END)) {
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
setCursor(Cursor.getDefaultCursor());
}
}
private boolean isWithinBounds(int x, int y, int xStart, int xEnd, int yStart, int yEnd) {
return x >= xStart && x <= xEnd && y >= yStart && y <= yEnd;
}
private void toggleMusic() {
if (sound.getBgSoundClip() != null) {
sound.stop();
} else {
try {
sound.playBgMusic();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
e.printStackTrace();
}
}
}
@Override
public void paint(Graphics g) {
g.drawImage(bgImage, 0, 0, this);
}
public static void main(String[] args) {
new Game();
}

下面是业务逻辑代码

import javax.swing.*;
import java.awt.*;
public class GameFrame extends JFrame {
// 游戏区域的宽度和高度
private static final int GAME_WIDTH = 535;
private static final int GAME_HEIGHT = 565;
private GamePanel gPanel; // 游戏面板
private JMenuBar jBar; // 菜单栏
private JMenuItem[] jItems; // 菜单项
private JLabel scoreLabel; // 用于显示得分的标签
private boolean isTwoPlayerMode = false; // 双人模式标志
private boolean isChallengeMode = false; // 挑战模式标志
private Gear gear; // 齿轮
public GameFrame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setSize(GAME_WIDTH, GAME_HEIGHT);
setLayout(null);
setLocationRelativeTo(null); // 窗口居中显示
setUndecorated(true); // 去掉窗口的边框
jBar = new JMenuBar(); // 创建菜单栏
JMenu difficultyMenu = new JMenu("难度"); // 创建难度菜单
JMenu modeMenu = new JMenu("模式"); // 创建模式菜单
jItems = new JMenuItem[9]; // 创建菜单项数组
jItems[0] = new JMenuItem("重新开始");
jItems[0].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)); // 设置快捷键
jItems[1] = new JMenuItem("暂停/开始");
jItems[1].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)); // 设置快捷键
jItems[2] = new JRadioButtonMenuItem("低");
jItems[3] = new JRadioButtonMenuItem("中");
jItems[4] = new JRadioButtonMenuItem("高");
jItems[5] = new JMenuItem("退出");
jItems[5].setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0));
jItems[6] = new JRadioButtonMenuItem("单人模式");
jItems[7] = new JRadioButtonMenuItem("双人模式");
jItems[8] = new JMenuItem("挑战");
// 设置菜单项的首选大小和最大大小
jItems[0].setPreferredSize(new Dimension(215, 40)); // 开始
jItems[1].setPreferredSize(new Dimension(215, 40)); // 暂停/开始
jItems[2].setPreferredSize(new Dimension(75, 40)); // 低
jItems[3].setPreferredSize(new Dimension(75, 40)); // 中
jItems[4].setPreferredSize(new Dimension(75, 40)); // 高
jItems[5].setPreferredSize(new Dimension(160, 40)); // 退出
jItems[6].setPreferredSize(new Dimension(160, 40)); // 单人模式
jItems[7].setPreferredSize(new Dimension(160, 40)); // 双人模式
jItems[8].setPreferredSize(new Dimension(110, 40)); // 挑战
// 默认选中“低”菜单项
jItems[2].setSelected(true);
// 默认选中“单人模式”菜单项
jItems[6].setSelected(true);
// 创建并添加难度菜单项
ButtonGroup difficultyGroup = new ButtonGroup();
difficultyGroup.add(jItems[2]);
difficultyGroup.add(jItems[3]);
difficultyGroup.add(jItems[4]);
difficultyMenu.add(jItems[2]);
difficultyMenu.add(jItems[3]);
difficultyMenu.add(jItems[4]);
// 创建并添加模式菜单项
ButtonGroup modeGroup = new ButtonGroup(); // 创建模式按钮组
modeGroup.add(jItems[6]);
modeGroup.add(jItems[7]);
modeMenu.add(jItems[6]);
modeMenu.add(jItems[7]);
jBar.add(jItems[0]); // jItems[0]是开始游戏的菜单项
jBar.add(jItems[1]); // jItems[1]是暂停/开始游戏的菜单项
jBar.add(difficultyMenu);
jBar.add(modeMenu); // 添加模式菜单
jBar.add(jItems[8]); // 添加挑战菜单项
jBar.add(jItems[5]); // jItems[5]是退出游戏的菜单项
for (int i = 0; i < jItems.length; i++) {
jItems[i].addActionListener(new MyAction()); // 为所有菜单项添加事件监听器,处理菜单项的单击事件
}
// 创建并添加用于显示得分的标签
scoreLabel = new JLabel("得分: 0"); // 创建得分标签
scoreLabel.setHorizontalAlignment(SwingConstants.RIGHT); // 设置标签中的文本右对齐
jBar.add(Box.createHorizontalGlue()); // 添加弹性空间以将得分标签推到右侧
jBar.add(scoreLabel); // 添加得分标签
setJMenuBar(jBar); // 设置菜单栏
gPanel = new GamePanel(this);
gPanel.setBounds(0, 0, GAME_WIDTH, GAME_HEIGHT); // 设置游戏面板的位置和大小
add(gPanel);
addWindowListener(new WindowAdapter() { // 为窗口添加窗口事件监听器
@Override
public void windowClosing(WindowEvent e) {
// 弹出对话框,询问用户是否退出游戏
int result = JOptionPane.showConfirmDialog(null, "是否退出游戏?", "退出游戏", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
System.exit(0);
}
}
});
setVisible(true);
gPanel.requestFocus();
showScore();
}
private void showScore() {
Timer timer = new Timer(100, e -> {
scoreLabel.setText("得分: " + gPanel.getScore() + " 长度: " + gPanel.getLength() + " 速度: " + (300 - gPanel.getSpeed()));
});
timer.start();
}
private class MyAction implements ActionListener { // 菜单项的事件监听器
@Override
public void actionPerformed(ActionEvent e) { // 处理菜单项的单击事件
String s = e.getActionCommand(); // 获取事件源的名称
switch (s) {
case "重新开始":
gPanel.againStart();
break;
case "暂停/开始":
gPanel.stop();
break;
case "低":
gPanel.setSpeed(200);
break;
case "中":
gPanel.setSpeed(150);
break;
case "高":
gPanel.setSpeed(100);
break;
case "挑战":
//暂停
gPanel.superStop();
//先判断是否已经是挑战模式,如果是,询问是否退出挑战模式
if (isChallengeMode) {
int result = JOptionPane.showConfirmDialog(null, "是否退出挑战模式?", "退出挑战", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
isChallengeMode = false;
gPanel.setSpeed(200);
gear=null;
//重新开始
gPanel.againStart();
// gPanel.stop();
}
break;
}
int result = JOptionPane.showConfirmDialog(null, "是否挑战?", "挑战", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION) {
isChallengeMode = true;
gPanel.setSpeed(100);
gPanel.stop();
}
// isChallengeMode = true;
// gPanel.setSpeed(110);
break;
case "退出":
//暂停
gPanel.superStop();
// 弹出对话框,询问用户是否退出游戏
result = JOptionPane.showConfirmDialog(null, "是否退出游戏?", "退出游戏", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.YES_OPTION)
System.exit(0);
else {
//继续
gPanel.stop();
}
break;
case "单人模式":
isTwoPlayerMode = false; // 设置为单人模式
break;
case "双人模式":
isTwoPlayerMode = true; // 设置为双人模式
break;
default:
break;
}
}
}
public boolean isTwoPlayerMode() {
return isTwoPlayerMode;
}
public boolean isChallengeMode() {
return isChallengeMode;
}
}

这里完成了游戏的基本逻辑,下面是数据访问(也就是细节实现):

import java.awt.*;
import javax.swing.*;
public class GamePanel extends JPanel {
private static final long serialVersionUID = 1L;
private Snake snake;
private Food food;
private Gear gear;
private Timer timer;
private int score; // 分数
private int length = 3; // 蛇身长度
private int speed; // 速度
private GameFrame gameFrame; // 引用 GameFrame 实例
private int gearMoveCounter = 0; // 齿轮移动计数器
public GamePanel(GameFrame gameFrame) {
this.gameFrame = gameFrame;
snake = new Snake();
food = new Food();
speed = 200;
timer = new Timer(speed, new SnakeRunListener()); // 设置定时器,控制蛇移动,速度,吃食物,碰撞检测
setSize(SizeConstants.WIDTH * SizeConstants.SIZE, SizeConstants.HEIGHT * SizeConstants.SIZE); // 设置面板大小
addKeyListener(new KeyControl()); // 添加键盘监听,控制蛇移动
}
// 开始游戏
public void startGame() {
score = 0;
length = snake.getSnakeBody().size();
if (gameFrame.isChallengeMode()) {
gear = new Gear(); // 仅在挑战模式下初始化齿轮
gear.randomGear(); // 随机生成齿轮
} else {
gear = null; // 非挑战模式下齿轮为空
}
timer.start(); // 启动定时器,蛇开始移动
}
// 暂停
public void stop() {
if (timer.isRunning()) { // 判断是否在运行,如果isRunning为true,则暂停
timer.stop(); // 暂停
} else {
timer.start();
}
}
public void superStop() {
timer.stop();
}
// 重新开始
public void againStart() {
setSpeed(200);
repaint();
snake.againStart();
startGame();
}
// 当吃到食物后产生新食物
public void eatFood() {
if (snake.isEatFood(food)) {
addSpeed();
timer.setDelay(speed);
countScore();
countLength();
snake.eatFood();
snake.setColor(food.getColor());
food.changeColor();
food.createFood(snake);
}
}
// 游戏结束后的选择
public void gameEnd() {
if (!snake.getLife()) {
int option = JOptionPane.showConfirmDialog(null, "是否继续?", "游戏已结束", JOptionPane.YES_NO_OPTION);
if (option == JOptionPane.YES_OPTION) {
setSpeed(200);
timer.setDelay(speed);
againStart();
} else {
System.exit(0);
}
}
}
// 速度增长比例
public void addSpeed() {
// 判断延迟是否大于25
if (speed > 25) {
speed = speed - 5;
}
}
// 分数计算
public void countScore() {
score = score + 2 * (length - 2);
}
// 长度计算
public void countLength() {
length++;
}
public int getScore() {
return score;
}
public int getLength() {
return length;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g); //双缓冲技术,防止闪烁
for (int x = 0; x < SizeConstants.WIDTH; x++) {
for (int y = 0; y < SizeConstants.HEIGHT; y++) {
// 设置单元格填充颜色为白色
g.setColor(new Color(242, 242, 242));
// 绘制单元格
g.fillRect(x * SizeConstants.SIZE, y * SizeConstants.SIZE, SizeConstants.SIZE, SizeConstants.SIZE);
// 设置边框颜色为灰白色
g.setColor(Color.white);
// 绘制单元格边框
g.drawRect(x * SizeConstants.SIZE, y * SizeConstants.SIZE, SizeConstants.SIZE, SizeConstants.SIZE);
}
}
// 如果是挑战模式,绘制齿轮
if (gameFrame.isChallengeMode() && gear != null) {
g.drawImage(new ImageIcon("src/images/齿轮.jpg").getImage(), gear.getX() * SizeConstants.SIZE, gear.getY() * SizeConstants.SIZE, this);
}
// 绘制蛇和食物
snake.drawSnake(g);
food.drawFood(g);
eatFood();
}
private class SnakeRunListener implements ActionListener { // 定时器监听,控制蛇移动
@Override
public void actionPerformed(ActionEvent e) {
if (snake.getLife()) { // 判断蛇是否存活
snake.snakeMove();
if (gear != null) {
gearMoveCounter++;
if (gearMoveCounter >= 5) { // 每5次移动一次齿轮
gear.move(); // 更新齿轮位置
gearMoveCounter = 0;
}
if (snake.isMeetGear(gear)) { // 判断是否碰到齿轮
System.out.println("碰到齿轮");
snake.setLife(false); // 结束游戏
}
}
gameEnd();
repaint();
}
}
}
private class KeyControl extends KeyAdapter { // 键盘监听
@Override
public void keyPressed(KeyEvent e) { // 键盘按下事件
int key = e.getKeyCode(); // 获取按下的键值
if (gameFrame.isTwoPlayerMode()) {
switch (key) {
case KeyEvent.VK_UP:
snake.changeDeriction(snake.UP);
break;
case KeyEvent.VK_DOWN:
snake.changeDeriction(snake.DOWN);
break;
// 'a'键
case KeyEvent.VK_A:
snake.changeDeriction(snake.LEFT);
break;
// 'd'键
case KeyEvent.VK_D:
snake.changeDeriction(snake.RIGHT);
break;
}
} else {
switch (key) {
// 加上‘w','a','s','d'键控制
case KeyEvent.VK_UP:
case KeyEvent.VK_W:
snake.changeDeriction(snake.UP);
break;
case KeyEvent.VK_DOWN:
case KeyEvent.VK_S:
snake.changeDeriction(snake.DOWN);
break;
case KeyEvent.VK_LEFT:
case KeyEvent.VK_A:
snake.changeDeriction(snake.LEFT);
break;
case KeyEvent.VK_RIGHT:
case KeyEvent.VK_D:
snake.changeDeriction(snake.RIGHT);
break;
}
}
}
}
}
到此,游戏的所有逻辑已经完成,下面我们加上声音和游戏开始界面
声音相关代码:
import java.io.File;
/**
* 音乐播放器类
*/
public class Sound {
private static File bgSoundFile; // 背景音乐文件
private static File missileSoundFile; // 撞击音效文件
private Clip missileSoundClip; // 撞击音效播放器
private Clip bgSoundClip; // 背景音乐播放器
private static File eatileSoundFile; // 吃食物音效文件
private Clip eatileSoundClip; // 吃食物音效播放器
// 加载声音文件
static {
// 指定音频文件路径
bgSoundFile = new File("src/audio/贪吃蛇.wav");
// 指定音频文件路径
missileSoundFile = new File("src/audio/PenZ.wav");
// 指定音频文件路径
eatileSoundFile = new File("src/audio/Eat.wav");
}
public Clip getBgSoundClip() {
return this.bgSoundClip;
}
/**
* 获得背景音乐播放器对象
*
* @return
* @throws UnsupportedAudioFileException
* @throws IOException
* @throws LineUnavailableException
*/
public void playBgMusic() throws UnsupportedAudioFileException, IOException, LineUnavailableException {
// 获取音频输入流
AudioInputStream bgSoundStream = AudioSystem.getAudioInputStream(bgSoundFile);
// 获取Clip对象
this.bgSoundClip = AudioSystem.getClip();
// 开发音乐流
this.bgSoundClip.open(bgSoundStream);
// 开始播放音乐
this.bgSoundClip.start();
// 循环播放
this.bgSoundClip.loop(-1);
}
/**
* 播放撞击音效
*
* @return
*/
public void playMissileSound() throws UnsupportedAudioFileException, IOException, LineUnavailableException {
// 获取音频输入流
AudioInputStream missileSoundStream = AudioSystem.getAudioInputStream(missileSoundFile);
// 获取Clip对象
this.missileSoundClip = AudioSystem.getClip();
// 开发音乐流
this.missileSoundClip.open(missileSoundStream);
// 开始播放音乐
this.missileSoundClip.start();
}
/**
* 播放吃食物音效
*
* @return
*/
public void playEatileSound() throws UnsupportedAudioFileException, IOException, LineUnavailableException {
// 获取音频输入流
AudioInputStream eatileSoundStream = AudioSystem.getAudioInputStream(eatileSoundFile);
// 获取Clip对象
this.eatileSoundClip = AudioSystem.getClip();
// 开发音乐流
this.eatileSoundClip.open(eatileSoundStream);
// 开始播放音效
this.eatileSoundClip.start();
}
/**
* 停止背景音乐播放
*/
public void stop() {
if (this.bgSoundClip != null) {
this.bgSoundClip.stop();
this.bgSoundClip = null;
}
}
/**
* 停止吃食物音效播放
*/
public void stopEatileSound() {
if (this.eatileSoundClip != null) {
this.eatileSoundClip.stop();
this.eatileSoundClip = null;
}
}
}
上面就是所有的相关代码,以下是源代码地址: