大家好,我是百思不得小赵。
创作时间:2022 年 5 月 12 日
博客主页: ????点此进入博客主页
—— 新时代的农民工 ????
—— 换一种思维逻辑去看待这个世界 ????
今天是加入CSDN的第1167天。觉得有帮助麻烦????点赞、????评论、❤️收藏
目录
一、游戏背景
二、功能实现
三、效果展示
一、游戏背景
俄罗斯方块是俄罗斯人发明的。这人叫阿列克谢·帕基特诺夫(Алексей Пажитнов 英文:Alexey Pazhitnov)。俄罗斯方块原名是俄语Тетрис(英语是Tetris),这个名字来源于希腊语tetra,意思是“四”,而游戏的作者最喜欢网球(tennis)。于是,他把两个词tetra和tennis合而为一,命名为Tetris,这也就是俄罗斯方块名字的由来。
规则说明:
由小方块组成的不同形状的板块陆续从屏幕上方落下来,玩家通过调整板块的位置和方向,使它们在屏幕底部拼出完整的一条或几条。这些完整的横条会随即消失,给新落下来的板块腾出空间,与此同时,玩家得到分数奖励。没有被消除掉的方块不断堆积起来,一旦堆到屏幕顶端,玩家便告输,游戏结束。
二、功能实现
开发工具:idea、jdk8
技术汇总:Java基础知识、数组、面向对象、多线程、IO流、Swing。
整体代码分为三个模块:方格模块,七种图形模块,俄罗斯方块主模块。
小方块类:Cell
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
85public class Cell { // 行 private int row; // 列 private int col; private BufferedImage image; public Cell() { } public Cell(int row, int col, BufferedImage image) { this.row = row; this.col = col; this.image = image; } public int getRow() { return row; } public void setRow(int row) { this.row = row; } public int getCol() { return col; } public void setCol(int col) { this.col = col; } public BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } @Override public String toString() { return "Cell{" + "row=" + row + ", col=" + col + ", image=" + image + '}'; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Cell)) { return false; } Cell cell = (Cell) o; return getRow() == cell.getRow() && getCol() == cell.getCol() && Objects.equals(getImage(), cell.getImage()); } @Override public int hashCode() { return Objects.hash(getRow(), getCol(), getImage()); } //左移动一格 public void left(){ col--; } //右移动一格 public void right(){ col++; } //下移动一格 public void down(){ row++; } }
四方格图形的父类:Tetromino
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
200public class Tetromino { public Cell[] cells = new Cell[4]; //旋转的状态 protected State[] states; //声明旋转次数 protected int count = 10000; //左移方法 public void moveLeft() { for (Cell cell : cells) { cell.left(); } } //右移方法 public void moveRight() { for (Cell cell : cells) { cell.right(); } } //单元格下落 public void moveDrop() { for (Cell cell : cells) { cell.down(); } } //编写随机生成四方格 public static Tetromino randomOne() { int num = (int) (Math.random() * 7); Tetromino tetromino = null; switch (num) { case 0: tetromino = new I(); break; case 1: tetromino = new J(); break; case 2: tetromino = new L(); break; case 3: tetromino = new O(); break; case 4: tetromino = new S(); break; case 5: tetromino = new T(); break; case 6: tetromino = new Z(); break; } return tetromino; } //顺时针旋转的方法 public void rotateRight() { if (states.length == 0) { return; } //旋转次数+1 count++; State s = states[count % states.length]; Cell cell = cells[0]; int row = cell.getRow(); int col = cell.getCol(); cells[1].setRow(row + s.row1); cells[1].setCol(col + s.col1); cells[2].setRow(row + s.row2); cells[2].setCol(col + s.col2); cells[3].setRow(row + s.row3); cells[3].setCol(col + s.col3); } //逆时针旋转的方法 public void rotateLeft() { if (states.length == 0) { return; } //旋转次数+1 count--; State s = states[count % states.length]; Cell cell = cells[0]; int row = cell.getRow(); int col = cell.getCol(); cells[1].setRow(row + s.row1); cells[1].setCol(col + s.col1); cells[2].setRow(row + s.row2); cells[2].setCol(col + s.col2); cells[3].setRow(row + s.row3); cells[3].setCol(col + s.col3); } //四方格旋转状态的内部类 protected class State { //存储四方格各元素的位置 int row0, col0, row1, col1, row2, col2, row3, col3; public State() { } public State(int row0, int col0, int row1, int col1, int row2, int col2, int row3, int col3) { this.row0 = row0; this.col0 = col0; this.row1 = row1; this.col1 = col1; this.row2 = row2; this.col2 = col2; this.row3 = row3; this.col3 = col3; } public int getRow0() { return row0; } public void setRow0(int row0) { this.row0 = row0; } public int getCol0() { return col0; } public void setCol0(int col0) { this.col0 = col0; } public int getRow1() { return row1; } public void setRow1(int row1) { this.row1 = row1; } public int getCol1() { return col1; } public void setCol1(int col1) { this.col1 = col1; } public int getRow2() { return row2; } public void setRow2(int row2) { this.row2 = row2; } public int getCol2() { return col2; } public void setCol2(int col2) { this.col2 = col2; } public int getRow3() { return row3; } public void setRow3(int row3) { this.row3 = row3; } public int getCol3() { return col3; } public void setCol3(int col3) { this.col3 = col3; } @Override public String toString() { return "State{" + "row0=" + row0 + ", col0=" + col0 + ", row1=" + row1 + ", col1=" + col1 + ", row2=" + row2 + ", col2=" + col2 + ", row3=" + row3 + ", col3=" + col3 + '}'; } } }
七种图形类:I、J、L、O、S、T、Z
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class I extends Tetromino { public I() { cells[0] = new Cell(0,4, Tetris.I); cells[1] = new Cell(0,3, Tetris.I); cells[2] = new Cell(0,5, Tetris.I); cells[3] = new Cell(0,6, Tetris.I); //共有两种旋转状态 states =new State[2]; //初始化两种状态的相对坐标 states[0]=new State(0,0,0,-1,0,1,0,2); states[1]=new State(0,0,-1,0,1,0,2,0); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class J extends Tetromino { public J() { cells[0] = new Cell(0,4, Tetris.J); cells[1] = new Cell(0,3, Tetris.J); cells[2] = new Cell(0,5, Tetris.J); cells[3] = new Cell(1,5, Tetris.J); states=new State[4]; states[0]=new State(0,0,0,-1,0,1,1,1); states[1]=new State(0,0,-1,0,1,0,1,-1); states[2]=new State(0,0,0,1,0,-1,-1,-1); states[3]=new State(0,0,1,0,-1,0,-1,1); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class L extends Tetromino { public L() { cells[0] = new Cell(0,4, Tetris.L); cells[1] = new Cell(0,3, Tetris.L); cells[2] = new Cell(0,5, Tetris.L); cells[3] = new Cell(1,3, Tetris.L); states=new State[4]; states[0]=new State(0,0,0,-1,0,1,1,-1); states[1]=new State(0,0,-1,0,1,0,-1,-1); states[2]=new State(0,0,0,1,0,-1,-1,1); states[3]=new State(0,0,1,0,-1,0,1,1); } }
1
2
3
4
5
6
7
8
9
10
11public class O extends Tetromino { public O() { cells[0] = new Cell(0, 4, Tetris.O); cells[1] = new Cell(0, 5, Tetris.O); cells[2] = new Cell(1, 4, Tetris.O); cells[3] = new Cell(1, 5, Tetris.O); //无旋转状态 states = new State[0]; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class S extends Tetromino { public S() { cells[0] = new Cell(0,4, Tetris.S); cells[1] = new Cell(0,5, Tetris.S); cells[2] = new Cell(1,3, Tetris.S); cells[3] = new Cell(1,4, Tetris.S); //共有两种旋转状态 states =new State[2]; //初始化两种状态的相对坐标 states[0]=new State(0,0,0,1,1,-1,1,0); states[1]=new State(0,0,1,0,-1,-1,0,-1); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class T extends Tetromino { public T() { cells[0] = new Cell(0,4, Tetris.T); cells[1] = new Cell(0,3, Tetris.T); cells[2] = new Cell(0,5, Tetris.T); cells[3] = new Cell(1,4, Tetris.T); states=new State[4]; states[0]=new State(0,0,0,-1,0,1,1,0); states[1]=new State(0,0,-1,0,1,0,0,-1); states[2]=new State(0,0,0,1,0,-1,-1,0); states[3]=new State(0,0,1,0,-1,0,0,1); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class Z extends Tetromino { public Z() { cells[0] = new Cell(1,4, Tetris.Z); cells[1] = new Cell(0,3, Tetris.Z); cells[2] = new Cell(0,4, Tetris.Z); cells[3] = new Cell(1,5, Tetris.Z); //共有两种旋转状态 states =new State[2]; //初始化两种状态的相对坐标 states[0]=new State(0,0,-1,-1,-1,0,0,1); states[1]=new State(0,0,-1,1,0,1,1,0); } }
俄罗斯方块游戏主类:Tetris
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377public class Tetris extends JPanel { //正在下落的方块 private Tetromino currentOne = Tetromino.randomOne(); //将要下落的方块 private Tetromino nextOne = Tetromino.randomOne(); //游戏主区域 private Cell[][] wall = new Cell[18][9]; //声明单元格的值 private static final int CELL_SIZE = 48; //游戏分数池 int[] scores_pool = {0, 1, 2, 5, 10}; //当前游戏的分数 private int totalScore = 0; //当前消除的行数 private int totalLine = 0; //游戏三种状态 游戏中、暂停、结束 public static final int PLING = 0; public static final int STOP = 1; public static final int OVER = 2; //当前游戏状态值 private int game_state; //显示游戏状态 String[] show_state = {"P[pause]", "C[continue]", "S[replay]"}; //载入方块图片 public static BufferedImage I; public static BufferedImage J; public static BufferedImage L; public static BufferedImage O; public static BufferedImage S; public static BufferedImage T; public static BufferedImage Z; public static BufferedImage background; static { try { I = ImageIO.read(new File("images/I.png")); J = ImageIO.read(new File("images/J.png")); L = ImageIO.read(new File("images/L.png")); O = ImageIO.read(new File("images/O.png")); S = ImageIO.read(new File("images/S.png")); T = ImageIO.read(new File("images/T.png")); Z = ImageIO.read(new File("images/Z.png")); background = ImageIO.read(new File("images/background.png")); } catch (IOException e) { e.printStackTrace(); } } @Override public void paint(Graphics g) { g.drawImage(background, 0, 0, null); //平移坐标轴 g.translate(22, 15); //绘制游戏主区域 paintWall(g); //绘制正在下落的四方格 paintCurrentOne(g); //绘制下一个将要下落的四方格 paintNextOne(g); //绘制游戏得分 paintSource(g); //绘制当前游戏状态 paintState(g); } public void start() { game_state = PLING; KeyListener l = new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { int code = e.getKeyCode(); switch (code) { case KeyEvent.VK_DOWN: sortDropActive(); break; case KeyEvent.VK_LEFT: moveleftActive(); break; case KeyEvent.VK_RIGHT: moveRightActive(); break; case KeyEvent.VK_UP: rotateRightActive(); break; case KeyEvent.VK_SPACE: hadnDropActive(); break; case KeyEvent.VK_P: //判断当前游戏状态 if (game_state == PLING) { game_state = STOP; } break; case KeyEvent.VK_C: if (game_state == STOP) { game_state = PLING; } break; case KeyEvent.VK_S: //重新开始 game_state = PLING; wall = new Cell[18][9]; currentOne = Tetromino.randomOne(); nextOne = Tetromino.randomOne(); totalScore = 0; totalLine = 0; break; } } }; //将窗口设置为焦点 this.addKeyListener(l); this.requestFocus(); while (true) { if (game_state == PLING) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } if (camDrop()) { currentOne.moveDrop(); } else { landToWall(); destroyLine(); if (isGameOver()) { game_state = OVER; } else { //游戏没有结束 currentOne = nextOne; nextOne = Tetromino.randomOne(); } } } repaint(); } } //创建顺时针旋转 public void rotateRightActive() { currentOne.rotateRight(); if (outOFBounds() || coincide()) { currentOne.rotateLeft(); } } //瞬间下落 public void hadnDropActive() { while (true) { //判断能否下落 if (camDrop()) { currentOne.moveDrop(); } else { break; } } //嵌入到墙中 landToWall(); destroyLine(); if (isGameOver()) { game_state = OVER; } else { //游戏没有结束 currentOne = nextOne; nextOne = Tetromino.randomOne(); } } //按键一次,下落一格 public void sortDropActive() { if (camDrop()) { //当前四方格下落一格 currentOne.moveDrop(); } else { landToWall(); destroyLine(); if (isGameOver()) { game_state = OVER; } else { //游戏没有结束 currentOne = nextOne; nextOne = Tetromino.randomOne(); } } } //单元格嵌入墙中 private void landToWall() { Cell[] cells = currentOne.cells; for (Cell cell : cells) { int row = cell.getRow(); int col = cell.getCol(); wall[row][col] = cell; } } //判断四方格能否下落 public boolean camDrop() { Cell[] cells = currentOne.cells; for (Cell cell : cells) { int row = cell.getRow(); int col = cell.getCol(); //判断是否到达底部 if (row == wall.length - 1) { return false; } else if (wall[row + 1][col] != null) { return false; } } return true; } //消除行 public void destroyLine() { int line = 0; Cell[] cells = currentOne.cells; for (Cell cell : cells) { int row = cell.getRow(); if (isFullLine(row)) { line++; for (int i = row; i > 0; i--) { System.arraycopy(wall[i - 1], 0, wall[i], 0, wall[0].length); } wall[0] = new Cell[9]; } } //分数池获取分数,累加到总分 totalScore += scores_pool[line]; //总行数 totalLine += line; } //判断当前行是否已经满了 public boolean isFullLine(int row) { Cell[] cells = wall[row]; for (Cell cell : cells) { if (cell == null) { return false; } } return true; } //判断游戏是否结束 public boolean isGameOver() { Cell[] cells = nextOne.cells; for (Cell cell : cells) { int row = cell.getRow(); int col = cell.getCol(); if (wall[row][col] != null) { return true; } } return false; } private void paintState(Graphics g) { if (game_state == PLING) { g.drawString(show_state[PLING], 500, 660); } else if (game_state == STOP) { g.drawString(show_state[STOP], 500, 660); } else { g.drawString(show_state[OVER], 500, 660); g.setColor(Color.RED); g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 60)); g.drawString("GAME OVER!", 30, 400); } } private void paintSource(Graphics g) { g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 30)); g.drawString("分数: " + totalScore, 500, 250); g.drawString("行数: " + totalLine, 500, 430); } private void paintNextOne(Graphics g) { Cell[] cells = nextOne.cells; for (Cell cell : cells) { int x = cell.getCol() * CELL_SIZE + 370; int y = cell.getRow() * CELL_SIZE + 25; g.drawImage(cell.getImage(), x, y, null); } } private void paintCurrentOne(Graphics g) { Cell[] cells = currentOne.cells; for (Cell cell : cells) { int x = cell.getCol() * CELL_SIZE; int y = cell.getRow() * CELL_SIZE; g.drawImage(cell.getImage(), x, y, null); } } private void paintWall(Graphics g) { for (int i = 0; i < wall.length; i++) { for (int j = 0; j < wall[i].length; j++) { int x = j * CELL_SIZE; int y = i * CELL_SIZE; Cell cell = wall[i][j]; //判断是否有小方块 if (cell == null) { g.drawRect(x, y, CELL_SIZE, CELL_SIZE); } else { g.drawImage(cell.getImage(), x, y, null); } } } } //判断是否出界 public boolean outOFBounds() { Cell[] cells = currentOne.cells; for (Cell cell : cells) { int col = cell.getCol(); int row = cell.getRow(); if (row < 0 || row > wall.length - 1 || col < 0 || col > wall[0].length-1) { return true; } } return false; } //按键一次,左移一次 public void moveleftActive() { currentOne.moveLeft(); //判断是否越界或重合 if (outOFBounds() || coincide()) { currentOne.moveRight(); } } //按键一次,右移一次 public void moveRightActive() { currentOne.moveRight(); //判断是否越界或重合 if (outOFBounds() || coincide()) { currentOne.moveLeft(); } } //判断是否重合 public boolean coincide() { Cell[] cells = currentOne.cells; for (Cell cell : cells) { int row = cell.getRow(); int col = cell.getCol(); if (wall[row][col] != null) { return true; } } return false; } public static void main(String[] args) { JFrame jFrame = new JFrame("俄罗斯方块"); //创建游戏界面 Tetris panel = new Tetris(); jFrame.add(panel); //设置可见 jFrame.setVisible(true); //设置窗口大小 jFrame.setSize(810, 940); //设置剧中 jFrame.setLocationRelativeTo(null); //设置窗口关闭时停止 jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //游戏主要开始逻辑 panel.start(); } }
三、效果展示
游戏开始,方快下落,右边区域展示即将下落的方块图、分数、消除的行数以及游戏切换的状态。
按下空格键,方块瞬间下落, 按下P键游戏暂停,消除一行分数为1(此处由分数池进行控制)
按下C键游戏继续。
按下S键,游戏重新开始。
方块占满,游戏结束,此时可以按下S键重新开始游戏。
本次游戏中所使用的素材文件以及所有的源代码文件都已经同步到Github,小伙伴们点击下方链接直接获取。
Github链接地址:点击获取完整源代码,下载到本地即可运行https://github.com/xiaoZ-zhao/Tetris
Gitee地址:Tetris: 【开箱即用】使用Java实现俄罗斯方块,开发工具idea - Gitee.comhttps://gitee.com/xiaoZcode/Tetris/tree/master
最后
以上就是英俊枫叶最近收集整理的关于Java实现俄罗斯方块小游戏。(附完整源代码)一、游戏背景二、功能实现三、效果展示的全部内容,更多相关Java实现俄罗斯方块小游戏内容请搜索靠谱客的其他文章。
发表评论 取消回复