package zeng; public class Main { public static void main(String[] args){ new MyFrame(); } } package zeng; public class Node { int x; int y; public Node(int x, int y) { this.x = x; this.y = y; } } package zeng; import java.awt.BorderLayout; import java.awt.Canvas; import java.awt.Color; import java.awt.Container; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.Iterator; import java.util.LinkedList; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; public class MyFrame extends KeyAdapter implements ActionListener{ JFrame frame ; Canvas canvas; Container container; JLabel label; // 计分 Snake snake = null; // 蛇 public static final int DEFAULT_WIDTH = 800; // 界面宽 public static final int DEFAULT_HEIGHT = 600; // 界面高 public static final int nodeWidth = 10; // 结点宽 public static final int nodeHeight = 10; // 结点高 JMenuItem start = new JMenuItem("开始"); JMenuItem exit = new JMenuItem("退出"); JMenuItem paused = new JMenuItem("暂停/开始"); JMenuItem speedUp = new JMenuItem("加速"); JMenuItem speedDown = new JMenuItem("减速"); JMenuItem about = new JMenuItem("关于贪吃蛇"); JMenuBar menuBar; JMenu file; JMenu function; JMenu help; // 初始化游戏界面 public MyFrame() { // 设置界面 frame = new JFrame(); frame.setTitle("贪吃蛇"); frame.setLocation(200,200); container = frame.getContentPane(); label = new JLabel("分数:", JLabel.CENTER); container.add(label, BorderLayout.SOUTH); canvas = new Canvas(); canvas.setSize(DEFAULT_WIDTH-20, DEFAULT_HEIGHT-20); container.add(canvas, BorderLayout.CENTER); menuBar = new JMenuBar(); frame.setJMenuBar(menuBar); file = new JMenu("文件"); function = new JMenu("功能"); help = new JMenu("帮助"); file.add(start); start.addActionListener(this); file.add(exit); exit.addActionListener(this); function.add(paused); paused.addActionListener(this); function.add(speedUp); speedUp.addActionListener(this); function.add(speedDown); speedDown.addActionListener(this); help.add(about); about.addActionListener(this); menuBar.add(file); menuBar.add(function); menuBar.add(help); frame.addKeyListener(this); frame.pack(); frame.setResizable(false); // 窗口大小不能变化 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 窗口关闭方式 frame.setVisible(true); // 显示 begin(); // 开始游戏 } // 绘制游戏界面(包括蛇和食物) public void repaint(){ Graphics g = canvas.getGraphics(); // 背景 g.setColor(Color.LIGHT_GRAY); g.fillRect(0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT); // 蛇 g.setColor(Color.BLACK); LinkedList<Node> snakeNode = snake.nodeArray; Iterator<Node> it = snakeNode.iterator(); while (it.hasNext()) { Node n = (Node) it.next(); drawNode(g, n); } // 食物 g.setColor(Color.RED); Node n = snake.food; drawNode(g, n); updateScore(); } // 绘画某一结点(蛇身或食物) private void drawNode(Graphics g, Node n) { g.fillRect(n.x * nodeWidth, n.y * nodeHeight, nodeWidth - 1, nodeHeight - 1); } // 更新分数 public void updateScore() { String s = "分数:" + snake.score; label.setText(s); } // 游戏开始,放蛇 void begin() { if (snake == null || !snake.running) { snake = new Snake(this, DEFAULT_WIDTH / nodeWidth, DEFAULT_HEIGHT / nodeHeight); (new Thread(snake)).start(); } } // 菜单监听事件 @Override public void actionPerformed(ActionEvent e){ if(snake.running){ if(e.getSource() == start){ // 开始 snake.running = false; begin(); } else if(e.getSource() == exit){ // 退出 int select=JOptionPane.showConfirmDialog(null, "确认退出", "提示", JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE); if(select==JOptionPane.OK_OPTION){ System.exit(0); } } else if(e.getSource() == paused){ // 暂停/继续 snake.changePauseState(); } else if(e.getSource() == speedUp){ // 加速 snake.speedUp(); } else if(e.getSource() == speedDown){// 减速 snake.speedDown(); } else if(e.getSource() == about){ // 关于贪吃蛇 JOptionPane.showMessageDialog(null, "贪吃蛇\n"+"制作人:小曾 计本1501\n" +" 按上下左右键控制蛇的方向\n" +" 按‘+’或PageUp 加速 、按‘-’或PageDown加速\n" +" 按空格或p\t暂停/开始"); } } } // 键盘监听 public void keyPressed(KeyEvent e) { int keyCode = e.getKeyCode(); if (snake.running) switch (keyCode) { case KeyEvent.VK_UP: // 方向键:上 snake.changeDirection(Snake.UP); break; case KeyEvent.VK_DOWN: // 方向键:下 snake.changeDirection(Snake.DOWN); break; case KeyEvent.VK_LEFT: // 方向键:左 snake.changeDirection(Snake.LEFT); break; case KeyEvent.VK_RIGHT: // 方向键:右 snake.changeDirection(Snake.RIGHT); break; 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: // P键 snake.changePauseState(); // 暂停或继续 break; default: } // 重新开始(回车键、S键) if (keyCode == KeyEvent.VK_S || keyCode == KeyEvent.VK_ENTER) { snake.running = false; begin(); } } } package zeng; import java.util.Arrays; import java.util.LinkedList; import java.util.Random; import javax.swing.JOptionPane; public class Snake implements Runnable{ Node food; MyFrame myFrame; LinkedList<Node> nodeArray = new LinkedList<Node>(); int maxX; int maxY; boolean[][] matrix; int timeInterval = 200; int score = 0; boolean running = false; boolean paused = false; double speedChangeRate = 0.75; int direction = 2; public static final int UP = 2; public static final int DOWN = 4; public static final int LEFT = 1; public static final int RIGHT = 3; // 初始化界面 public Snake(MyFrame myFrame, int maxX, int maxY){ this.myFrame = myFrame; this.maxX = maxX; this.maxY = maxY; matrix = new boolean[maxX][]; for (int i = 0; i < maxX; ++i) { matrix[i] = new boolean[maxY]; Arrays.fill(matrix[i], false); } int initArrayLength = maxX > 20 ? 10 : maxX / 2; for (int i = 0; i < initArrayLength; ++i) { int x = maxX / 2 + i; int y = maxY / 2; nodeArray.addLast(new Node(x, y)); matrix[x][y] = true; } food = createFood(); matrix[food.x][food.y] = true; } // 改变方向 public void changeDirection(int newDirection) { if (direction % 2 != newDirection % 2) { direction = newDirection; } } // 生成食物和放置位置 private Node createFood() { int x = 0; int y = 0; do { Random r = new Random(); x = r.nextInt(maxX); y = r.nextInt(maxY); } while (matrix[x][y]); return new Node(x, y); } // 蛇移动 public boolean moveOn() { Node n = (Node) nodeArray.getFirst(); int x = n.x; int y = n.y; switch (direction) { case UP: y--; break; case DOWN: y++; break; case LEFT: x--; break; case RIGHT: x++; break; } if ((0 <= x && x < maxX) && (0 <= y && y < maxY)) { if (matrix[x][y]) { // 吃到食物或者撞到身体 if (x == food.x && y == food.y) { // 吃到食物 nodeArray.addFirst(food); // 在头部加上一结点 score += 10; food = createFood(); matrix[food.x][food.y] = true; return true; } else return false; // 撞到身体 } else { // 什么都没有碰到 nodeArray.addFirst(new Node(x, y)); // 加上头部 matrix[x][y] = true; n = (Node) nodeArray.removeLast(); // 去掉尾部 matrix[n.x][n.y] = false; return true; } } return false; // 越界(撞到墙壁) } // 蛇运动线程 public void run() { running = true; while (running) { try { Thread.sleep(timeInterval); } catch (Exception e) { break; } if (!paused) { if (moveOn()) { // 未结束 myFrame.repaint(); } else { // 游戏结束 JOptionPane.showMessageDialog(null, "GAME OVER", "Game Over", JOptionPane.INFORMATION_MESSAGE); break; } } } running = false; } // 加速 public void speedUp() { timeInterval *= speedChangeRate; } // 减速 public void speedDown() { timeInterval /= speedChangeRate; } // 暂停/继续 public void changePauseState() { paused = !paused; } }