最简单的4个java类就可以实现贪吃蛇:

main函数:

 1 package tcs;
 2 
 3 public class GreedSnake {
 4 
 5 
 6     public static void main(String[] args) {
 7 
 8         SnakeModel model = new SnakeModel(20,30);
 9         SnakeControl control = new SnakeControl(model);
10         SnakeView view = new SnakeView(model,control);
11         //添加一个观察者,让view成为model的观察者
12         model.addObserver(view);
13 
14         (new Thread(model)).start();
15 
16     }
17 
18 }

控制蛇的移动类:

 1 package tcs;
 2 
 3 import java.awt.event.KeyEvent;
 4 import java.awt.event.KeyListener;
 5 
 6 
 7 public class SnakeControl  implements KeyListener{
 8     SnakeModel model;
 9 
10     public SnakeControl(SnakeModel model){
11         this.model = model;
12     }
13 
14     public void keyPressed(KeyEvent e) {
15         int keyCode = e.getKeyCode();
16         if (model.running){                // 运行状态下,处理的按键
17             switch (keyCode) {
18             case KeyEvent.VK_UP:
19                 model.changeDirection(SnakeModel.UP);
20                 break;
21             case KeyEvent.VK_DOWN:
22                 model.changeDirection(SnakeModel.DOWN);
23                 break;
24             case KeyEvent.VK_LEFT:
25                 model.changeDirection(SnakeModel.LEFT);
26                 break;
27             case KeyEvent.VK_RIGHT:
28                 model.changeDirection(SnakeModel.RIGHT);
29                 break;
30             case KeyEvent.VK_ADD:
31             case KeyEvent.VK_PAGE_UP:
32                 model.speedUp();
33                 break;
34             case KeyEvent.VK_SUBTRACT:
35             case KeyEvent.VK_PAGE_DOWN:
36                 model.speedDown();
37                 break;
38             case KeyEvent.VK_SPACE:
39             case KeyEvent.VK_P:
40                 model.changePauseState();
41                 break;
42             default:
43             }
44         }
45 
46         // 任何情况下处理的按键,按键导致重新启动游戏
47         if (keyCode == KeyEvent.VK_R ||
48                 keyCode == KeyEvent.VK_S ||
49                 keyCode == KeyEvent.VK_ENTER) {
50             model.reset();
51         }
52     }
53 
54     public void keyReleased(KeyEvent e) {
55     }
56 
57     public void keyTyped(KeyEvent e) {
58     }
59 }

