本文為大家推薦了一款由java實現經典小游戲:貪吃蛇,相信大家都玩過,如何實現的吶?
效果圖:
廢話不多說,直接奉上代碼:
1、
1
2
3
4
5
6
7
8
9
10
11
|
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(); } } |
2、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
package mvcTest; //SnakeControl.java import java.awt.event.KeyEvent; import java.awt.event.KeyListener; public class SnakeControl implements KeyListener{ SnakeModel model; public SnakeControl(SnakeModel model){ this .model = model; } public void keyPressed(KeyEvent e) { 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(); } } public void keyReleased(KeyEvent e) { } public void keyTyped(KeyEvent e) { } } |
3、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
package mvcTest; //SnakeModel.java 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; } } 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; } } |
4、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
package mvcTest; //SnakeView.java import javax.swing.*; import java.awt.*; import java.util.Iterator; import java.util.LinkedList; import java.util.Observable; import java.util.Observer; 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 ; public SnakeView(SnakeModel model, SnakeControl control) { this .model = model; this .control = control; mainFrame = new JFrame( "GreedSnake" ); Container cp = mainFrame.getContentPane(); // 創建頂部的分數顯示 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(); } } |
本文的目的就是帶著大家回味經典,但是更主要的目的就是幫助大家學習好java程序設計。