本文为大家推荐了一款由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程序设计。