hello
// snakemodel package mvctest; import javax.swing.*; import java.util.Arrays; import java.util.LinkedList; import java.util.Observable; import java.util.Random; class snakemodel extends Observable implements Runnable { 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 score = 0; // 得分 int countmove = 0; // 吃到食物前移动的次数 // up and down should be even // right and left should be odd 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 snakemodel( int maxx, int maxy) { this.maxx = maxx; this.maxy = maxy; reset(); } public void reset(){ direction = snakemodel.up; // 蛇运行的方向 timeinterval = 200; // 时间间隔,毫秒 paused = false; // 暂停标志 score = 0; // 得分 countmove = 0; // 吃到食物前移动的次数 // initial matirx, 全部清0 matrix = new boolean[maxx][]; for (int i = 0; i < maxx; ++i) { matrix[i] = new boolean[maxy]; Arrays.fill(matrix[i], false); } // initial the snake // 初始化蛇体,如果横向位置超过20个,长度为10,否则为横向位置的一半 int initarraylength = maxx > 20 ? 10 : maxx / 2; nodearray.clear(); for (int i = 0; i < initarraylength; ++i) { int x = maxx / 2 + i;//maxx被初始化为20 int y = maxy / 2; //maxy被初始化为30 //nodearray[x,y]: [10,15]-[11,15]-[12,15]~~[20,15] //默认的运行方向向上,所以游戏一开始nodearray就变为: // [10,14]-[10,15]-[11,15]-[12,15]~~[19,15] 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; } } /** * 运行一次 * @return */ 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); // 从蛇头赠长 // 分数规则,与移动改变方向的次数和速度两个元素有关 int scoreget = (10000 - 200 * countmove) / timeinterval; score += scoreget > 0 ? scoreget : 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; // 触到边线,失败 } public void run() { running = true; while (running) { try { Thread.sleep(timeinterval); } catch (Exception e) { break; } if (!paused) { if (moveon()) { setChanged(); // model通知view数据已经更新 notifyObservers(); } else { JOptionPane.showMessageDialog(null, "you failed", "game over", JOptionPane.INFORMATION_MESSAGE); break; } } } running = false; } 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 void speedup() { timeinterval *= speedchangerate; } public void speeddown() { timeinterval /= speedchangerate; } public void changepausestate() { paused = !paused; } public String tostring() { String result = ""; for (int i = 0; i < nodearray.size(); ++i) { node n = (node) nodearray.get(i); result += "[" + n.x + "," + n.y + "]"; } return result; } } class node { int x; int y; node(int x, int y) { this.x = x; this.y = y; } } // snakeview package mvctest; import javax.swing.*; import java.awt.*; import java.util.Iterator; import java.util.LinkedList; import java.util.Observable; import java.util.Observer; /** * mvc模式中得viewer,只负责对数据的显示,而不用理会游戏的控制逻辑 */ public class snakeview implements Observer { snakecontrol control = null; snakemodel model = null; JFrame mainframe; Canvas paintcanvas; JLabel labelscore; public static final int canvaswidth = 200; public static final int canvasheight = 300; public static final int nodewidth = 10; public static final int nodeheight = 10; JMenuBar jMenuBar = new JMenuBar(); JMenu jMenu = new JMenu("menu"); JMenuItem reset = new JMenuItem("reset"); JMenuItem newgame = new JMenuItem("newgame"); public snakeview(snakemodel model, snakecontrol control) { this.model = model; this.control = control; mainframe = new JFrame("greedsnake"); Container cp = mainframe.getContentPane(); jMenuBar.add(jMenu); jMenu.add(reset); jMenu.add(newgame); // 创建顶部的分数显示 labelscore = new JLabel("score:"); cp.add(labelscore, BorderLayout.NORTH); // 创建中间的游戏显示区域 paintcanvas = new Canvas(); paintcanvas.setSize(canvaswidth + 1, canvasheight + 1); paintcanvas.addKeyListener(control); cp.add(paintcanvas, BorderLayout.CENTER); // 创建底下的帮助栏 JPanel panelbuttom = new JPanel(); panelbuttom.setLayout(new BorderLayout()); JLabel labelhelp; labelhelp = new JLabel("pageup, pagedown for speed;", JLabel.CENTER); panelbuttom.add(labelhelp, BorderLayout.NORTH); labelhelp = new JLabel("enter or r or s for start;", JLabel.CENTER); panelbuttom.add(labelhelp, BorderLayout.CENTER); labelhelp = new JLabel("space or p for pause", JLabel.CENTER); panelbuttom.add(labelhelp, BorderLayout.SOUTH); cp.add(panelbuttom, BorderLayout.SOUTH); mainframe.addKeyListener(control); mainframe.pack(); mainframe.setResizable(false); mainframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainframe.setVisible(true); } void repaint() { Graphics g = paintcanvas.getGraphics(); //draw background g.setColor(Color.white); g.fillRect(0, 0, canvaswidth, canvasheight); // draw the snake g.setColor(Color.black); LinkedList na = model.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 = model.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 = "score: " + model.score; labelscore.setText(s); } public void update(Observable o, Object arg) { repaint(); } } // snakecontrol package mvctest; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; /** * mvc中的controler,负责接收用户的操作,并把用户操作通知model */ public class snakecontrol implements KeyListener{ snakemodel model; public snakecontrol(snakemodel model){ this.model = model; } @Override public void keyPressed(KeyEvent e) { // TODO Auto-generated method stub int keycode = e.getKeyCode(); if (model.running){ // 运行状态下,处理的按键 switch (keycode) { case KeyEvent.VK_UP: model.changedirection(snakemodel.up); break; case KeyEvent.VK_DOWN: model.changedirection(snakemodel.down); break; case KeyEvent.VK_LEFT: model.changedirection(snakemodel.left); break; case KeyEvent.VK_RIGHT: model.changedirection(snakemodel.right); break; case KeyEvent.VK_ADD: case KeyEvent.VK_PAGE_UP: model.speedup(); break; case KeyEvent.VK_SUBTRACT: case KeyEvent.VK_PAGE_DOWN: model.speeddown(); break; case KeyEvent.VK_SPACE: case KeyEvent.VK_P: model.changepausestate(); break; default: } } // 任何情况下处理的按键,按键导致重新启动游戏 if (keycode == KeyEvent.VK_R || keycode == KeyEvent.VK_S || keycode == KeyEvent.VK_ENTER) { model.reset(); } } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } } // greedSnake package mvctest; public class greedSnake { public static void main(String[] args) { snakemodel model = new snakemodel(20,30); snakecontrol control = new snakecontrol(model); snakeview view = new snakeview(model,control); //添加一个观察者,让view成为model的观察者 model.addObserver(view); (new Thread(model)).start(); } }