import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.*; //============================================= //Main Class //============================================= public class GreedSnake implements KeyListener { JFrame mainFrame; Canvas paintCanvas; JLabel label得分;//计分牌 SnakeModel snakeModel=null;// 蛇 public static final int canvasWidth=200; public static final int canvasHeight=300; public static final int nodeWidth=10; public static final int nodeHeight=10; //---------------------------------------------------------------------- //GreedSnake():初始化游戏界面 //---------------------------------------------------------------------- public GreedSnake() { //设置界面元素 mainFrame=new JFrame("贪吃蛇"); Container cp=mainFrame.getContentPane(); label得分=new JLabel("得分:"); cp.add(label得分,BorderLayout.NORTH); paintCanvas=new Canvas(); paintCanvas.setSize(canvasWidth+1,canvasHeight+1); paintCanvas.addKeyListener(this); cp.add(paintCanvas,BorderLayout.CENTER); JPanel panelButtom=new JPanel(); panelButtom.setLayout(new BorderLayout()); JLabel labelHelp;// 帮助信息 labelHelp=new JLabel("上下加速;",JLabel.CENTER); panelButtom.add(labelHelp,BorderLayout.NORTH); labelHelp=new JLabel("确认,R,S开始;",JLabel.CENTER); panelButtom.add(labelHelp,BorderLayout.CENTER); labelHelp=new JLabel("空格或者P暂停,卢奇",JLabel.CENTER); panelButtom.add(labelHelp,BorderLayout.SOUTH); cp.add(panelButtom,BorderLayout.SOUTH); mainFrame.addKeyListener(this); mainFrame.pack(); mainFrame.setResizable(false); mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainFrame.setVisible(true); begin(); } //---------------------------------------------------------------------- //keyPressed():按键检测 //---------------------------------------------------------------------- public void keyPressed(KeyEvent e) { int keyCode=e.getKeyCode(); if(snakeModel.running) switch(keyCode) { case KeyEvent.VK_UP: snakeModel.changeDirection(SnakeModel.UP); break; case KeyEvent.VK_DOWN: snakeModel.changeDirection(SnakeModel.DOWN); break; case KeyEvent.VK_LEFT: snakeModel.changeDirection(SnakeModel.LEFT); break; case KeyEvent.VK_RIGHT: snakeModel.changeDirection(SnakeModel.RIGHT); break; case KeyEvent.VK_ADD: case KeyEvent.VK_PAGE_UP: snakeModel.speedUp();// 加速 break; case KeyEvent.VK_SUBTRACT: case KeyEvent.VK_PAGE_DOWN: snakeModel.speedDown();// 减速 break; case KeyEvent.VK_SPACE: case KeyEvent.VK_P: snakeModel.changePauseState();// 暂停或继续 break; default: } //重新开始 if(keyCode==KeyEvent.VK_R || keyCode==KeyEvent.VK_S || keyCode==KeyEvent.VK_ENTER) { snakeModel.running=false; begin(); } } //---------------------------------------------------------------------- //keyReleased():空函数 //---------------------------------------------------------------------- public void keyReleased(KeyEvent e) { } //---------------------------------------------------------------------- //keyTyped():空函数 //---------------------------------------------------------------------- public void keyTyped(KeyEvent e) { } //---------------------------------------------------------------------- //repaint():绘制游戏界面(包括蛇和食物) //---------------------------------------------------------------------- void repaint() { Graphics g=paintCanvas.getGraphics(); //draw background g.setColor(Color.YELLOW); g.fillRect(0,0,canvasWidth,canvasHeight); //draw the snake g.setColor(Color.BLUE); LinkedList na=snakeModel.nodeArray; Iterator it=na.iterator(); while(it.hasNext()) { Node n=(Node)it.next(); drawNode(g,n); } // draw the food g.setColor(Color.RED); Node n=snakeModel.food; drawNode(g,n); update得分(); } //---------------------------------------------------------------------- //drawNode():绘画某一结点(蛇身或食物) //---------------------------------------------------------------------- private void drawNode(Graphics g,Node n) { g.fillRect(n.x*nodeWidth,n.y*nodeHeight,nodeWidth-1,nodeHeight-1); } //---------------------------------------------------------------------- //update得分():改变计分牌 //---------------------------------------------------------------------- public void update得分() { String s="得分: "+snakeModel.得分; label得分.setText(s); } //---------------------------------------------------------------------- //begin():游戏开始,放置贪吃蛇 //---------------------------------------------------------------------- void begin() { if(snakeModel==null||!snakeModel.running) { snakeModel=new SnakeModel(this,canvasWidth/nodeWidth, this.canvasHeight/nodeHeight); (new Thread(snakeModel)).start(); } } //---------------------------------------------------------------------- //main():主函数 //---------------------------------------------------------------------- public static void main(String[] args) { GreedSnake gs=new GreedSnake(); } } /************************************************************************** *要点分析: *1)数据结构:matrix[][]用来存储地图上面的信息,如果什么也没有设置为false, * 如果有食物或蛇,设置为true;nodeArray,一个LinkedList,用来保存蛇的每 * 一节;food用来保存食物的位置;而Node类是保存每个位置的信息。 *2)重要函数: * changeDirection(int newDirection) ,用来改变蛇前进的方向,而且只是 * 保存头部的前进方向,因为其他的前进方向已经用位置来指明了。 其中newDirection * 必须和原来的direction不是相反方向,所以相反方向的值用了同样的奇偶性。在测试 * 的时候使用了direction%2!=newDirection%2 进行判断。 * moveOn(),用来更新蛇的位置,对于当前方向,把头部位置进行相应改变。如果越界, * 结束;否则,检测是否遇到食物(加头部)或身体(结束);如果什么都没有,加上头部, * 去掉尾部。由于用了LinkedList数据结构,省去了相当多的麻烦。 *************************************************************************/ //---------------------------------------------------------------------- //Node:结点类 //---------------------------------------------------------------------- class Node { int x; int y; Node(int x,int y) { this.x=x; this.y=y; } } //---------------------------------------------------------------------- //SnakeModel:贪吃蛇模型 //---------------------------------------------------------------------- class SnakeModel implements Runnable { GreedSnake gs; boolean[][] matrix;// 界面数据保存在数组里 LinkedList nodeArray=new LinkedList(); Node food; int maxX;//最大宽度 int maxY;//最大长度 int direction=2;//方向 boolean running=false; int timeInterval=200;// 间隔时间(速度) double speedChangeRate=0.75;// 速度改变程度 boolean paused=false;// 游戏状态 int 得分=0; int countMove=0; // UP和DOWN是偶数,RIGHT和LEFT是奇数 public static final int UP=2; public static final int DOWN=4; public static final int LEFT=1; public static final int RIGHT=3; //---------------------------------------------------------------------- //GreedModel():初始化界面 //---------------------------------------------------------------------- public SnakeModel(GreedSnake gs,int maxX,int maxY) { this.gs=gs; this.maxX=maxX; this.maxY=maxY; matrix=new boolean[maxX][]; for(int i=0;i20 ? 10 : maxX/2; for(int i=0;i0 ? 得分Get : 10; countMove=0; 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; countMove++; return true; } } return false;//越界(撞到墙壁) } //---------------------------------------------------------------------- //run():贪吃蛇运动线程 //---------------------------------------------------------------------- public void run() { running=true; while(running) { try { Thread.sleep(timeInterval); }catch(Exception e) { break; } if(!paused) { if(moveOn())// 未结束 { gs.repaint(); } else//游戏结束 { JOptionPane.showMessageDialog(null,"你傻逼啊这么简单都会死", "傻逼",JOptionPane.INFORMATION_MESSAGE); break; } } } running=false; } //---------------------------------------------------------------------- //createFood():生成食物及放置地点 //---------------------------------------------------------------------- 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); } //---------------------------------------------------------------------- //speedUp():加快蛇运动速度 //---------------------------------------------------------------------- public void speedUp() { timeInterval*=speedChangeRate; } //---------------------------------------------------------------------- //speedDown():放慢蛇运动速度 //---------------------------------------------------------------------- public void speedDown() { timeInterval/=speedChangeRate; } //---------------------------------------------------------------------- //changePauseState(): 改变游戏状态(暂停或继续) //---------------------------------------------------------------------- public void changePauseState() { paused=!paused; } }