贪吃蛇设计思想:
1)每一次移动
// 将最后一个快放在数组第一个,这个过程在我的word文档中有解释*****
// 这个过程相当于蛇的对象数组前进了。
for (int i = LEN - 2; i >= headL; i--) {
ps[i].copyTo(ps[i + 1]);// 赋值拷贝,安全
}
ps[headL + 1].setShape(2);// 原先是头的形状改为身体形状
ps[LEN - 1].setShape(3);// 原先是尾前的身体形状改为尾的形状
ps[headL].set(1, headD, headX, headY);
2)吃食物
upgrade();// 判断是否升级
ps[headL].setShape(2);
ps[--headL] = new Partly(1, headD, headX, headY);
layoutFood();
图片
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
///*
// * 游戏规则:
// * 1)满四级就打通关;
// * 2) 蛇是可以穿越墙壁的;
// * 3)贪吃蛇每吃三个食物就升一级;
// * 4)每升一级,贪吃蛇的移动速度就会加快;
// * 5) 在一定时间内没有通关,就表示游戏失败;
// * 6) 贪吃蛇不能往回走;
// * 7) 撞到自己的身体,游戏失败。
// * 8) 每吃一个食物就的10分。
// * 9) 1分钟内没有取胜,那么被判为失败。
// */
public class GluttonousSnake extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private final int MXS = 3;// mapXStart
private final int MXE = 25;// mapXEnd
private final int MYS = 3;// mapYStart
private final int MYE = 25;// mapYEnd
private final int LEN = 12;// 贪吃蛇的长度
private MyJPaint paint = null;// 自定义画布
private Timer timer = null;// 定时器
private MyTimer mt = null;// 定时器的实现者
private Partly[] ps = null;// 贪吃蛇对象数组
private int rank = 1;// 满三级就表示胜利
private int delay = 1000;// 初始速度为每1秒一格的移速
private int headL = 9;// 蛇头在对象数组中的初始位置
private int headX = MXS + 5;// 蛇头的初始x位置
private int headY = MYS + 3;// 蛇头的初始y位置
private int headD = 4;// 蛇的初始方向为右
private int foodX = 0;// 食物x位置
private int foodY = 0;// 食物y位置
private boolean isChange = true;// 使颜色可以变换
private int count = 0, countNumber = 0;
private boolean isStart = false;
private JButton btn = null;
public static void main(String[] args) {
new GluttonousSnake();
}
public GluttonousSnake() {
super("嘿嘿!虚空金蛇");
this.setBounds(200, 50, 900, 620);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// new对象
ps = new Partly[LEN];
initSnake();
mt = new MyTimer();
timer = new Timer(delay, mt);
layoutFood();
paint = new MyJPaint();
btn = new JButton("开始");
btn.addActionListener(this);
btn.setActionCommand("start");
// this加组件
this.getContentPane().add(paint);
this.getContentPane().add(getSouthJPanel(), "South");
// this加监听
this.addKeyListener(mt);
// 显示界面
this.setVisible(true);
timer.start();
}
public void initSnake() {
headX = MXS + 5;
headY = MYS + 3;
headD = 4;
ps[LEN - 1] = new Partly(3, 3, MXS + 3, MYS + 3);
ps[LEN - 2] = new Partly(2, 3, MXS + 4, MYS + 3);
ps[headL] = new Partly(1, 3, MXS + 5, MYS + 3);
}
public JPanel getSouthJPanel() {
JPanel panel = new JPanel();
panel.add(btn);
return panel;
}
public void left() {
if (headX - 1 <= MXS) {
end();// ,碰壁,游戏结束
} else {
headX--;
}
headD = 3;
}
public void right() {
if (headX + 1 >= MXE) {
end();// ,碰壁,游戏结束
} else {
headX++;
}
headD = 4;
}
public void up() {
if (headY - 1 < MYS) {
end();// ,碰壁,游戏结束
} else {
headY--;
}
headD = 1;
}
public void down() {
if (headY + 1 >= MYE) {
end();// ,碰壁,游戏结束
} else {
headY++;
}
headD = 2;
}
public void start() {
end();
headL = 9;
countNumber = 0;
count = 0;
rank = 0;
initSnake();
layoutFood();
paint.repaint();
isStart = true;
timer.start();
}
public void end(int n){
if(n==1){
JOptionPane.showMessageDialog(this, "游戏时间到,你失败了。");
}
end();
}
public void end() {
paint.repaint();
isStart = false;
timer.stop();
timer.setDelay(delay = 1000);
}
public void snakeMove() {
if (headD == 3) {
left();
}
if (headD == 4) {
right();
}
if (headD == 1) {
up();
}
if (headD == 2) {
down();
}
snakeNext();
}
public void snakeNext() {
// 判断前进的快是否是否有东西,这里只有3种。
// 1是食物,2是蛇的身体,什么也没有。
// 撞到自己,则游戏失败
for (int i = LEN - 2; i >= headL; i--) {
if (ps[i].isPartly(headX, headY)) {
end();
JOptionPane.showMessageDialog(this, "失败!!!");
return;
}
}
// 吃到食物
if (foodX == headX && foodY == headY) {
upgrade();
ps[headL].setShape(2);
ps[--headL] = new Partly(1, headD, headX, headY);
layoutFood();
} else {
// 将最后一个快放在数组第一个,这个过程在我的word文档中有解释*****
// 这个过程相当于蛇的对象数组前进了。
for (int i = LEN - 2; i >= headL; i--) {
ps[i].copyTo(ps[i + 1]);// 赋值拷贝,安全
}
ps[headL + 1].setShape(2);// 原先是头的形状改为身体形状
ps[LEN - 1].setShape(3);// 原先是尾前的身体形状改为尾的形状
ps[headL].set(1, headD, headX, headY);
}
paint.repaint();
}
public void upgrade() {// 判断是否升级
count++;
if (count == 3) {
rank++;
delay -= 400;
} else if (count == 6) {
rank++;
delay -= 400;
} else if (count == 9) {
rank++;
end();
if (0 == JOptionPane.showConfirmDialog(this, "恭喜你打通关了,是否要重新开始?")) {
start();
}
}
timer.setDelay(delay);
}
private void layoutFood() {
// 先使食物的范围确定
foodX = isExist((int) (Math.random() * 1000), true);
foodY = isExist((int) (Math.random() * 1000), false);
// 食物放置的位置对不对
boolean b = false;
for (int i = headL; i < LEN; i++) {
if (ps[i].isPartly(foodX, foodY)) {
b = true;
break;
}
}
if (b) {
layoutFood();
}
}
private int isExist(int n, boolean boo) {
if (boo) {
n %= MXE;
if (!(n < MXE && n > MXS)) {// 不在范围内就死循环
n = isExist((int) (Math.random() * 1000), true);
}
} else {
n %= MYE;
if (!(n < MYE && n > MYS)) {
n = isExist((int) (Math.random() * 1000), false);
}
}
return n;
}
private class Partly {
protected int shape;// 1头,2身,3尾
protected int direction;// 3左,4右,1上,2下
protected int x, y;// 贪吃蛇身体的位置
public Partly(int shape, int direction, int x, int y) {
this.set(shape, direction, x, y);
}
public void copyTo(Partly p) {// 这里不捆绑
p.shape = this.shape;
p.direction = this.direction;
p.x = this.x;
p.y = this.y;
}
public void set(int shape, int direction, int x, int y) {
this.shape = shape;
this.direction = direction;
this.x = x;
this.y = y;
}
public void setShape(int shape) {
this.shape = shape;
}
public boolean isPartly(int x, int y) {
if (this.x != x) {
return false;
}
if (this.y != y) {
return false;
}
return true;
}
@Override
public String toString() {
return "Partly [shape=" + shape + ", direction=" + direction
+ ", x=" + x + ", y=" + y + "]";
}
}
private class MyJPaint extends JPanel {
private static final long serialVersionUID = 1L;
protected final int P_WIDTH = 20;// 画布宽度为20像素
protected final int P_HEIGHT = 20;// 画布高度为20像素
@Override
public void paint(Graphics g) {
super.paint(g);// 擦掉原来的图画
// 画框架,就是画线,交叉的线看起来就像是框框
g.setColor(Color.blue);
for (int i = MXS; i <= MXE; i++) {
g.drawLine(i * P_WIDTH, MYS * P_HEIGHT, i * P_WIDTH, MYE
* P_HEIGHT);// 画列,行不动,就是y不动
g.fill3DRect(i * P_WIDTH, (MYS - 1) * P_HEIGHT, P_WIDTH,
P_HEIGHT, true);// true表示填充块是凸起的,画上面的框架
g.fill3DRect(i * P_WIDTH, MYE * P_HEIGHT, P_WIDTH, P_HEIGHT,
true);// 画下面的框架
}
for (int j = MYS; j <= MYE; j++) {
g.drawLine(MXS * P_WIDTH, j * P_HEIGHT, MXE * P_WIDTH, j
* P_HEIGHT);// 画行,列不动,就是x不动
g.fill3DRect(MXS * P_HEIGHT, (j - 1) * P_WIDTH, P_WIDTH,
P_HEIGHT, true);// 画左边的的框架,y要上移
g.fill3DRect(MXE * P_HEIGHT, j * P_WIDTH, P_WIDTH, P_HEIGHT,
true);// 画右边的框架
}
// 画食物
if (isChange) {
g.setColor(Color.red);
} else {
g.setColor(Color.blue);
}
isChange = !isChange;
g.fillOval(foodX * P_WIDTH, foodY * P_HEIGHT, P_WIDTH, P_HEIGHT);
// 画贪吃蛇
for (int i = headL; i < LEN; i++) {
if (ps[i].shape == 1) {
g.setColor(Color.red);
g.fill3DRect(ps[i].x * P_WIDTH, ps[i].y * P_HEIGHT,
P_WIDTH, P_HEIGHT, true);
}
if (ps[i].shape == 2) {
g.setColor(Color.yellow);
g.fill3DRect(ps[i].x * P_WIDTH, ps[i].y * P_HEIGHT,
P_WIDTH, P_HEIGHT, true);
}
if (ps[i].shape == 3) {
g.setColor(Color.green);
g.fill3DRect(ps[i].x * P_WIDTH, ps[i].y * P_HEIGHT,
P_WIDTH, P_HEIGHT, true);
}
}
// 画提示语
g.setColor(Color.red);
g.drawString("游戏等级: " + rank, 600, 100);
g.drawString("游戏得分: " + count * 10, 600, 120);
g.drawString("游戏规则:", 600, 140);
g.drawString("1)满四级就打通关;", 600, 155);
g.drawString("2) 蛇是可以穿越墙壁的;", 600, 170);
g.drawString("3)贪吃蛇每吃三个食物就升一级;", 600, 185);
g.drawString("4)每升一级,贪吃蛇的移动速度就会加快;", 600, 200);
g.drawString("5) 在一定时间内没有通关,就表示游戏失败;", 600, 215);
g.drawString("6) 贪吃蛇不能往回走;", 600, 230);
g.drawString("7) 撞到自己的身体,游戏失败。", 600, 245);
g.drawString("8) 每吃一个食物就的10分。", 600, 260);
g.drawString("9) 1分钟内没有取胜,那么被判为失败。", 600, 275);
g.drawString("已用时间: "+countNumber, 700, 120);
if (headL > 0) {
g.setColor(Color.orange);
Font font = new Font("宋体", Font.BOLD, 20);
g.setFont(font);
g.drawString("注意: ", 600, 320);
g.drawString("请点击按钮开始游戏", 600, 360);
repaint();// 显示字体
}
}
}
private class MyTimer implements ActionListener, KeyListener {
@Override
public void actionPerformed(ActionEvent e) {
paint.repaint();
if (!isStart) {
return;
}
if (countNumber++ > 60) {
end(1);
}
snakeMove();
}
public void keyTyped(KeyEvent e) {// 没用
}
@Override
public void keyPressed(KeyEvent e) {// 目标
if (!isStart) {
return;
}
int k = e.getKeyCode();// 不允许反向移动
boolean boo = true;
if (KeyEvent.VK_LEFT == k && headD != 4) {
boo = false;
left();
} else if (KeyEvent.VK_RIGHT == k && headD != 3) {
boo = false;
right();
} else if (KeyEvent.VK_UP == k && headD != 2) {
boo = false;
up();
} else if (KeyEvent.VK_DOWN == k && headD != 1) {
boo = false;
down();
}
if (boo) {
snakeMove();
} else {
snakeNext();
}
}
@Override
public void keyReleased(KeyEvent e) {// 没用
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("start")) {
btn.setText("结束游戏");
btn.setActionCommand("end");
start();
}
if (e.getActionCommand().equals("end")) {
btn.setText("开始游戏");
btn.setActionCommand("start");
end();
}
this.requestFocus();
}
}