修改:1、添加了菜单栏,并进行了监听
2、添加了通关的条件
3、添加了背景音乐(音频文件连接:http://yunpan.cn/cQjY4PzpkfSdz (提取码:2726))
4、美观了蛇身
class SnakeMain代码:
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class SnakeMain extends JFrame implements ActionListener {
private static JLabel scoreLabel;
private JButton stop,start;
static SnakeModel snake;
AudioClip snakeSong;
public static void main(String[] args) {
new SnakeMain();
}
public SnakeMain() {
super("贪吃蛇");
this.setBounds(300, 100, 400, 400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setResizable(false);
this.getContentPane().setBackground(Color.white);
JPanel p = new JPanel();
this.getContentPane().add(p, "North");
p.setBackground(Color.WHITE);
scoreLabel=new JLabel();
scoreLabel.setText("score:"+0);
stop = new JButton("stop");
start = new JButton("start");
//添加菜单
JMenuBar menuBar=new JMenuBar();
setJMenuBar(menuBar);
JMenu menuGame=new JMenu("GAMES");
menuBar.add(menuGame);
JMenuItem newGames=new JMenuItem("New");
JMenuItem JStop=new JMenuItem("Stop");
JMenuItem GoOn=new JMenuItem("GoOn");
JMenuItem Exit=new JMenuItem("Exit");
menuGame.add(newGames);
menuGame.insertSeparator(1);
menuGame.add(JStop);
menuGame.insertSeparator(10);
menuGame.add(GoOn);
menuGame.insertSeparator(20);
menuGame.add(Exit);
JMenu menuHlep=new JMenu("HELP");
menuBar.add(menuHlep);
JMenuItem regarding=new JMenuItem("Regarding");
menuHlep.add(regarding);
//添加音乐
new Thread(new Runnable() {
@Override
public void run() {
try {
snakeSong=Applet.newAudioClip(new URL("file:" + "image/snakeSongs/song1.wav"));
snakeSong.loop();
snakeSong.play();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
// 让这些组件丢失焦点
// scoreField.setFocusable(false);
stop.setFocusable(false);
start.setFocusable(false);
//添加组件到面板p
p.add(scoreLabel);
p.add(stop);
p.add(start);
snake = new SnakeModel(400);// 500为刷新时间
this.getContentPane().add(snake); // 把蛇加入到面板中 (蛇的运行范围:0<=x<=380
// 0<=y<=330)
Control control = new Control(snake); // 控制蛇
// 进行监听
stop.addActionListener(this);
start.addActionListener(this);
this.addKeyListener(control);
//菜单项加监听
newGames.addActionListener(this);
JStop.addActionListener(this);
GoOn.addActionListener(this);
Exit.addActionListener(this);
regarding.addActionListener(this);
// 显示
this.setVisible(true);
}
public static void re() { // 刷新分数框
scoreLabel.setText("score:" + SnakeModel.getScore());
if(SnakeModel.getScore()==100){
SnakeModel.stop();
int a=JOptionPane.showConfirmDialog(null, "Restart or Exit?!","Congratulations to patience!!!", JOptionPane.YES_NO_OPTION);
if(a==JOptionPane.OK_OPTION){
snake.reStart();
}else{
System.exit(0);
}
}
}
public static void gameOver() {// 游戏结束
// JOptionPane.showMessageDialog(null, "Game Over!!!ReStart?Please press R");
int a=JOptionPane.showConfirmDialog(null, "Restart or Exit?!", "Game Over!!!", JOptionPane.YES_NO_OPTION);
if(a==JOptionPane.OK_OPTION){
snake.reStart();
}else{
System.exit(0);
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == stop||e.getActionCommand().equals("Stop")) {
SnakeModel.stop();
}
if (e.getSource() == start||e.getActionCommand().equals("GoOn")) {
SnakeModel.start();
}
if(e.getActionCommand().equals("New")){
snake.reStart();
}
if(e.getActionCommand().equals("Exit")){
System.exit(0);
}
if(e.getActionCommand().equals("Regarding")){
JOptionPane.showConfirmDialog(null," BlogID:http://blog.csdn.net/xionghui2013 ","The APP", JOptionPane.YES_OPTION);
}
}
}
class SnakeModel 代码:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.Timer;
import cn.hncu.xh.Snake.snakePoint.point;
/*
* 思路: 利用动态数组装蛇模型,蛇身的点都只跟着蛇头(即:数组的第一个元素)动,
* 每 repaint()一次,就把动态数组里面的蛇全部数出来。
* 每吃一个食物时,就添加在蛇头,蛇头往后移动一步,然后蛇身跟着移动。
* 注意:在蛇吃到食物时,要避免捆绑!!!
*/
public class SnakeModel extends Canvas implements ActionListener {
private snakePoint[] snakePoint; // 装蛇的数组
private static Timer timer; // 定时器
private static int score = 0; // 分数
private int Dx, Dy;// 蛇头所在坐标
private int Px, Py; // 食物的坐标
static final int LEFT = 1;
static final int UP = 2;
static final int DOWN = 4;
static final int RIGHT = 3;
int direction = 4; // 初始方向为向下移动
boolean isFrist = true; // 控制第一个食物的位置
boolean isOne = true; // 控制每次刷新一次蛇只能按一次键盘
boolean food; // 控制没吃到一个食物才去刷新食物的坐标
public SnakeModel(int delay) {// 构造蛇模型
this.snakePoint = new snakePoint[600]; // 用来装蛇头
snakePoint[1] = new snakePoint(100, 100);// 画蛇头
// 使用定时器
timer = new Timer(delay, this);
}
public static int getScore() { // 获取分数
return score;
}
class snakePoint { // 蛇身(每条蛇由很多蛇身构成)
int x, y;
public snakePoint(int x, int y) {
this.x = x;
this.y = y;
}
snakePoint(snakePoint p) {
this.x = p.x;
this.y = p.y;
}
}
@Override
public void paint(Graphics g) {
// 食物
creatFood();
// 每走一次就让数组自动移动一次
if (score != 0) {
for (int i = score + 2; i > 1; i--) {
snakePoint[i] = new snakePoint(snakePoint[i - 1]);
}
}
switch (direction) {// 判断蛇头的走向
case UP:
snakePoint[1].y -= 10;
break;
case DOWN:
snakePoint[1].y += 10;
break;
case LEFT:
snakePoint[1].x -= 10;
break;
case RIGHT:
snakePoint[1].x += 10;
break;
}
// 吃到了食物
// 要考虑食物的坐标不可能与蛇头坐标重合
if (snakePoint[1].x <= Px + 7 && snakePoint[1].x >= Px - 5
&& snakePoint[1].y <= Py + 7 && snakePoint[1].y >= Py - 5) {
score++; // 分数加一
food = true; // 刷新食物
SnakeMain.re(); // 刷新分数
timer.setDelay((timer.getDelay() - 4) <= 0 ? 20
: timer.getDelay() - 4); // 每次吃到食物后就会加速蛇的移动速度
// System.out.println(timer.getDelay());
// 吃掉一个食物后,在蛇头增加一个长度
for (int j = score + 1; j > 1; j--) {
snakePoint[j] = new snakePoint(snakePoint[j - 1]);
}
// 让蛇头往移动方向走一步
switch (direction) {// 判断蛇头的走向
case UP:
this.snakePoint[1].y -= 10;
break;
case DOWN:
this.snakePoint[1].y += 10;
break;
case LEFT:
this.snakePoint[1].x -= 10;
break;
case RIGHT:
this.snakePoint[1].x += 10;
break;
}
}
g.setColor(Color.RED);// 食物为红色
g.fill3DRect(Px, Py, 10, 10,true);// 画食物
g.setColor(Color.black);
g.draw3DRect(Px, Py, 10, 10,true);
// 画蛇,把蛇从数组中画出来
for (int i = 1; i <= score + 1; i++) {
g.setColor(Color.GREEN);
g.fill3DRect(snakePoint[i].x, snakePoint[i].y, 10, 10, true);
g.setColor(Color.blue);
g.draw3DRect(snakePoint[i].x, snakePoint[i].y, 10, 10, true);
// g.fillRect(snakePoint[i].x, snakePoint[i].y, 10, 10);
}
}
private void creatFood() {
if (isFrist) {
Px = legal(380);// 获得合法的x值,
Py = legal(300);// 获得合法的y值,即与x组合成食物坐标后不在蛇身上
isFrist = false;
return;
}
// 下一个食物坐标
if (food) {
Px = legal(380);// 同上
Py = legal(300);
food = false;
}
// System.out.println(Px);
// System.out.println(Py);
}
private int legal(int i) {
Random r = new Random(); // 生成随机数
if (i == 380) { // 生成食物的y坐标
while (true) {
int n = (r.nextInt(37) + 1) * 10;
for (int j = 1; j <= score + 1; j++) { // 每次都要与蛇身进行匹配,避免食物出现在蛇身上;下同
if (snakePoint[j].x != n && j == (score + 1)) {
return n;
}
}
}
}
if (i == 300) { // 生成食物的x坐标
while (true) {
int n = (r.nextInt(29) + 1) * 10;
for (int j = 1; j <= score + 1; j++) {
if (snakePoint[j].y != n && j == (score + 1)) {
return n;
}
}
}
}
return 0;
}
@Override
public void actionPerformed(ActionEvent e) {
isOver();// 判断是否结束游戏
repaint();
isOne = true;
// System.out.println(snakePoint[1].x+" "+snakePoint[1].y);
}
private void isOver() {
if (isCondition()) {// isCondition()//判断是否结束的所有条件放在里面
timer.stop();
SnakeMain.gameOver(); // 游戏结束,弹出对话框
}
}
private boolean isCondition() { // 游戏结束的条件
// 出界(撞墙)
if (snakePoint[1].x <= 0 || snakePoint[1].x >= 380
|| snakePoint[1].y <= 0 || snakePoint[1].y >= 300) {
return true;
}
// 蛇头吃到蛇身了
for (int i = 2; i <= score + 1; i++) {
if (snakePoint[1].x == snakePoint[i].x
&& snakePoint[1].y == snakePoint[i].y) {
return true;
}
}
return false;
}
public void changeDirection(int newDirection) { // 改变方向
if (direction % 2 != newDirection % 2 && isOne) {// 改变的方向不能与原来的方向相同或相反
direction = newDirection;
isOne = false;
}
}
public static void stop() {
timer.stop();
}
public static void start() {
timer.start();
}
// 重置所有的数据
public void reStart() {
score = 0;
SnakeMain.re();
direction = 4;
isFrist = true;
isOne = true;
food = false;
// snakePoint=null;
snakePoint[1].x = 100;
snakePoint[1].y = 100;
creatFood();
}
}
class Control代码:
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Control implements KeyListener { //对键盘进行监听
SnakeModel snake=null;
public Control(SnakeModel snake) {
this.snake=snake;
}
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_UP){
snake.changeDirection(SnakeModel.UP);
}
if(e.getKeyCode()==KeyEvent.VK_DOWN){ //监听按键↓,向下移动
snake.changeDirection(SnakeModel.DOWN);
}
if(e.getKeyCode()==KeyEvent.VK_LEFT){ //监听按键←,向左移动
snake.changeDirection(SnakeModel.LEFT);
}
if(e.getKeyCode()==KeyEvent.VK_RIGHT){ //监听按键↑,向上移动
snake.changeDirection(SnakeModel.RIGHT);
}
if(e.getKeyCode()==KeyEvent.VK_RIGHT){ //监听按键→,向右移动
snake.changeDirection(SnakeModel.RIGHT);
}
// if(e.getKeyCode()==KeyEvent.VK_R){//监听按键R,重置
// snake.reStart();
// }
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {}
}