蛇实体类:

 

  1 package tcs;
  2 
  3 import javax.swing.*;
  4 import java.util.Arrays;
  5 import java.util.LinkedList;
  6 import java.util.Observable;
  7 import java.util.Random;
  8 
  9 
 10 class SnakeModel extends Observable implements Runnable {
 11     boolean[][] matrix;                         // 指示位置上有没蛇体或食物
 12     @SuppressWarnings("rawtypes")
 13     LinkedList nodeArray = new LinkedList();    // 蛇体
 14     Node food;
 15     int maxX;
 16     int maxY;
 17     int direction = 2;                          // 蛇运行的方向
 18     boolean running = false;                    // 运行状态
 19 
 20     int timeInterval = 50;                     // 时间间隔,毫秒
 21     double speedChangeRate = 0.75;              // 每次得速度变化率
 22     boolean paused = false;                     // 暂停标志
 23 
 24     int score = 0;                              // 得分
 25     int countMove = 0;                          // 吃到食物前移动的次数
 26 
 27     // UP and DOWN should be even
 28     // RIGHT and LEFT should be odd
 29     public static final int UP = 2;
 30     public static final int DOWN = 4;
 31     public static final int LEFT = 1;
 32     public static final int RIGHT = 3;
 33 
 34     public SnakeModel( int maxX, int maxY) {
 35         this.maxX = maxX;
 36         this.maxY = maxY;
 37 
 38         reset();
 39     }
 40 
 41     @SuppressWarnings("unchecked")
 42     public void reset(){
 43         direction = SnakeModel.UP;              // 蛇运行的方向
 44         timeInterval = 200;                     // 时间间隔,毫秒
 45         paused = false;                         // 暂停标志
 46         score = 0;                              // 得分
 47         countMove = 0;                          // 吃到食物前移动的次数
 48 
 49         // initial matirx, 全部清0
 50         matrix = new boolean[maxX][];
 51         for (int i = 0; i < maxX; ++i) {
 52             matrix[i] = new boolean[maxY];
 53             Arrays.fill(matrix[i], false);
 54         }
 55 
 56         // initial the snake
 57         // 初始化蛇体,如果横向位置超过20个,长度为10,否则为横向位置的一半
 58         int initArrayLength = maxX > 20 ? 10 : maxX / 2;
 59         nodeArray.clear();
 60         for (int i = 0; i < initArrayLength; ++i) {
 61             int x = maxX / 2 + i;//maxX被初始化为20
 62             int y = maxY / 2;    //maxY被初始化为30
 63             //nodeArray[x,y]: [10,15]-[11,15]-[12,15]~~[20,15]
 64             //默认的运行方向向上,所以游戏一开始nodeArray就变为:
 65             //       [10,14]-[10,15]-[11,15]-[12,15]~~[19,15]
 66             nodeArray.addLast(new Node(x, y));
 67             matrix[x][y] = true;
 68         }
 69 
 70         // 创建食物
 71         food = createFood();
 72         matrix[food.x][food.y] = true;
 73     }
 74 
 75     public void changeDirection(int newDirection) {
 76         // 改变的方向不能与原来方向同向或反向
 77         if (direction % 2 != newDirection % 2) {
 78             direction = newDirection;
 79         }
 80     }
 81 
 82 
 83     @SuppressWarnings("unchecked")
 84     public boolean moveOn() {
 85         Node n = (Node) nodeArray.getFirst();
 86         int x = n.x;
 87         int y = n.y;
 88 
 89         // 根据方向增减坐标值
 90         switch (direction) {
 91         case UP:
 92             y--;
 93             break;
 94         case DOWN:
 95             y++;
 96             break;
 97         case LEFT:
 98             x--;
 99             break;
100         case RIGHT:
101             x++;
102             break;
103         }
104 
105         // 如果新坐标落在有效范围内,则进行处理
106         if ((0 <= x && x < maxX) && (0 <= y && y < maxY)) {
107 
108             if (matrix[x][y]) {        // 如果新坐标的点上有东西(蛇体或者食物)
109                 if (x == food.x && y == food.y) {       // 吃到食物,成功
110                     nodeArray.addFirst(food);           // 从蛇头赠长
111 
112                     // 分数规则,与移动改变方向的次数和速度两个元素有关
113                     int scoreGet = (10000 - 200 * countMove) / timeInterval;
114                     score += scoreGet > 0 ? scoreGet : 10;
115                     countMove = 0;
116 
117                     food = createFood();                // 创建新的食物
118                     matrix[food.x][food.y] = true;      // 设置食物所在位置
119                     return true;
120                 } else                                  // 吃到蛇体自身,失败
121                     return false;
122 
123             } else {                 // 如果新坐标的点上没有东西(蛇体),移动蛇体
124                 nodeArray.addFirst(new Node(x, y));
125                 matrix[x][y] = true;
126                 n = (Node) nodeArray.removeLast();
127                 matrix[n.x][n.y] = false;
128                 countMove++;
129                 return true;
130             }
131         }
132         return false;                                   // 触到边线,失败
133     }
134 
135     public void run() {
136         running = true;
137         while (running) {
138             try {
139                 Thread.sleep(timeInterval);
140             } catch (Exception e) {
141                 break;
142             }
143 
144             if (!paused) {
145                 if (moveOn()) {
146                     setChanged();           // Model通知View数据已经更新
147                     notifyObservers();
148                 } else {
149                     JOptionPane.showMessageDialog(null,
150                             "you failed",
151                             "Game Over",
152                             JOptionPane.INFORMATION_MESSAGE);
153                     break;
154                 }
155             }
156         }
157         running = false;
158     }
159 
160     private Node createFood() {
161         int x = 0;
162         int y = 0;
163         // 随机获取一个有效区域内的与蛇体和食物不重叠的位置
164         do {
165             Random r = new Random();
166             x = r.nextInt(maxX);
167             y = r.nextInt(maxY);
168         } while (matrix[x][y]);
169 
170         return new Node(x, y);
171     }
172 
173     public void speedUp() {
174         timeInterval *= speedChangeRate;
175     }
176 
177     public void speedDown() {
178         timeInterval /= speedChangeRate;
179     }
180 
181     public void changePauseState() {
182         paused = !paused;
183     }
184 
185     public String toString() {
186         String result = "";
187         for (int i = 0; i < nodeArray.size(); ++i) {
188             Node n = (Node) nodeArray.get(i);
189             result += "[" + n.x + "," + n.y + "]";
190         }
191         return result;
192     }
193 }
194 
195 class Node {
196     int x;
197     int y;
198 
199     Node(int x, int y) {
200         this.x = x;
201         this.y = y;
202     }
203 }

