实验二 贪吃蛇游戏开发
Posted 螃蟹在剥吾壳
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实验二 贪吃蛇游戏开发相关的知识,希望对你有一定的参考价值。
目录
一.项目要求
(1)实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子, 上下左右控制“蛇”的移动,吃到“豆子”以后“蛇”的身体加长一点。
(2)“蛇”碰到边界或蛇头与蛇身相撞,蛇死亡,游戏结束。
(3)为游戏设计友好的交互界面;例如欢迎界面,游戏界面,游戏结束界面。要有开始键、暂停键和停止退出的选项。
(4)对蛇吃到豆子进行分值计算,可以设置游戏速度,游戏音乐 等拓展元素。
二.项目平台
IDEA.Java Swing
三.项目实现过程
1.实现键盘控制:
public void keyPressed(KeyEvent e)
// 键盘按下,未释放
//获取按下的键盘是哪个键
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_SPACE) //如果按下的是空格键
if (isDie) //失败,游戏再来一遍
isDie = false;
init(); //重新初始化游戏
else //暂停游戏
isStart = !isStart;
repaint(); //刷新界面
//键盘控制走向
if (keyCode == KeyEvent.VK_LEFT) //如果按下的是空格键
fx = "L";
else if (keyCode == KeyEvent.VK_RIGHT) //如果按下的是空格键
fx = "R";
else if (keyCode == KeyEvent.VK_UP) //如果按下的是空格键
fx = "U";
else if (keyCode == KeyEvent.VK_DOWN) //如果按下的是空格键
fx = "D";
2.游戏画面及内容设置:
protected void paintComponent(Graphics g)
super.paintComponent(g); //清屏
this.setBackground(Color.BLACK);//设置背景的颜色
//绘制积分框
Data.header.paintIcon(this, g, 0, 0);
//绘制游戏区域
g.fillRect(0, 75, 1000, 625);
//画一条静态的蛇
if (fx.equals("R"))
Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
else if (fx.equals("L"))
Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
else if (fx.equals("U"))
Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
else if (fx.equals("D"))
Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
//蛇的身体长度通过length来控制
for (int i = 1; i < length; i++)
Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
//画食物
Data.food.paintIcon(this, g, foodx, foody);
//画积分
g.setColor(Color.white); //设置画笔颜色
g.setFont(new Font("微软雅黑", Font.BOLD, 18));
g.drawString("长度:" + length, 750, 35);
g.drawString("分数:" + score, 750, 55);
//游戏提示:是否开始
if (isStart == false)
//画一段文字
g.setColor(Color.white); //设置画笔颜色
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("按下空格开始游戏", 300, 300);
//失败提醒
if (isDie)
//画一段文字
g.setColor(Color.red); //设置画笔颜色
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("游戏失败,按下空格重新开始", 200, 300);
3.食物随机产生:
public void init()
length = 3;
snakeX[0] = 100;
snakeY[0] = 100; //头部坐标
snakeX[1] = 75;
snakeY[1] = 100; //第一个身体坐标
snakeX[2] = 50;
snakeY[2] = 100; //第二个身体坐标
fx = "R"; //默认蛇向右
foodx = 50 + 25 * random.nextInt(32);
foody = 125 + 75 * random.nextInt(6);
score = 0;
4.触碰墙与身体的判定:
public void actionPerformed(ActionEvent e)
//如果游戏处于开始状态,并且游戏没有结束
if (isStart && isDie == false)
//右移
for (int i = length - 1; i > 0; i--) //身体移动
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
if(fx.equals("R"))
snakeX[0] = snakeX[0] + 25; //头部移动
// 边界判断
if(snakeX[0]>925 ) isDie=true;
else if(fx.equals("L"))
snakeX[0] = snakeX[0] - 25; //头部移动
// 边界判断
if(snakeX[0]<25)isDie=true;
else if(fx.equals("U"))
snakeY[0] = snakeY[0] - 25; //头部移动
// 边界判断
if(snakeY[0]<100)isDie=true;
else if(fx.equals("D"))
snakeY[0] = snakeY[0] + 25; //头部移动
// 边界判断
if(snakeY[0]>625)isDie=true;
//如果小蛇的头和食物坐标重合
if (snakeX[0] == foodx && snakeY[0] == foody)
//长度+1
length++;
//重新生成食物
foodx = 25 + 25 * random.nextInt(32);
foody = 100 + 75 * random.nextInt(6);
score += 10;
//如果小蛇的头和小蛇的身体坐标重合,失败,(把小蛇设置为撞到身体不死)
for(int i=1;i<length;i++)
if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i])
isDie=true;
//刷新界面
repaint();
timer.start(); //让时间动起来
5.移动与身体加长:
if (snakeX[0] == foodx && snakeY[0] == foody)
//长度+1
length++;
//重新生成食物
foodx = 25 + 25 * random.nextInt(32);
foody = 100 + 75 * random.nextInt(6);
//积分+10
score += 10;
//如果小蛇的头和小蛇的身体坐标重合,失败,(把小蛇设置为撞到身体不死)
for(int i=1;i<length;i++)
if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i])
isDie=true;
//刷新界面
repaint();
6.开始加载音乐
public class Music extends Thread
private String fileName;
private final int EXTERNAL_BUFFER_SIZE = 524288;
public Music(String wavFile)
this.fileName = wavFile;
@SuppressWarnings("unused")
public void run()
File soundFile = new File(fileName); // 播放音乐的文件名
if (!soundFile.exists())
System.err.println("Wave file not found:" + fileName);
return;
while (true) // 设置循环播放
AudioInputStream audioInputStream = null; // 创建音频输入流对象
try
audioInputStream = Audiosystem.getAudioInputStream(soundFile); // 创建音频对象
catch (UnsupportedAudioFileException e1)
e1.printStackTrace();
return;
catch (IOException e1)
e1.printStackTrace();
return;
AudioFormat format = audioInputStream.getFormat(); // 音频格式
SourceDataLine auline = null; // 源数据线
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
catch (LineUnavailableException e)
e.printStackTrace();
return;
catch (Exception e)
e.printStackTrace();
return;
if (auline.isControlSupported(FloatControl.Type.PAN))
FloatControl pan = (FloatControl) auline.getControl(FloatControl.Type.PAN);
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
try
while (nBytesRead != -1)
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
catch (IOException e)
e.printStackTrace();
return;
finally
auline.drain();
// auline.close();
四、项目实现效果
1.运行界面:
2.完整代码
package com.zsx.snake;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
public class GamePanel extends JPanel implements KeyListener, ActionListener
int length; //蛇的长度
int[] snakeX = new int[600]; //蛇的坐标X
int[] snakeY = new int[500]; //蛇的坐标Y
String fx; //R:右 L:左 U:上 D:下
static boolean isStart = false; //游戏是否开始
boolean isDie = false; //判断蛇是否死亡
Timer timer = new Timer(125, this);//定时器
//定义食物:
int foodx;
int foody;
Random random = new Random();
//定义墙体
//int wallx[]=new int[100];
//int wally[]=new int[100];
//积分系统
int score;
//这里可设置障碍
public void map1()
//wallx[0]=250+75;wally[0]=475;
//wallx[1]=250+75;wally[1]=500;
//wallx[2]=250+75;wally[2]=525;
//wallx[3]=250+75;wally[3]=550;
//wallx[4]=250+75;wally[4]=575;
//wallx[5]=250+100;wally[5]=475;
//wallx[6]=250+100;wally[6]=575;
//wallx[7]=250+125;wally[7]=475;
//wallx[8]=250+125;wally[8]=575;
//初始化数据
public void init()
length = 3;
snakeX[0] = 100;
snakeY[0] = 100; //头部坐标
snakeX[1] = 75;
snakeY[1] = 100; //第一个身体坐标
snakeX[2] = 50;
snakeY[2] = 100; //第二个身体坐标
fx = "R"; //默认蛇向右
foodx = 50 + 25 * random.nextInt(32);
foody = 125 + 75 * random.nextInt(6);
// for(int a=0;a<9;a++)
// if(foodx==wallx[a]&&foody==wally[a])
// foodx = 100;
// foody = 100;
// break;
//
//
score = 0;
//构造器调用初始化数据
public GamePanel()
init();
//获取键盘的监听事件
this.setFocusable(true);
this.addKeyListener(this);
timer.start(); //让时间动起来
//画板:画界面,画蛇
//Graphics:画笔
protected void paintComponent(Graphics g)
super.paintComponent(g); //清屏
this.setBackground(Color.BLACK);//设置背景的颜色
//绘制积分框
Data.header.paintIcon(this, g, 0, 0);
//绘制游戏区域
g.fillRect(0, 75, 1000, 625);
//调用地图1
//map1();
//for(int a=0;a<21;a++)
// Data.wall.paintIcon(this, g, wallx[a], wally[a]);
//
//画一条静态的蛇
if (fx.equals("R"))
Data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
else if (fx.equals("L"))
Data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
else if (fx.equals("U"))
Data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
else if (fx.equals("D"))
Data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
//蛇的身体长度通过length来控制
for (int i = 1; i < length; i++)
Data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
//画食物
Data.food.paintIcon(this, g, foodx, foody);
//画积分
g.setColor(Color.white); //设置画笔颜色
g.setFont(new Font("微软雅黑", Font.BOLD, 18));
g.drawString("长度:" + length, 750, 35);
g.drawString("分数:" + score, 750, 55);
//游戏提示:是否开始
if (isStart == false)
//画一段文字
g.setColor(Color.white); //设置画笔颜色
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("按下空格开始游戏", 300, 300);
//失败提醒
if (isDie)
//画一段文字
g.setColor(Color.red); //设置画笔颜色
g.setFont(new Font("微软雅黑", Font.BOLD, 40));
g.drawString("游戏失败,按下空格重新开始", 200, 300);
//接受键盘的输入:监听
@Override
public void keyPressed(KeyEvent e)
// 键盘按下,未释放
//获取按下的键盘是哪个键
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_SPACE) //如果按下的是空格键
if (isDie) //失败,游戏再来一遍
isDie = false;
init(); //重新初始化游戏
else //暂停游戏
isStart = !isStart;
repaint(); //刷新界面
//键盘控制走向
if (keyCode == KeyEvent.VK_LEFT) //如果按下的是空格键
fx = "L";
else if (keyCode == KeyEvent.VK_RIGHT) //如果按下的是空格键
fx = "R";
else if (keyCode == KeyEvent.VK_UP) //如果按下的是空格键
fx = "U";
else if (keyCode == KeyEvent.VK_DOWN) //如果按下的是空格键
fx = "D";
//定时器:监听时间流动;执行定时操作
@Override
public void actionPerformed(ActionEvent e)
//如果游戏处于开始状态,并且游戏没有结束
if (isStart && isDie == false)
//右移
for (int i = length - 1; i > 0; i--) //身体移动
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
//碰到墙壁
// for(int i=0;i<9;i++)
// if(snakeX[0]==wallx[i]&&snakeY[0]==wally[i])
// isDie=true;
//
//
//通过控制方向让头部移动
//这里可以控制蛇撞到四周墙壁不死
/* if (fx.equals("R"))
snakeX[0] = snakeX[0] + 25; //头部移动
//边界判断
for (int i = 0; i < snakeX.length; i++)
if (snakeX[i] > 1000)
snakeX[i] = snakeX[0] - 1000; //isDie=true;
else if (fx.equals("L"))
snakeX[0] = snakeX[0] - 25; //头部移动
//边界判断
for (int i = 0; i < snakeX.length; i++)
if (snakeX[i] < 0)
snakeX[i] = snakeX[0] + 1000; //isDie=true;
//if(snakeX[0]<25)isDie=true;
else if (fx.equals("U"))
snakeY[0] = snakeY[0] - 25; //头部移动
//边界判断
for (int i = 0; i < snakeY.length; i++)
if (snakeY[i] < 90)
snakeY[i] = snakeY[0] + 600; //isDie=true;
//if(snakeY[0]<75)isDie=true;
else if (fx.equals("D"))
snakeY[0] = snakeY[0] + 25; //头部移动
//边界判断
for (int i = 0; i < snakeY.length; i++)
if (snakeY[i] > 600)
snakeY[i] = snakeY[0] - 525; //isDie=true;
//if(snakeY[0]>625)isDie=true;
*/
if(fx.equals("R"))
snakeX[0] = snakeX[0] + 25; //头部移动
// 边界判断
if(snakeX[0]>925 ) isDie=true;
else if(fx.equals("L"))
snakeX[0] = snakeX[0] - 25; //头部移动
// 边界判断
if(snakeX[0]<25)isDie=true;
else if(fx.equals("U"))
snakeY[0] = snakeY[0] - 25; //头部移动
// 边界判断
if(snakeY[0]<100)isDie=true;
else if(fx.equals("D"))
snakeY[0] = snakeY[0] + 25; //头部移动
// 边界判断
if(snakeY[0]>625)isDie=true;
//如果小蛇的头和食物坐标重合
if (snakeX[0] == foodx && snakeY[0] == foody)
//长度+1
length++;
//重新生成食物
foodx = 25 + 25 * random.nextInt(32);
foody = 100 + 75 * random.nextInt(6);
// for(int a=0;a<9;a++)
// if(foodx==wallx[a]&&foody==wally[a])
// foodx = 100;
// foody = 100;
// break;
//
//
//积分+10
score += 10;
//如果小蛇的头和小蛇的身体坐标重合,失败,(把小蛇设置为撞到身体不死)
for(int i=1;i<length;i++)
if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i])
isDie=true;
/*for(int i=1;i<length;i++)
if(snakeX[0]==snakeX[i] && snakeY[0]==snakeY[i])
isDie=true;
*/
//刷新界面
repaint();
timer.start(); //让时间动起来
@Override
public void keyReleased(KeyEvent arg0)
// 释放某个键 不实现
@Override
public void keyTyped(KeyEvent arg0)
// 键盘按下,弹起 不实现
public class Data
//头部的图片
public static URL headerURL = Data.class.getResource("/image/header.png");
public static ImageIcon header = new ImageIcon(headerURL);
//蛇的头部:
public static URL upURL = Data.class.getResource("/image/up.png");
public static URL downURL = Data.class.getResource("/image/down.png");
public static URL leftURL = Data.class.getResource("/image/left.png");
public static URL rightURL = Data.class.getResource("/image/right.png");
public static ImageIcon up = new ImageIcon(upURL);
public static ImageIcon down = new ImageIcon(downURL);
public static ImageIcon left = new ImageIcon(leftURL);
public static ImageIcon right = new ImageIcon(rightURL);
//蛇的身体
public static URL bodyURL = Data.class.getResource("/image/body.png");
public static ImageIcon body = new ImageIcon(bodyURL);
//食物:
public static URL foodURL = Data.class.getResource("/image/food.png");
public static ImageIcon food = new ImageIcon(foodURL);
//墙的图片
public static URL wallURL = Data.class.getResource("/image/wall.png");
public static ImageIcon wall = new ImageIcon(wallURL);
public class GameJMenuBar extends JMenuBar implements ActionListener
public void init()
//创建菜单对象
JMenu menu1 = new JMenu("游戏选项");
JMenu menu2 = new JMenu("帮助");
//添加菜单到工具栏对象
this.add(menu1);
this.add(menu2);
//创建菜单项对象
JMenuItem item1 = new JMenuItem("退出");
//添加菜单项到菜单对象menu1中
menu1.add(item1);
//创建菜单项对象
JMenuItem item3 = new JMenuItem("操作方法");
//添加菜单项到菜单对象menu1中
menu2.add(item3);
//创建菜单项对象
JMenuItem item2 = new JMenuItem("注意事项");
//添加菜单项到菜单对象menu1中
menu2.add(item2);
item1.addActionListener(this);// 为菜单项添加事件监听器
item2.addActionListener(this);// 为菜单项添加事件监听器
item3.addActionListener(this);// 为菜单项添加事件监听器
public GameJMenuBar()
init();
@Override
public void actionPerformed(ActionEvent e)
String cmd = e.getActionCommand();
if (cmd.equals("退出"))
System.exit(0);
if (cmd.equals("注意事项"))
JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
JLabel Label1 = new JLabel("请注意正确使用");
JLabel Label2 = new JLabel("游戏结束请按空格重新开始");
JLabel Label3 = new JLabel("暂停游戏也可以按空格");
panel.add(Label1);
panel.add(Label2);
panel.add(Label3);
GamePanel.isStart = false;
JOptionPane.showMessageDialog(this, panel, "注意事项", JOptionPane.PLAIN_MESSAGE);
repaint(); //刷新界面
if (cmd.equals("操作方法"))
JPanel panel = new JPanel(new GridLayout(0, 1, 5, 5));
JLabel Label1 = new JLabel("按下空格可以暂停/开始游戏");
//JLabel Label2 = new JLabel("目前死亡的唯一方式:暂停,并退出");
JLabel Label2 = new JLabel("目前死亡的唯一方式:碰到自己的身体");
JLabel Label3 = new JLabel("按下方向键可以控制蛇的移动");
panel.add(Label1);
panel.add(Label2);
panel.add(Label3);
GamePanel.isStart = false;
JOptionPane.showMessageDialog(this, panel, "操作方法", JOptionPane.PLAIN_MESSAGE);
repaint(); //刷新界面,repaint()方法用来重新绘制图像,图像发生改变时立即显示,paint()方法用来绘制图像,
public class Music extends Thread
private String fileName;
private final int EXTERNAL_BUFFER_SIZE = 524288;
public Music(String wavFile)
this.fileName = wavFile;
@SuppressWarnings("unused")
public void run()
File soundFile = new File(fileName); // 播放音乐的文件名
if (!soundFile.exists())
System.err.println("Wave file not found:" + fileName);
return;
while (true) // 设置循环播放
AudioInputStream audioInputStream = null; // 创建音频输入流对象
try
audioInputStream = AudioSystem.getAudioInputStream(soundFile); // 创建音频对象
catch (UnsupportedAudioFileException e1)
e1.printStackTrace();
return;
catch (IOException e1)
e1.printStackTrace();
return;
AudioFormat format = audioInputStream.getFormat(); // 音频格式
SourceDataLine auline = null; // 源数据线
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
catch (LineUnavailableException e)
e.printStackTrace();
return;
catch (Exception e)
e.printStackTrace();
return;
if (auline.isControlSupported(FloatControl.Type.PAN))
FloatControl pan = (FloatControl) auline.getControl(FloatControl.Type.PAN);
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
try
while (nBytesRead != -1)
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
catch (IOException e)
e.printStackTrace();
return;
finally
auline.drain();
// auline.close();
public class StartGame
static final int WIDTH = 1000;
static final int HEIGHT = 750;
public static void main(String args[])
//1、绘制一个静态窗口 JFrame
JFrame jf = new JFrame();
jf.setTitle("王校长吃面包");
//设置界面大小
jf.setSize(WIDTH, HEIGHT);
//窗口大小不可以改变
jf.setResizable(false);
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
//获取屏幕的宽度和高度
int width = screenSize.width;
int height = screenSize.height;
int x = (width - WIDTH) / 2;
int y = (height - HEIGHT) / 2;
//背景音乐启动
Music audioPlayWave = new Music("music.wav");// 开音乐 音樂名
audioPlayWave.start();
@SuppressWarnings("unused")
int musicOpenLab = 1;
jf.setLocation(x, y);
//设置关闭事件
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//2、面板 JPanel
jf.add(new GamePanel());
//3、菜单栏 JMenuBar
jf.setJMenuBar(new GameJMenuBar());
jf.setVisible(true);
以上是关于实验二 贪吃蛇游戏开发的主要内容,如果未能解决你的问题,请参考以下文章
代码解析双向链表实现贪吃蛇游戏!简单易学,开发自己第一个游戏!