项目目标和主要内容
1)实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子。玩家能利用上下左右键控制“蛇”的移动,“蛇”吃到“豆子”后“蛇”身体加长一节,得分增加,“蛇”碰到边界或蛇头与蛇身相撞,“蛇”死亡,游戏结束。
项目的主要功能
1)进行交互界面的设计,要有开始键、暂停键和停止退出的选项,能够控制游戏进程。
项目总体框架
系统详细设计
Java Swing搭建的GUI
1)贪吃蛇窗口的整体大小、位置
2)上方信息显示区以及下方游戏画面区
3)蛇头、蛇身以及食物的绘制
键盘监听
1)通过“W”“A”“S”“D”或小键盘区的上下左右控制蛇的移动
2)通过“F”实现游戏的开始与暂停
随机生成
1)在游戏区域通过随机算法计算食物在网格中的坐标并生成食物
2)在游戏开始时固定生成蛇的位置与上下左右方向
碰撞的判断
1)当蛇头坐标与食物坐标相同时,原食物消失,生成新的食物,蛇长+1,分数+1
2)当蛇头坐标与蛇身或墙壁相同时,游戏结束,玩家无法继续操控,计分停止
关键算法分析
·通过定时器来设置蛇的行进速度,本次实验我将数值设置为90
·在游戏区域范围内,通过随机生成食物的X坐标与Y坐标来定位随机生成的食物的位置
·蛇的初始位置与方向通过代码固定
·将蛇行进的“上”“下”“左”“右”三个方向通过数字代替,在代码中将方向概念数字化,通过if语句设置为不可回头,如:向右行进的过程中不能向左移动
·在初始代码中,蛇如果超出上界,则蛇头会显示在界面最上方,如图:
经过代码的修改,在蛇超过上界时,将蛇头坐标设置到界面之外,达到隐藏蛇头的效果,如图:
源代码
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
public class Main extends JFrame implements KeyListener, ActionListener, MouseListener {
//蛇当前长度
int slong = 2;
//蛇坐标
int[] Snakex = new int[100];
int[] Snakey = new int[100];
int fx = 1;
//蛇的方向 0-左 1-右 2-上 3-下
Timer timer = new Timer(90, this);//设置速度
//食物位置
int foodx;
int foody;
//随机数,随机位置生成食物
Random random = new Random();
//游戏信息 0-未开始 1-开始 2-结束
int started = 0;
public void myJFrame() {
this.setTitle("贪吃蛇");
this.setSize(800, 600);
this.setResizable(false);
this.setDefaultCloseOperation(Main.EXIT_ON_CLOSE);
int width = Toolkit.getDefaultToolkit().getScreenSize().width; //获取屏幕宽度
int height = Toolkit.getDefaultToolkit().getScreenSize().height; //获取屏幕高度
this.setLocation((width - 800) / 2, (height - 600) / 2);
this.setFocusable(true);
this.addKeyListener(this);
this.setVisible(true);
//蛇的初始位置
Snakex[0] = 80;
Snakey[0] = 120;
Snakex[1] = 60;
Snakey[1] = 120;
//随机食物的初始位置
foodx = random.nextInt(39);
foody = random.nextInt(22);
foodx = foodx * 20;
foody = foody * 20 + 80;
System.out.println(foodx + "," + foody);
}
public void paint(Graphics g) {
//绘制背景
g.setColor(Color.white);
g.fillRect(0, 0, 800, 600);
//绘制游戏区域
g.setColor(Color.black);
g.fillRect(0, 80, 800, 520);
//绘制蛇
for (int i = 0; i < slong; i++) {
g.setColor(new Color(17, 15, 198));
g.fillRect(Snakex[i], Snakey[i], 15, 15);
}
//绘制食物
g.setColor(new Color(0, 117, 15));
g.fillOval(foodx, foody, 20, 20);
if (started == 0) {
g.setColor(Color.BLACK);//设置画笔颜色
g.setFont(new Font("华文新魏", 10, 20));
g.drawString("按下“F”开始游戏", 325, 65); //绘制字符
} else if (started == 1) {
g.setColor(Color.BLACK);//设置画笔颜色
g.setFont(new Font("华文新魏", 10, 20));
g.drawString("得分:", 300, 65); //绘制字符
g.drawString(String.valueOf(slong - 2), 420, 65); //绘制字符
} else if (started == 2) {
g.setColor(Color.BLACK);//设置画笔颜色
g.setFont(new Font("华文新魏", 10, 20));
g.drawString("游戏结束-", 250, 65); //绘制字符
g.drawString("最终得分为:", 350, 65); //绘制字符
g.drawString(String.valueOf(slong - 2), 470, 65); //绘制字符
}
}
@Override
public void actionPerformed(ActionEvent e) {
//判断游戏是否开始
if (started == 1) {
// 通过循环控制蛇移动
for (int i = slong - 1; i > 0; i--) {
Snakex[i] = Snakex[i - 1];
Snakey[i] = Snakey[i - 1];
}
//判断蛇移动的方向
if (fx == 0) {
Snakex[0] = Snakex[0] - 20;
} else if (fx == 1) {
Snakex[0] = Snakex[0] + 20;
} else if (fx == 2) {
Snakey[0] = Snakey[0] - 20;
} else if (fx == 3) {
Snakey[0] = Snakey[0] + 20;
}
//判断蛇是否撞到墙外
if (Snakex[0] < 0 || Snakex[0] > 780 || Snakey[0] < 80 || Snakey[0] > 580) {
started = 2;
}
//判断蛇是否吃到了食物
if (Snakex[0] == foodx && Snakey[0] == foody) {
slong++;
foodx = random.nextInt(39);
foody = random.nextInt(22);
foodx = foodx * 20;
foody = foody * 20 + 80;
System.out.println(foodx + "," + foody);
}
//判断是否吃到了自己
for (int i = 1; i < slong; i++) {
if (Snakex[0] == Snakex[i] && Snakey[0] == Snakey[i]) {
started = 2;
}
}
//判断食物是否随机在了蛇身上
for (int i = 0; i < slong; i++) {
if (foodx == Snakex[i] && foody == Snakey[i]) {
// 随机食物的初始位置
foodx = random.nextInt(39);
foody = random.nextInt(22);
foodx = foodx * 20;
foody = foody * 20 + 80;
System.out.println(foodx + "," + foody);
}
}
repaint();
}
timer.start();
}
//输入
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
//获取从键盘输入的键
int key = e.getKeyCode();
//判断是否为F
if (key == KeyEvent.VK_F) {
if (started == 0) {
started = 1;
} else if (started == 1) {
started = 0;
} else if (started == 2) {
started = 0;
//蛇当前长度
slong = 2;
//蛇的初始位置
Snakex[0] = 60;
Snakey[0] = 100;
Snakex[1] = 40;
Snakey[1] = 100;
//随机食物的初始位置
foodx = random.nextInt(39);
foody = random.nextInt(22);
foodx = foodx * 20;
foody = foody * 20 + 80;
//初始化方向
fx = 1;
}
repaint();
timer.start();
//左
} else if (key == KeyEvent.VK_LEFT || key == KeyEvent.VK_A) {
if (fx != 1) {
fx = 0;
}
//右
} else if (key == KeyEvent.VK_RIGHT || key == KeyEvent.VK_D) {
if (fx != 0) {
fx = 1;
}
//上
} else if (key == KeyEvent.VK_UP || key == KeyEvent.VK_W) {
if (fx != 3) {
fx = 2;
}
//下
} else if (key == KeyEvent.VK_DOWN || key == KeyEvent.VK_S) {
if (fx != 2) {
fx = 3;
}
}
}
//抬起
@Override
public void keyReleased(KeyEvent e) {
}
//点击
@Override
public void mouseClicked(MouseEvent e) {
}
//按下
@Override
public void mousePressed(MouseEvent e) {
}
//抬起
@Override
public void mouseReleased(MouseEvent e) {
}
//进入
@Override
public void mouseEntered(MouseEvent e) {
}
//离开
@Override
public void mouseExited(MouseEvent e) {
}
}
class Test {
public static void main(String[] args) {
Main snake = new Main();
snake.myJFrame();
}
}
贪吃蛇界面展示