图形界面:

  1 package tcs;
  2 import javax.swing.*;
  3 import java.awt.*;
  4 import java.util.Iterator;
  5 import java.util.LinkedList;
  6 import java.util.Observable;
  7 import java.util.Observer;
  8 
  9 
 10 public class SnakeView implements Observer {
 11     SnakeControl control = null;
 12     SnakeModel model = null;
 13 
 14     JFrame mainFrame;
 15     Canvas paintCanvas;
 16     JLabel labelScore;
 17 
 18     public static final int canvasWidth = 200;
 19     public static final int canvasHeight = 300;
 20 
 21     public static final int nodeWidth = 10;
 22     public static final int nodeHeight = 10;
 23 
 24     public SnakeView(SnakeModel model, SnakeControl control) {
 25         this.model = model;
 26         this.control = control;
 27 
 28         mainFrame = new JFrame("GreedSnake");
 29 
 30         Container cp = mainFrame.getContentPane();
 31 
 32         // 创建顶部的分数显示
 33         labelScore = new JLabel("Score:");
 34         cp.add(labelScore, BorderLayout.NORTH);
 35 
 36         // 创建中间的游戏显示区域
 37         paintCanvas = new Canvas();
 38         paintCanvas.setSize(canvasWidth + 1, canvasHeight + 1);
 39         paintCanvas.addKeyListener(control);
 40         cp.add(paintCanvas, BorderLayout.CENTER);
 41 
 42         // 创建底下的帮助栏
 43         JPanel panelButtom = new JPanel();
 44         panelButtom.setLayout(new BorderLayout());
 45         JLabel labelHelp;
 46         labelHelp = new JLabel("PageUp, PageDown for speed;", JLabel.CENTER);
 47         panelButtom.add(labelHelp, BorderLayout.NORTH);
 48         labelHelp = new JLabel("ENTER or R or S for start;", JLabel.CENTER);
 49         panelButtom.add(labelHelp, BorderLayout.CENTER);
 50         labelHelp = new JLabel("SPACE or P for pause", JLabel.CENTER);
 51         panelButtom.add(labelHelp, BorderLayout.SOUTH);
 52         cp.add(panelButtom, BorderLayout.SOUTH);
 53 
 54         mainFrame.addKeyListener(control);
 55         mainFrame.pack();
 56         mainFrame.setResizable(false);
 57         mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 58         mainFrame.setVisible(true);
 59     }
 60 
 61     @SuppressWarnings("rawtypes")
 62     void repaint() {
 63         Graphics g = paintCanvas.getGraphics();
 64 
 65         //draw background
 66         g.setColor(Color.WHITE);
 67         g.fillRect(0, 0, canvasWidth, canvasHeight);
 68 
 69         // draw the snake
 70         g.setColor(Color.BLACK);
 71         LinkedList na = model.nodeArray;
 72         Iterator it = na.iterator();
 73         while (it.hasNext()) {
 74             Node n = (Node) it.next();
 75             drawNode(g, n);
 76         }
 77 
 78         // draw the food
 79         g.setColor(Color.RED);
 80         Node n = model.food;
 81         drawNode(g, n);
 82 
 83         updateScore();
 84     }
 85 
 86     private void drawNode(Graphics g, Node n) {
 87         g.fillRect(n.x * nodeWidth,
 88                 n.y * nodeHeight,
 89                 nodeWidth - 1,
 90                 nodeHeight - 1);
 91     }
 92 
 93     public void updateScore() {
 94         String s = "Score: " + model.score;
 95         labelScore.setText(s);
 96     }
 97 
 98     public void update(Observable o, Object arg) {
 99         repaint();
100     }
101 }

 

版权声明:本文为xiayahui原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/xiayahui/p/5001036.html