软件实习项目二 —— Java实现贪吃蛇小游戏的开发制作
一、实验任务
(1)该题要求实现贪吃蛇的基本功能。
(2)屏幕上随机出现一个“食物”,称之为豆子。⬆️⬇️⬅️➡️控制“蛇”的移动。吃到“豆子”以后的“蛇”的身体加长一点,得分增加,“蛇”碰到边界,或蛇头与蛇身相撞,蛇死亡,游戏状态转为结束。
(3)为游戏设计初识欢迎界面,游戏界面,游戏结束界面。
二、实验准备
(1)具体编程语言:Java
(2)确定锁定图形界面:Java Swing
三、设计思路
(1)游戏需要开始界面,游戏进行中的界面,犯规失败导致游戏重新开始的界面。主要的角色蛇、食物的设计,背景面板、边框的设计
(2)编写方法,通过键盘上的上下左右键控制蛇身运动,蛇身是否与墙体或自身碰撞,是则犯规失败。食物的随机生成与判断是否被吃掉,蛇身的加长,得分的增加,蛇身随着蛇头一起运动
(3)增加线程对时间进行控制,增加计时功能
四、功能实现
(1)游戏界面的设计,背景面板的构造,蛇的构造,食物的构造
class SnakeDemo extends JComponent{
/**
*
*/
private static final long serialVersionUID = 3794762291171148906L;
private final int MAX_SIZE = 400;//蛇身体最长为400节
private Tile temp = new Tile(0,0);
private Tile temp2 = new Tile(0,0);
private Tile head = new Tile(227,100);//头部的位置初始化为(227,100)
private Tile[] body = new Tile[MAX_SIZE];
private String direction = "D";//默认向下走
private String current_direction = "D";//当前方向
private boolean first_launch = false;//设置初始状态下的豆豆没有吃到
private boolean iseaten = false;//设置初始状态为没吃到
private boolean isrun = false;//设置初始状态为停止运动
private int randomx,randomy;//设置一个随即坐标生成豆豆
private int body_length = 5;//身体长度初始化为5
private int food = 0;
private Thread run;
private JLabel label1 = new JLabel("得分:");
private JLabel label2 = new JLabel("用时:");
private JLabel label3 = new JLabel("规则:");
private JTextArea explain = new JTextArea("按下空格键以开始或暂停游戏,按下ESC键以重新开始游戏。" +
"通过键盘上的 上️、下️、左️、右️ 键来控制蛇身的运动走向,使蛇吃豆豆来增加分数️。" +
"注意不要让蛇吃到自己身体的部分或撞到墙壁,否则游戏结束,得分归零");
private JLabel Score = new JLabel("0");
private JLabel Time = new JLabel("");
private Font f1 = new Font("Miriam Fixed",Font.PLAIN,18);
private Font f2 = new Font("Miriam Fixed",Font.PLAIN,13);
private JPanel p = new JPanel();
private int hour = 0;
private int min = 0;
private int sec = 0;
private boolean pause = true;//设置初始状态暂停
public SnakeDemo(){
String lookAndFeel =UIManager.getSystemLookAndFeelClassName();
try {
UIManager.setLookAndFeel(lookAndFeel);
} catch (ClassNotFoundException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
} catch (InstantiationException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
} catch (IllegalAccessException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
} catch (UnsupportedLookAndFeelException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
//布局
add(label1);
label1.setBounds(500, 10, 80, 20);
label1.setFont(f1);
add(Score);
Score.setBounds(500, 35, 80, 20);
Score.setFont(f1);
add(label2);
label2.setBounds(500, 60, 80, 20);
label2.setFont(f1);
add(Time);
Time.setBounds(500, 85, 80, 20);
Time.setFont(f1);
add(p);
p.setBounds(498, 110, 93, 1);
p.setBorder(BorderFactory.createLineBorder(Color.lightGray));
add(label3);
label3.setBounds(500, 115, 80, 20);
label3.setFont(f1);
add(explain);
explain.setBounds(498, 138, 100, 350);
explain.setFont(f2);
explain.setLineWrap(true);
explain.setOpaque(false);
//画头部
g.setColor(Color.ORANGE);
g.fillRoundRect(head.x, head.y, 20, 20, 10, 10);
g.setPaint(new GradientPaint(115,135,Color.YELLOW,230,135,Color.GREEN,true));
if(!first_launch)
{
//初始化身体
int x = head.x;
for(int i = 0;i < body_length;i++)
{
x -= 22;//相邻两个方块的间距为2个像素,方块宽度都为20像素
body[i].x = x;
body[i].y = head.y;
g.fillRoundRect(body[i].x, body[i].y, 20, 20, 20, 20);
}
//初始化豆豆的位置
ProduceRandom();
g.fillOval(randomx, randomy, 19, 19);
}
else
{
//每次刷新身体
for(int i = 0;i < body_length;i++)
{
g.fillRoundRect(body[i].x, body[i].y, 20, 20, 20, 20);
}
//画墙
g.setStroke( new BasicStroke(4,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
g.setBackground(Color.white);
g.drawRect(2, 7, 491, 469);
//网格线
for(int i = 1;i < 22;i++)
{
g.setStroke( new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
g.setColor(Color.LIGHT_GRAY);
g.drawLine(5+i*22,9,5+i*22,472);
if(i <= 20)
{
g.drawLine(4,10+i*22,491,10+i*22);
}
}
(2)游戏的过程,需要玩家用户通过⬆️⬇️⬅️➡️键来控制蛇身的运动方向,来吃掉随机生成的食物。如果蛇身碰撞的墙体或咬到自身身体部分,则判断为失败,游戏结束。再设置其他功能操作的按钮,如以按下空格来开始暂停游戏,按下ESC键来重新开始游戏。
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
if(e.getKeyCode() == KeyEvent.VK_RIGHT)
{
if(isrun && current_direction != "L")
{
direction = "R";
}
}
if(e.getKeyCode() == KeyEvent.VK_LEFT)
{
if(isrun && current_direction != "R")
{
direction = "L";
}
}
if(e.getKeyCode() == KeyEvent.VK_UP)
{
if(isrun && current_direction != "D")
{
direction = "U";
}
}
if(e.getKeyCode() == KeyEvent.VK_DOWN)
{
if(isrun && current_direction != "U")
{
direction = "D";
}
}
if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
{
direction = "D";//默认向下走
current_direction = "D";//当前方向
first_launch = false;
iseaten = false;
isrun = true;
body_length = 5;
head = new Tile(227,100);
Score.setText("0");
hour = 0;
min = 0;
sec = 0;
for(int i = 0; i < MAX_SIZE;i++)
{
body[i].x = 0;
body[i].y = 0;
}
run = new Thread();
run.start();
System.out.println("Start again");
}
if(e.getKeyCode() == KeyEvent.VK_SPACE)//按空格键开始和暂停
{
if(!pause)//暂停
{
pause = true;
isrun = false;
}
else//开始
{
pause = false;
isrun = true;
}
}
}
});
//每次刷新身体
for(int i = 0;i < body_length;i++)
{
g.fillRoundRect(body[i].x, body[i].y, 20, 20, 20, 20);
}
if(EATEN())//豆豆被吃后重新随机生成豆豆
{
ProduceRandom();
g.fillOval(rando