实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子,上下左右控制“蛇”的移动,吃到“豆子”以后“蛇”的身体加长一点,得分增加,“蛇”碰到边界或,蛇头与蛇身相撞,蛇死亡,游戏结束。为游戏设计初始欢迎界面,游戏界面,游戏结束界面。
贪吃蛇实验图形界面由蛇头,蛇身,食物等组成。
蛇头部分通过键盘方向键进行上下左右的移动。豆子随机生成,操纵蛇头吃到随机的豆子,蛇身长度变长,得分增加。据此,可分析出具体需要实现的功能:
1.构建合适的网格,并且设置好墙。
2.在适当的位置产生豆子,即网格内部,且不是蛇身的地方。
3.通过键盘控制实现蛇头的移动
4.实现蛇身的刷新。当蛇在去吃食物的移动过程中,蛇头按照方向去往邻近的一个网格,蛇身的每一个结点取代上一个结点的位置,蛇尾处的结点消失。蛇吃到豆子的那一次移动,豆子即为蛇头的位置,其余不再取代上一个结点的位置。
5.判断是否撞墙与撞到自身,即蛇头的位置是否与墙及自己身体的坐标重合。
6.进行计分与计时。
构建网格与其他说明界面
private JLabel label2 = new JLabel("所花时间:");
private JLabel label3 = new JLabel("得分"); // 标签
private JLabel label4 = new JLabel("说 明:");
private JTextArea explain = new JTextArea("游戏界面按上下左右键实现移动,按ESC重新开始,按空格键可以实现暂停和开始");
private JLabel score = new JLabel("");
private JLabel Time = new JLabel("");
private Font f = new Font("微软雅黑",Font.PLAIN,15);
private Font f2 = new Font("微软雅黑",Font.PLAIN,13);
private JPanel p = new JPanel(); //面板
private int hour =0; // 定义时间,小时,分钟,秒
private int min =0;
private int sec =0 ;
private int sco=0;
private boolean pause = false;
add(label3);
label3.setBounds(500, 10, 80, 20);
label3.setFont(f);
add(score);
score.setBounds(500, 35, 80, 20);
score.setFont(f);
add(label2);
label2.setBounds(500, 60, 80, 20);
label2.setFont(f); // 标签
add(Time);
Time.setBounds(500, 85, 80, 20);
Time.setFont(f);
add(p);
p.setBounds(498, 110, 93, 1);
p.setBorder(BorderFactory.createLineBorder(Color.black));
add(label4);
label4.setBounds(500, 115, 80, 20);
label4.setFont(f);
add(explain);
explain.setBounds(498, 138, 90, 350);
explain.setFont(f2);
explain.setLineWrap(true);
explain.setOpaque(false);
//墙
g.setStroke( new BasicStroke(4,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
g.setBackground(Color.black);
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.black);
g.drawLine(5+i*22,9,5+i*22,472);
if(i <= 20)
{
g.drawLine(4,10+i*22,491,10+i*22);
}
}
进行蛇整体的布局及移动还有食物的生成
public class Snake extends JComponent {
//建一个贪吃蛇的类对其进行编辑
private static final long serialVersionUID = 3794762291171148906L; // 定义了一个私有的静态的不可改变的long类型的 名字是VersionUID,
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 = "R";//默认向右走
private String current_direction = "R";//当前方向
private boolean first_launch = false;
private boolean iseaten = false;
private boolean isrun = true;
private int randomx,randomy;
private int body_length = 5;//身体长度初始化为5
private Thread run;
public void paintComponent(Graphics g1){
// 指调用父类的绘制事件,在重写父类函数时经常会调用一下相应的父类方法
super.paintComponent(g1); // super关键字用来调用父类中定义的构造器,控制对象的父类的部分结构
Graphics2D g = (Graphics2D) g1; // 画(Graphics g)
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,RenderingHints.VALUE_STROKE_NORMALIZE);
//画头部
g.setColor(Color.red); // 设置颜色
g.fillRoundRect(head.x, head.y, 20, 20, 10, 10);
g.setPaint(new GradientPaint(115,135,Color.CYAN,230,135,Color.MAGENTA,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, 10, 10);
}
//初始化食物位置
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, 10, 10);
}
if(EatFood())//被吃了重新产生食物,并且计入得分
{
ProduceRandom();
g.fillOval(randomx, randomy, 19, 19);
iseaten = false;
sco++;
showScore();
}
else
{
g.fillOval(randomx, randomy, 19, 19);
}
}
对是否撞墙以及是否撞到自己进行判断以及处理
public void HitWall(){
//判断是否撞墙
if(current_direction == "L")
{
if(head.x < 7)
{
int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
if(result==JOptionPane.YES_NO_OPTION)
{
direction = "R";//默认向右走
current_direction = "R";//当前方向
first_launch = false;
iseaten = false;
isrun = true;
body_length = 5;
head = new Tile(227,100);
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");
}
else
{
run.stop();
}
}
}
if(current_direction == "R")
{
if(head.x > 489)
{
int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
if(result==JOptionPane.YES_NO_OPTION)
{
direction = "R";//默认向右走
current_direction = "R";//当前方向
first_launch = false;
iseaten = false;
isrun = true;
body_length = 5;
head = new Tile(227,100);
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");
}
else
{
run.stop();
}
}
}
if(current_direction == "U")
{
if(head.y < 12)
{
int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
if(result==JOptionPane.YES_NO_OPTION)
{
direction = "R";//默认向右走
current_direction = "R";//当前方向
first_launch = false;
iseaten = false;
isrun = true;
body_length = 5;
head = new Tile(227,100);
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");
}
else
{
run.stop();
}
}
}
if(current_direction == "D")
{
if(head.y > 472)
{
int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
if(result==JOptionPane.YES_NO_OPTION)
{
direction = "R";//默认向右走
current_direction = "R";//当前方向
first_launch = false;
iseaten = false;
isrun = true;
body_length = 5;
head = new Tile(227,100);
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");
}
else
{
run.stop();
}
}
}
}
public void HitSelf(){
//判断是否撞到自己身上
for(int i = 0;i < body_length; i++)
{
if(body[i].x == head.x && body[i].y == head.y)
{
int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
if(result==JOptionPane.YES_NO_OPTION)
{
direction = "R";//默认向右走
current_direction = "R";//当前方向
first_launch = false;
iseaten = false;
isrun = true;
body_length = 5;
head = new Tile(227,100);
hour =0;
min =0;
sec =0 ;
for(int j = 0; j < MAX_SIZE;j++)
{
body[j].x = 0;
body[j].y = 0;
}
run = new Thread();
run.start();
System.out.println("Start again");
}
else
{
run.stop();
}
break;
}
}
}