贪吃蛇

package com.zjgs.swing;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Move {//小蛇或食物位置(方位)移动
int move_X;
int move_Y;
Move(int move_X, int move_Y) {//带参数构造方法进行初始化
   this.move_X = move_X;
   this.move_Y = move_Y;
}
}
class MoveOperate extends Observable implements Runnable {//小蛇和食物移动操作的类
public static final int LEFT = 1;//小蛇向左移动的标识
public static final int UP = 2;//小蛇向上运动的标识
public static final int RIGHT = 3;//小蛇向右运动的标识
public static final int DOWN = 4;//小蛇向下运动的标识
private boolean[][] isHave; //指示位置上是否有小蛇或食物
private LinkedList snake = new LinkedList();//声明小蛇的双链表集合
private Move aliment; //食物
private int move_Direction = LEFT;//小蛇移动的方向向左
private boolean running = false; // 运行状态
private int timeSpace = 300; //时间间隔
private double speedChange = 0.75; // 每次的速度变化率
private boolean paused = false; // 暂停标志
private int score = 0; //得分
private int moveCount = 0; //吃到食物前移动的次数
private int X;//横坐标
private int Y;//纵坐标
public MoveOperate(int X, int Y) {//带参数构造方法进行初始化
   this.X = X;
   this.Y = Y;
   resetGame();
}
public void run() {//实现Runnable接口必须实现的方法
   running = true;//标识设置为真
   while (running) {//根据标识进行循环
    try {
     Thread.sleep(timeSpace);//休眠0.3秒
    } catch (Exception e) {
     System.out.println("休眠出错:"+e.getMessage());
     break;//跳出循环
    }
    if (!paused) {//小蛇正在移动时
     if (move()) {
      setChanged();//更新界面数据
      notifyObservers();
     } else {//弹出对话框显示游戏结束
      JOptionPane.showMessageDialog(null, "你失败了!",
        "Game Over", JOptionPane.INFORMATION_MESSAGE);
      break;//跳出循环
     }
    }
   }
   if (!running) {//小蛇暂停或停止
    JOptionPane.showMessageDialog(null, "你停止了游戏",
      "Game Over", JOptionPane.INFORMATION_MESSAGE);
   }
}
public void resetGame() {//重置游戏
   move_Direction = MoveOperate.LEFT;//小蛇移动的方向向左
   timeSpace = 300;//时间间隔为0.3秒
   paused = false;//不暂停
   score = 0;
   moveCount = 0;//吃到食物前移动的次数为0
   isHave = new boolean[X][Y];//初始化小蛇活动的范围
   for (int i = 0; i < X; i++) {
    isHave[i] = new boolean[Y];
    Arrays.fill(isHave[i], false);//填充数据
   }
   int initLength = X > 20 ? 10 : X / 2;//初始化小蛇,如果横向位置超过20个,长度为10,否则为横向位置的一半
   snake.clear();
   int x = X / 2;//初始居中显示
   int y = Y / 2;
   for (int i = 0; i < initLength; i++) {
    snake.addLast(new Move(x, y));//添加蛇移动的位置
    isHave[x][y] = true;
    x++;
   }
   aliment = createAliment();//创建食物
   isHave[aliment.move_X][aliment.move_Y] = true;//在指定位置上有蛇或食物
}
public boolean move() {//蛇运行一步
   Move snakeHead = (Move) snake.getFirst();//获得蛇头的位置
   int headX = snakeHead.move_X;//获得蛇的横坐标
   int headY = snakeHead.move_Y;//获得蛇的纵坐标
   switch (move_Direction) {//分支循环判断蛇的运动
   case UP://向上移动
    headY--;//纵坐标减1
    break;//跳出支循环
   case DOWN://向下移动
    headY++;//纵坐标加1
    break;
   case LEFT://向左移动
    headX--;//横坐标减1
    break;
   case RIGHT://向上移动
    headX++;//横坐标加1
    break;
   }
   if ((0 <= headX && headX < X) && (0 <= headY && headY < Y)) {
    if (isHave[headX][headY]) {//如果指定位置有蛇或食物
     if (headX == aliment.move_X && headY == aliment.move_Y) {
      snake.addFirst(aliment);//蛇头增长表示吃到食物
      int scoreGet = (10000 - 200 * moveCount) / timeSpace;//分数与改变方向次数和速度有关
      score += scoreGet > 0 ? scoreGet : 10;
      moveCount = 0;
      aliment = createAliment(); //创建新的食物
      isHave[aliment.move_X][aliment.move_Y] = true;//设置食物所在位置
      return true;
     } else {
      return false;//小蛇吃到自己
     }
    } else {
     snake.addFirst(new Move(headX, headY));//添加小蛇的身体
     isHave[headX][headY] = true;
     snakeHead = (Move) snake.removeLast();//获得蛇头信息
     isHave[snakeHead.move_X][snakeHead.move_Y] = false;
     moveCount++;
     return true;
    }
   }
   return false;//碰到外壁失败
}
public void changeDirection(int dir) {//改变蛇运动的方向
   if (move_Direction % 2 != dir % 2) {//改变的方向不与原方向相同或相反
    move_Direction = dir;
   }
}
private Move createAliment() {// 创建食物
   int x = 0;
   int y = 0;
   do {
    Random r = new Random();//随机获取位置
    x = r.nextInt(X);
    y = r.nextInt(Y);
   } while (isHave[x][y]);
   return new Move(x, y);//返回食物的新位置
}
public void speedUp() {// 加速运行
   timeSpace *= speedChange;
}
public void speedDown() {// 减速运行
   timeSpace /= speedChange;
}
public void changePauseState() {// 改变暂停状态
   paused = !paused;
}
public boolean isRunning() {//判断是否运动
   return running;
}
public void setRunning(boolean running) {//设置运动标识
   this.running = running;
}
public LinkedList getMoveList() {//获得链表数据(蛇的身体)
   return snake;
}
public Move getAliment() {//获得食物
   return aliment;
}
public int getScore() {//获得得分
   return score;
}
}
class SnakeFrame extends JFrame implements Observer {//贪吃蛇的视图,MVC中的View
public static final int gridWidth = 10;//格子的宽度
public static final int gridHeight = 10;//格子的高度
private int gameWidth;//画面的宽度
private int gameHeight;//画面的高度
private int gameX = 0;//画面左上角横位置
private int startY = 0;//画面左上角纵坐标
JLabel score; //声明分数标签
Canvas canvas; //声明画布
public SnakeFrame() {//// 默认构造方法调用带参数的构造方法
   this(30, 40, 0, 0);
}
public SnakeFrame(int X, int Y) {// 带参数的构造方法进行初始化
   this(X, Y, 0, 0);
}
public SnakeFrame(int X, int Y, int startX, int startY) {// 带参数的构造方法进行初始化
   this.gameWidth = X * gridWidth;
   this.gameHeight = Y * gridHeight;
   this.gameX = startX;
   this.startY = startY;
   init();
}
private void init() {// 初始化游戏界面
   this.setTitle("贪吃的小蛇");//设置界面的标题
   this.setLocation(gameX, startY);//设置界面的位置(方位)
   Container cp = this.getContentPane();//获得一容器
   score = new JLabel("成绩:");
   cp.add(score, BorderLayout.SOUTH);//将成绩放在界面的南侧
   canvas = new Canvas();//创建中间的游戏显示区域
   canvas.setSize(gameWidth + 1, gameHeight + 1);//设置区域的大小
   cp.add(canvas, BorderLayout.CENTER);//区域放在界面的中间
   this.pack();//根据组件的最优尺寸来进行布局 
   this.setResizable(false);//窗体不能最小化
   this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置默认关闭操作
   this.setVisible(true);//可视
}
public void update(Observable observer, Object obj) {// 实现Observer接口定义的update方法
   MoveOperate operate = (MoveOperate)observer; //获取被监控的模型
   Graphics graphics = canvas.getGraphics();// 获得画笔
   graphics.setColor(Color.WHITE);//设置颜色为白色
   graphics.fillRect(0, 0, gameWidth, gameHeight);//填充一个矩形
   graphics.setColor(Color.BLACK);//重新设置颜色
   LinkedList list = operate.getMoveList();//获得蛇体
   Iterator it = list.iterator();
   while (it.hasNext()) {
    Move move = (Move) it.next();
    drawMove(graphics, move);//调用方法画方格
   }
   graphics.setColor(Color.RED);//设置颜色表示食物
   Move move = operate.getAliment();//获得食物
   drawMove(graphics, move);
   this.updateScore(operate.getScore());//更新成绩
}
private void drawMove(Graphics g, Move n) {//根据移动路径画格子
   g.fillRect(n.move_X * gridWidth, n.move_Y * gridHeight, gridWidth - 1,
     gridHeight - 1);//填充一个矩形
}
public void updateScore(int score) {//更新成绩
   String s = "成绩: " + score;
   this.score.setText(s);//设置成绩标签的值
}
}
class ControlSnake implements KeyListener {//控制蛇的运动
private MoveOperate snake; //贪吃的小蛇模型
private SnakeFrame frame; // 蛇的对象
private int X;//蛇移动区域横坐标
private int Y;//蛇移动区域纵坐标
public ControlSnake() {// 默认构造方法进行初始化
   this.X = 30;
   this.Y = 40;
}
public ControlSnake(int X, int Y) {// 带参数的构造方法进行初始化
   this();
   if ((10 < X) && (X < 200) && (10 < Y) && (Y < 200)) {//判断移动区域
    this.X = X;
    this.Y = Y;
   } else {
    System.out.println("初始化参数出错!");
   }
   initSnake();//调用初始化方法
}
private void initSnake() {// 初始化
   this.snake = new MoveOperate(X, Y); //创建蛇模型
   this.frame = new SnakeFrame(X, Y, 500, 200);
   this.snake.addObserver(this.frame); //为模型添加对象
   this.frame.addKeyListener(this); // 添加键盘事件
   (new Thread(this.snake)).start();//启动线程蛇运动
}
public void keyPressed(KeyEvent e) {// 键盘按下事件
   int keyCode = e.getKeyCode();
   if (snake.isRunning()) {// 只有在贪吃蛇处于运行状态下,才处理的按键事件
    switch (keyCode) {
    case KeyEvent.VK_ADD://按下数字键盘上的+ 
    case KeyEvent.VK_PAGE_UP://按下PageUp键
     snake.speedUp();
     break;
    case KeyEvent.VK_SUBTRACT://按下数字键盘上的-
    case KeyEvent.VK_PAGE_DOWN://按下PageDown
     snake.speedDown();
     break;
    case KeyEvent.VK_SPACE://按下空格键
    case KeyEvent.VK_P://按下PauseBreak
     snake.changePauseState();
     break;
    case KeyEvent.VK_UP://按下向上键
     snake.changeDirection(MoveOperate.UP);
     break;
    case KeyEvent.VK_DOWN://按下向下键
     snake.changeDirection(MoveOperate.DOWN);
     break;
    case KeyEvent.VK_LEFT://按下向左键
     snake.changeDirection(MoveOperate.LEFT);
     break;
    case KeyEvent.VK_RIGHT://按下向右键
     snake.changeDirection(MoveOperate.RIGHT);
     break;
    default:
    }
   }
   if (keyCode == KeyEvent.VK_F || keyCode == KeyEvent.VK_J
     || keyCode == KeyEvent.VK_ENTER) {//按下回车、F、J键开始游戏
    snake.resetGame();
   }
   if (keyCode == KeyEvent.VK_S) {//按下S键停止游戏
    snake.setRunning(false);
   }
}
public void keyReleased(KeyEvent e) {//键盘弹起事件
}
public void keyTyped(KeyEvent e) {//有字符被输入事件
}
}
public class SmallSnake {//操作实现小蛇吃食物的操作
public static void main(String[] args) {//java程序主入口处
   new ControlSnake(40,30);//实例化对象
}
}


你可能感兴趣的:(贪吃蛇)