本文實例為大家分享了Android實現(xiàn)俄羅斯方塊的具體代碼,供大家參考,具體內(nèi)容如下
思路:
- 首先要畫出游戲背景墻;
- 其次,要有方塊,以及方塊單元;
- 方塊的不同形狀,顏色隨機產(chǎn)生;
- 游戲的控制面板。
可能會出現(xiàn)的問題或者難點:
邊界問題:
①處于邊界的時候,方塊不可以再左右移動;
②下降的時候,到達邊界即底部,則不可繼續(xù)下落,此時應該產(chǎn)生一個新的方塊;
與其它方塊接觸問題:
①下落的時候,如果碰到其它的方塊則停止下落;
②左右移動的時候,移動的過程中,如果接觸到其他方快,則不可再繼續(xù)左右移動;
方塊的消除:
①調(diào)用方塊消除方法的時間:當方塊下落到底部的時候,判斷是否有需要消除的行;
②消除某一行之后,應該把這一行上面的全部方塊下移一行;
方塊的旋轉:
在當前項目中,我采用的是順時針旋轉。
①當旋轉的時候,如果出現(xiàn)方塊部分超出了邊界,應該對方塊進行平移,使其回到邊界以內(nèi)。(曾在網(wǎng)上看到有人做過,判斷旋轉之后是否會超出邊界,如果會超出,則不進行旋轉,我覺得不好,方塊只要沒有下落到底部,我覺得都可以進行旋轉,除了沒有空間讓其旋轉外);
②如果空間不足以旋轉,也不可以旋轉。空間不足以旋轉的意思是:比如橫向方向只有兩個的空間,而方塊旋轉后會占用三個空間,此時也不可進行旋轉;
③當無法繼續(xù)下落或者下落到了底部也不可再進行旋轉
控制面板:
①游戲開始、暫停、繼續(xù)、結束,這些狀態(tài)應該怎么去控制,以及游戲與控制臺的事件關聯(lián)。
未發(fā)現(xiàn)的問題:
因為本人能力,只做到這么多,如果有人發(fā)現(xiàn)問題,可以留言交流,歡迎挑問題。
游戲的運行界面如下所示,基本的功能以及操作很簡單。
下面直接看項目代碼
項目文件結構
下面分別介紹每個類的功能
TetrisViewAW.java游戲的主界面,背景墻以及方塊都在此TetrisViewAW.Java里面,就是一個自定義的View ,(默認大家對于自定義View是熟悉的),在改類里面,有一個游戲主線程,用于控制游戲的開始,暫停,繼續(xù),停止,以及方塊下落的速率。代碼我加了很多注釋,看不懂的可以留言。還有一點需要注意,當停止游戲時,要釋放線程,養(yǎng)成好習慣
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
|
/** * 俄羅斯方塊Game主界面 * * @sign Created by wang.ao on 2017年1月12日 */ @SuppressLint ( "DrawAllocation" ) public class TetrisViewAW extends View { /** 網(wǎng)格開始坐標值,橫縱坐標的開始值都是此值 */ public static final int beginPoint = 10 ; /** 俄羅斯方塊的最大坐標 */ private static int max_x, max_y; /** 行數(shù)和列數(shù) */ private static int num_x = 0 , num_y = 0 ; /** 背景墻畫筆 */ private static Paint paintWall = null ; /** 俄羅斯方塊的單元塊畫筆 */ private static Paint paintBlock = null ; private static final int BOUND_WIDTH_OF_WALL = 2 ; /** 當前正在下落的方塊 */ private List<BlockUnit> blockUnits = new ArrayList<BlockUnit>(); /** 下一個要顯示的方塊 */ private List<BlockUnit> blockUnitBufs = new ArrayList<BlockUnit>(); /** 下一個要顯示的方塊 */ private List<BlockUnit> routeBlockUnitBufs = new ArrayList<BlockUnit>(); /** 全部的方塊allBlockUnits */ private List<BlockUnit> allBlockUnits = new ArrayList<BlockUnit>(); /** 調(diào)用此對象的Activity對象 */ private TetrisActivityAW father = null ; private int [] map = new int [ 100 ]; // 保存每行網(wǎng)格中包含俄羅斯方塊單元的個數(shù) /** 游戲的主線程 */ private Thread mainThread = null ; // 游戲的幾種狀態(tài) /** 標識游戲是開始還是停止 */ private boolean gameStatus = false ; /** 標識游戲是暫停還是運行 */ private boolean runningStatus = false ; /** 俄羅斯方塊顏色數(shù)組 */ private static final int color[] = { Color.parseColor( "#FF6600" ), Color.BLUE, Color.RED, Color.GREEN, Color.GRAY }; /** 方塊的中心方塊單元的坐標, */ private int xx, yy; /** 方塊,用戶隨機獲取各種形狀的方塊 */ private TetrisBlock tetrisBlock; /** 分數(shù) */ private int score = 0 ; /** 當前方塊的類型 */ private int blockType = 0 ; public TetrisViewAW(Context context) { this (context, null ); } public TetrisViewAW(Context context, AttributeSet attrs) { super (context, attrs); if (paintWall == null ) { // 初始化化背景墻畫筆 paintWall = new Paint(); paintWall.setColor(Color.LTGRAY); paintWall.setStyle(Paint.Style.STROKE); paintWall.setStrokeWidth(BOUND_WIDTH_OF_WALL + 1 ); } if (paintBlock == null ) { // 初始化化背景墻畫筆 paintBlock = new Paint(); paintBlock.setColor(Color.parseColor( "#FF6600" )); } tetrisBlock = new TetrisBlock(); routeBlockUnitBufs = tetrisBlock.getUnits(beginPoint, beginPoint); Arrays.fill(map, 0 ); // 每行網(wǎng)格中包含俄羅斯方塊單元的個數(shù)全部初始化為0 // 繪制方塊 } /** * 設置當前游戲頁面的父類activity * * @param tetrisActivityAW */ public void setFather(TetrisActivityAW tetrisActivityAW) { father = tetrisActivityAW; } @Override protected void onDraw(Canvas canvas) { super .onDraw(canvas); max_x = getWidth(); max_y = getHeight(); RectF rel; // 繪制網(wǎng)格 num_x = 0 ; num_y = 0 ; for ( int i = beginPoint; i < max_x - BlockUnit.UNIT_SIZE; i += BlockUnit.UNIT_SIZE) { for ( int j = beginPoint; j < max_y - BlockUnit.UNIT_SIZE; j += BlockUnit.UNIT_SIZE) { rel = new RectF(i, j, i + BlockUnit.UNIT_SIZE, j + BlockUnit.UNIT_SIZE); canvas.drawRoundRect(rel, 8 , 8 , paintWall); num_y++; } num_x++; } // 隨機產(chǎn)生一個俄羅斯方塊 int len = blockUnits.size(); // 繪制方塊 // Toast.makeText(context, "" + len, Toast.LENGTH_SHORT).show(); for ( int i = 0 ; i < len; i++) { int x = blockUnits.get(i).x; int y = blockUnits.get(i).y; // 設置當前方塊的顏色 paintBlock.setColor(color[blockUnits.get(i).color]); rel = new RectF(x + BOUND_WIDTH_OF_WALL, y + BOUND_WIDTH_OF_WALL, x + BlockUnit.UNIT_SIZE - BOUND_WIDTH_OF_WALL, y + BlockUnit.UNIT_SIZE - BOUND_WIDTH_OF_WALL); canvas.drawRoundRect(rel, 8 , 8 , paintBlock); } // 隨機產(chǎn)生一個俄羅斯方塊 len = allBlockUnits.size(); // 繪制方塊 // Toast.makeText(context, "" + len, Toast.LENGTH_SHORT).show(); for ( int i = 0 ; i < len; i++) { int x = allBlockUnits.get(i).x; int y = allBlockUnits.get(i).y; paintBlock.setColor(color[allBlockUnits.get(i).color]); rel = new RectF(x + BOUND_WIDTH_OF_WALL, y + BOUND_WIDTH_OF_WALL, x + BlockUnit.UNIT_SIZE - BOUND_WIDTH_OF_WALL, y + BlockUnit.UNIT_SIZE - BOUND_WIDTH_OF_WALL); canvas.drawRoundRect(rel, 8 , 8 , paintBlock); } } /** * 開始游戲 */ public void startGame() { gameStatus = true ; runningStatus = true ; if (mainThread == null || !mainThread.isAlive()) { getNewBlock(); mainThread = new Thread( new MainThread()); mainThread.start(); } } /** * 暫停游戲 */ public void pauseGame() { runningStatus = false ; } /** * 繼續(xù)游戲 */ public void continueGame() { runningStatus = true ; } /** * 停止游戲 */ public void stopGame() { // 停止游戲,釋放游戲主線程 runningStatus = false ; gameStatus = false ; mainThread.interrupt(); blockUnits.clear(); allBlockUnits.clear(); score = 0 ; invalidate(); } /** * 向左滑動 */ public void toLeft() { if (BlockUnit.toLeft(blockUnits, max_x, allBlockUnits)) { xx = xx - BlockUnit.UNIT_SIZE; } invalidate(); } /** * 向右滑動 */ public void toRight() { if (BlockUnit.toRight(blockUnits, max_x, allBlockUnits)) { xx = xx + BlockUnit.UNIT_SIZE; } invalidate(); } /** * 按順時針旋轉 */ public void route() { if (blockType == 3 ) { // 如果當前正在下落的方塊為正方形,則不進行旋轉 return ; } if (routeBlockUnitBufs.size() != blockUnits.size()) { routeBlockUnitBufs = tetrisBlock.getUnits(xx, yy); } for ( int i = 0 ; i < blockUnits.size(); i++) { routeBlockUnitBufs.get(i).x = blockUnits.get(i).x; routeBlockUnitBufs.get(i).y = blockUnits.get(i).y; } for (BlockUnit blockUnit : routeBlockUnitBufs) { int tx = blockUnit.x; int ty = blockUnit.y; blockUnit.x = -(ty - yy) + xx; blockUnit.y = tx - xx + yy; } routeTran(routeBlockUnitBufs); if (!BlockUnit.canRoute(routeBlockUnitBufs, allBlockUnits)) { // Toast.makeText(father, "不可旋轉", Toast.LENGTH_SHORT).show(); return ; } for (BlockUnit blockUnit : blockUnits) { int tx = blockUnit.x; int ty = blockUnit.y; blockUnit.x = -(ty - yy) + xx; blockUnit.y = tx - xx + yy; } routeTran(blockUnits); invalidate(); } /** * 如果方塊處于邊緣,則翻轉過后,會出現(xiàn)方塊部分處于邊緣之外的情況, 因此,通過遞歸判斷是否有超出邊緣的部分, * 如果有,則進行左右平移,把處于邊緣外的方塊移動到邊緣內(nèi) */ public void routeTran(List<BlockUnit> blockUnitsBuf) { boolean needLeftTran = false ; boolean needRightTran = false ; for (BlockUnit u : blockUnitsBuf) { if (u.x < beginPoint) { needLeftTran = true ; } if (u.x > max_x - BlockUnit.UNIT_SIZE) { needRightTran = true ; } } if (needLeftTran || needRightTran) { for (BlockUnit u : blockUnitsBuf) { if (needLeftTran) { u.x = u.x + BlockUnit.UNIT_SIZE; } else if (needRightTran) { u.x = u.x - BlockUnit.UNIT_SIZE; } } routeTran(blockUnitsBuf); } else { return ; } } /** * 獲取一個新的方塊 */ private void getNewBlock() { // 新的方塊的坐標,x坐標位于x軸的中間,y 位于起始位置 this .xx = beginPoint + (num_x / 2 ) * BlockUnit.UNIT_SIZE; this .yy = beginPoint; if (blockUnitBufs.size() == 0 ) { // 當游戲第一次開始的時候,先初始化一個方塊 blockUnitBufs = tetrisBlock.getUnits(xx, yy); } blockUnits = blockUnitBufs; blockType = tetrisBlock.blockType; blockUnitBufs = tetrisBlock.getUnits(xx, yy); if (father != null ) { // 顯示出下一個要出現(xiàn)的方塊 father.setNextBlockView(blockUnitBufs, (num_x / 2 ) * BlockUnit.UNIT_SIZE); } } /** * 游戲的主線程 * * @sign Created by wang.ao on 2017年1月16日 */ private class MainThread implements Runnable { @Override public void run() { while (gameStatus) { while (runningStatus) { if (BlockUnit.canMoveToDown(blockUnits, max_y, allBlockUnits)) { // 判斷是否可以繼續(xù)下落,如果可以下落,則下落 BlockUnit.toDown(blockUnits, max_y, allBlockUnits); yy = yy + BlockUnit.UNIT_SIZE; } else { /** * 當不可以繼續(xù)下落的時候,把當前的方塊添加到allBlockUnits中, * 并且判斷是否有需要消除的方塊,然后再產(chǎn)生一個新的方塊 */ for (BlockUnit blockUnit : blockUnits) { blockUnit.y = blockUnit.y + BlockUnit.UNIT_SIZE; allBlockUnits.add(blockUnit); } for (BlockUnit u : blockUnits) { // 更新map,即更新每行網(wǎng)格中靜止俄羅斯方塊單元的個數(shù) int index = ( int ) ((u.y - beginPoint) / 50 ); // 計算所在行數(shù) map[index]++; } // 每行最大個數(shù) int end = ( int ) ((max_y - 50 - beginPoint) / BlockUnit.UNIT_SIZE); int full = ( int ) ((max_x - 50 - beginPoint) / BlockUnit.UNIT_SIZE) + 1 ; try { Thread.sleep(GameConfig.SPEED); } catch (InterruptedException e) { e.printStackTrace(); } for ( int i = 0 ; i <= end; i++) { /*** * 消除需要消除的方塊(觸發(fā)條件,某一行中被塞滿了方塊,沒有空白) * 注意順序,先消除某一行,再移動這一行上邊的方塊 */ if (map[i] >= full) { BlockUnit.remove(allBlockUnits, i); score += 100 ; map[i] = 0 ; for ( int j = i; j > 0 ; j--) map[j] = map[j - 1 ]; map[ 0 ] = 0 ; for (BlockUnit blockUnit : allBlockUnits) { if (blockUnit.y < (i * BlockUnit.UNIT_SIZE + beginPoint)) { blockUnit.y = blockUnit.y + BlockUnit.UNIT_SIZE; } } } } father.runOnUiThread( new Runnable() { @Override public void run() { /** * 刷新分數(shù) */ father.score.setText( "" + score); invalidate(); } }); try { Thread.sleep(GameConfig.SPEED * 3 ); } catch (InterruptedException e) { e.printStackTrace(); } father.runOnUiThread( new Runnable() { @Override public void run() { getNewBlock(); score += 10 ; father.score.setText( "" + score); } }); } father.runOnUiThread( new Runnable() { @Override public void run() { invalidate(); } }); try { Thread.sleep(GameConfig.SPEED); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } |
BlockUnit.java方塊的單元塊,大家都玩過俄羅斯方塊,每一個方塊由四個單元塊組成。單元快應該有以下屬性:①大小:單元塊的大小決定了主界面的容量(容納單元塊的數(shù)量);②顏色:每個單元塊都有一個顏色,美化游戲界面(可無);③坐標:包括X軸坐標、Y軸坐標,在繪制方塊的時候,以單元塊的坐標為起點繪制,即:單元塊的坐標值應該為單元塊在界面上的左上角的坐標。
此類的主要功能有:方塊的下落,左右移動,判斷是否可以旋轉等功能都在此類中,算是核心類。
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
|
/** * 俄羅斯方塊的單元快 * * @sign Created by wang.ao on 2017年1月13日 */ public class BlockUnit { public static final int UNIT_SIZE = 50 ; public static final int BEGIN = 10 ; public int color; // 單元塊 的坐標 public int x, y; public BlockUnit() { } public BlockUnit( int x, int y, int color) { /* * @param 單元塊橫縱坐標 構造函數(shù) */ this.x = x; this.y = y; this.color = color; } /** * 判斷方塊是否可以向左移動,1是否在邊緣,2是否會與其他方塊重合 * @param blockUnits 當前正在下落的方塊 * @param max_x 游戲主界面X軸的最大值 ,下同 * @param allBlockUnits 所有的方塊 * @return 能移動true;不能移動false */ public static boolean canMoveToLeft(List<BlockUnit> blockUnits, int max_x, List<BlockUnit> allBlockUnits) { for (BlockUnit blockUnit : blockUnits) { int x = blockUnit.x; if (x - UNIT_SIZE < BEGIN) { return false; } int y = blockUnit.y; if (isSameUnit(x - UNIT_SIZE, y, allBlockUnits)) { return false; } } return true; } /** * 判斷方塊是否可以向右移動,1是否在邊緣,2是否會與其他方塊重合 * @param blockUnits 當前正在下落的方塊 * @param max_x 游戲主界面X軸的最大值 ,下同 * @param allBlockUnits 所有的方塊 * @return 能移動true;不能移動false */ public static boolean canMoveToRight(List<BlockUnit> blockUnits, int max_x, List<BlockUnit> allBlockUnits) { for (BlockUnit blockUnit : blockUnits) { int x = blockUnit.x; if (x + UNIT_SIZE > max_x - UNIT_SIZE) { return false; } int y = blockUnit.y; if (isSameUnit(x + UNIT_SIZE, y, allBlockUnits)) { return false; } } return true; } /** * 判斷方塊是否可以向下移動,1是否在邊緣,2是否會與其他方塊重合 * @param blockUnits 當前正在下落的方塊 * @param max_x 游戲主界面X軸的最大值 ,下同 * @param allBlockUnits 所有的方塊 * @return 能移動true;不能移動false */ public static boolean canMoveToDown(List<BlockUnit> blockUnits, int max_y, List<BlockUnit> allBlockUnits) { for (BlockUnit blockUnit : blockUnits) { int x = blockUnit.x; int y = blockUnit.y + UNIT_SIZE * 2; if (y > max_y - UNIT_SIZE) { return false; } if (isSameUnit(x, y, allBlockUnits)) { return false; } } return true; } public static boolean canRoute(List<BlockUnit> blockUnits, List<BlockUnit> allBlockUnits){ for (BlockUnit blockUnit: blockUnits) { if(isSameUnit(blockUnit.x, blockUnit.y, allBlockUnits)){ return false; } } return true; } /** * 把當前方塊向左移動一格 * @param blockUnits * @param max_x * @param allBlockUnits * @return 是否成功移動一格,是:true,否:false */ public static boolean toLeft(List<BlockUnit> blockUnits, int max_x, List<BlockUnit> allBlockUnits) { if (canMoveToLeft(blockUnits, max_x, allBlockUnits)) { for (BlockUnit blockUnit : blockUnits) { blockUnit.x = blockUnit.x - UNIT_SIZE; } return true; } return false; } /** * 把當前方塊向右移動一格 * @param blockUnits * @param max_x * @param allBlockUnits * @return 是否成功移動一格,是:true,否:false */ public static boolean toRight(List<BlockUnit> blockUnits, int max_x, List<BlockUnit> allBlockUnits) { if (canMoveToRight(blockUnits, max_x, allBlockUnits)) { for (BlockUnit blockUnit : blockUnits) { blockUnit.x = blockUnit.x + UNIT_SIZE; } return true; } return false; } /** * 把當前方塊下落一格 * @param blockUnits * @param allBlockUnits * @return 是否成功移動一格,是:true,否:false */ public static void toDown(List<BlockUnit> blockUnits, int max_Y, List<BlockUnit> allBlockUnits) { for (BlockUnit blockUnit : blockUnits) { blockUnit.y = blockUnit.y + BlockUnit.UNIT_SIZE; } } /** * 判斷 方塊單元是否和所有方塊有重合 * @param x * @param y * @param allBlockUnits * @return */ public static boolean isSameUnit(int x, int y, List<BlockUnit> allBlockUnits) { for (BlockUnit blockUnit : allBlockUnits) { if (Math.abs(x - blockUnit.x) < UNIT_SIZE && Math.abs(y - blockUnit.y) < UNIT_SIZE) { return true; } } return false; } /** * 刪除在第j行上的方塊單元 * @param allBlockUnits * @param j 需刪除行標 */ public static void remove(List<BlockUnit> allBlockUnits, int j) { for (int i = allBlockUnits.size() - 1; i >= 0; i--) { /* * ①逆向遍歷 ②根據(jù)y坐標計算單元所在行,若為j行則從units中刪除 */ if (( int ) ((allBlockUnits.get(i).y - BEGIN) / 50 ) == j) allBlockUnits.remove(i); } } } |
TetrisBlock.java用于產(chǎn)生不同形狀的方塊,共有其中類型。
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
|
/** * 方塊 * * @sign Created by wang.ao on 2017年1月13日 */ public class TetrisBlock { private static final int TYPE_SUM = 7 ; public int blockType, blockDirection; // 方塊種類,方塊朝向 private int color; // 方塊顏色 private int x, y; // 方塊坐標 public TetrisBlock() { } public TetrisBlock( int x, int y) { this .x = x; this .y = y; } public List<BlockUnit> getUnits( int x, int y) { this .x = x; this .y = y; return returnUnit(); } /** * 隨機產(chǎn)生一種方塊 * @return */ public List<BlockUnit> returnUnit() { List<BlockUnit> units = new ArrayList<BlockUnit>(); // 方塊組成部分 blockType = ( int ) (Math.random() * TYPE_SUM) + 1 ; // 隨機生成一個種類 blockDirection = 1 ; // 默認初始方向 color = ( int ) (Math.random() * 4 ) + 1 ; // 隨機生成一個顏色 units.clear(); switch (blockType) { case 1 : // 橫線 for ( int i = 0 ; i < 4 ; i++) { units.add( new BlockUnit(x + (- 2 + i) * BlockUnit.UNIT_SIZE, y, color)); } break ; case 2 : units.add( new BlockUnit(x + (- 1 + 1 ) * BlockUnit.UNIT_SIZE, y - BlockUnit.UNIT_SIZE, color)); for ( int i = 0 ; i < 3 ; i++) { units.add( new BlockUnit(x + (- 1 + i) * BlockUnit.UNIT_SIZE, y, color)); } break ; case 3 : for ( int i = 0 ; i < 2 ; i++) { units.add( new BlockUnit(x + (i - 1 ) * BlockUnit.UNIT_SIZE, y - BlockUnit.UNIT_SIZE, color)); units.add( new BlockUnit(x + (i - 1 ) * BlockUnit.UNIT_SIZE, y, color)); } break ; case 4 : units.add( new BlockUnit(x + (- 1 + 0 ) * BlockUnit.UNIT_SIZE, y - BlockUnit.UNIT_SIZE, color)); for ( int i = 0 ; i < 3 ; i++) { units.add( new BlockUnit(x + (- 1 + i) * BlockUnit.UNIT_SIZE, y, color)); } break ; case 5 : units.add( new BlockUnit(x + (- 1 + 2 ) * BlockUnit.UNIT_SIZE, y - BlockUnit.UNIT_SIZE, color)); for ( int i = 0 ; i < 3 ; i++) { units.add( new BlockUnit(x + (- 1 + i) * BlockUnit.UNIT_SIZE, y, color)); } break ; case 6 : for ( int i = 0 ; i < 2 ; i++) { units.add( new BlockUnit(x + (- 1 + i) * BlockUnit.UNIT_SIZE, y - BlockUnit.UNIT_SIZE, color)); units.add( new BlockUnit(x + i * BlockUnit.UNIT_SIZE, y, color)); } break ; case 7 : for ( int i = 0 ; i < 2 ; i++) { units.add( new BlockUnit(x + i * BlockUnit.UNIT_SIZE, y - BlockUnit.UNIT_SIZE, color)); units.add( new BlockUnit(x + (- 1 + i) * BlockUnit.UNIT_SIZE, y, color)); } break ; } return units; } |
NextBlockView.java其實就是游戲主界面的一個縮減版,用于顯示下一個要出現(xiàn)的方塊的,玩家可以明確的知道下一個方塊的形狀和顏色。
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
|
/** * 下一個要展示的方塊 * * @sign Created by wang.ao on 2017年1月13日 */ @SuppressLint ( "DrawAllocation" ) public class NextBlockView extends View { /** 網(wǎng)格開始坐標值,橫縱坐標的開始值都是此值 */ public static final int beginPoint = 10 ; /** 俄羅斯方塊的最大坐標 */ private static int max_x, max_y; private List<BlockUnit> blockUnits = new ArrayList<BlockUnit>(); /** 背景墻畫筆 */ private static Paint paintWall = null ; private static final int BOUND_WIDTH_OF_WALL = 2 ; private static Paint paintBlock = null ; private int div_x = 0 ; // 俄羅斯方塊顏色數(shù)組 private static final int color[] ={ Color.parseColor( "#FF6600" ), Color.BLUE, Color.RED, Color.GREEN, Color.GRAY }; public NextBlockView(Context context) { this (context, null ); } public NextBlockView(Context context, AttributeSet attrs) { super (context, attrs); if (paintWall == null ) { // 初始化化背景墻畫筆 paintWall = new Paint(); paintWall.setColor(Color.LTGRAY); paintWall.setStyle(Paint.Style.STROKE); paintWall.setStrokeWidth(BOUND_WIDTH_OF_WALL + 1 ); } if (paintBlock == null ) { // 初始化化背景墻畫筆 paintBlock = new Paint(); paintBlock.setColor(Color.parseColor( "#FF6600" )); } } public void setBlockUnits(List<BlockUnit> blockUnits, int div_x) { this .blockUnits = blockUnits; this .div_x = div_x; invalidate(); } @Override protected void onDraw(Canvas canvas) { super .onDraw(canvas); max_x = getWidth(); max_y = getHeight(); RectF rel; // 繪制網(wǎng)格 int len = blockUnits.size(); // 繪制方塊 // Toast.makeText(context, "" + len, Toast.LENGTH_SHORT).show(); for ( int i = 0 ; i < len; i++) { paintBlock.setColor(color[blockUnits.get(i).color]); int x = blockUnits.get(i).x - div_x + BlockUnit.UNIT_SIZE * 2 ; int y = blockUnits.get(i).y + BlockUnit.UNIT_SIZE * 2 ; rel = new RectF(x + BOUND_WIDTH_OF_WALL, y + BOUND_WIDTH_OF_WALL, x + BlockUnit.UNIT_SIZE - BOUND_WIDTH_OF_WALL, y + BlockUnit.UNIT_SIZE - BOUND_WIDTH_OF_WALL); canvas.drawRoundRect(rel, 8 , 8 , paintBlock); rel = new RectF(x, y, x + BlockUnit.UNIT_SIZE, y + BlockUnit.UNIT_SIZE); canvas.drawRoundRect(rel, 8 , 8 , paintWall); } } } |
GameConfig.java用于配置方塊的下落速度
1
2
3
4
|
public class GameConfig { /**方塊下落的速度*/ public static final int SPEED = 300 ; } |
TetrisActivityAW.java主界面,包括游戲主界面和控制臺,很簡單,直接貼代碼。
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
|
public class TetrisActivityAW extends Activity { private NextBlockView nextBlockView; private TetrisViewAW tetrisViewAW; private TextView gameStatusTip; public TextView score; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_tetris_activity_aw); nextBlockView = (NextBlockView) findViewById(R.id.nextBlockView1); tetrisViewAW = (TetrisViewAW) findViewById(R.id.tetrisViewAW1); tetrisViewAW.setFather( this ); gameStatusTip = (TextView) findViewById(R.id.game_staus_tip); score = (TextView) findViewById(R.id.score); } public void setNextBlockView(List<BlockUnit> blockUnits, int div_x) { nextBlockView.setBlockUnits(blockUnits, div_x); } /** * 開始游戲 * * @param view */ public void startGame(View view) { tetrisViewAW.startGame(); gameStatusTip.setText( "游戲運行中" ); } /** * 暫停游戲 */ public void pauseGame(View view) { tetrisViewAW.pauseGame(); gameStatusTip.setText( "游戲已暫停" ); } /** * 繼續(xù)游戲 */ public void continueGame(View view) { tetrisViewAW.continueGame(); gameStatusTip.setText( "游戲運行中" ); } /** * 停止游戲 */ public void stopGame(View view) { tetrisViewAW.stopGame(); score.setText( "" + 0 ); gameStatusTip.setText( "游戲已停止" ); } /** * 向左滑動 */ public void toLeft(View view) { tetrisViewAW.toLeft(); } /** * 向右滑動 */ public void toRight(View view) { tetrisViewAW.toRight(); } /** * 向右滑動 */ public void toRoute(View view) { tetrisViewAW.route(); } } |
TetrisActivityAW activity的xml文件
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
|
< RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android" xmlns:tools = "http://schemas.android.com/tools" android:layout_width = "match_parent" android:layout_height = "match_parent" tools:context = "${relativePackage}.${activityClass}" > < com.awang.media.minetetris.TetrisViewAW android:id = "@+id/tetrisViewAW1" android:layout_width = "match_parent" android:layout_height = "match_parent" android:layout_marginBottom = "200dp" android:layout_marginRight = "120dp" /> < com.awang.media.minetetris.NextBlockView android:id = "@+id/nextBlockView1" android:layout_width = "120dp" android:layout_height = "120dp" android:layout_alignParentRight = "true" /> < LinearLayout android:layout_width = "110dp" android:layout_height = "wrap_content" android:layout_alignParentRight = "true" android:layout_below = "@+id/nextBlockView1" android:layout_marginTop = "20dp" android:orientation = "vertical" > < LinearLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" android:orientation = "horizontal" > < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "分數(shù)" /> < TextView android:id = "@+id/score" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginLeft = "10dp" android:text = "1" /> </ LinearLayout > < LinearLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginTop = "20dp" android:orientation = "horizontal" > < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "等級" /> < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginLeft = "10dp" android:text = "1" /> </ LinearLayout > < LinearLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginTop = "20dp" android:orientation = "horizontal" > < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "速度" /> < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginLeft = "10dp" android:text = "0" /> </ LinearLayout > < LinearLayout android:layout_width = "match_parent" android:layout_height = "wrap_content" android:layout_marginTop = "20dp" android:orientation = "horizontal" > < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:text = "最高分" /> < TextView android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginLeft = "10dp" android:text = "0" /> </ LinearLayout > < Button android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_marginTop = "10dp" android:onClick = "startGame" android:text = "開始" /> < Button android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:onClick = "pauseGame" android:text = "暫停" /> < Button android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:onClick = "continueGame" android:text = "繼續(xù)" /> < Button android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:onClick = "stopGame" android:text = "結束" /> </ LinearLayout > < RelativeLayout android:layout_width = "match_parent" android:layout_height = "200dp" android:layout_alignParentBottom = "true" > < Button android:layout_width = "100dp" android:layout_height = "100dp" android:onClick = "toLeft" android:text = "左" /> < TextView android:id = "@+id/game_staus_tip" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_centerHorizontal = "true" android:layout_marginTop = "5dp" android:text = "點擊開始運行游戲" android:textSize = "20sp" /> < Button android:layout_width = "100dp" android:layout_height = "100dp" android:layout_centerInParent = "true" android:onClick = "toRoute" android:text = "旋轉" /> < Button android:layout_width = "100dp" android:layout_height = "100dp" android:layout_alignParentRight = "true" android:onClick = "toRight" android:text = "右" /> </ RelativeLayout > </ RelativeLayout > |
整個項目就是這些,代碼已經(jīng)全部貼出來了。
整個項目寫的時候,以為很簡單,但是卻遇到了很多問題,不過都已解決。歡迎來找bug,大家共同進步。
源碼下載地址:Android 俄羅斯方塊與貪吃蛇源碼下載
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/waa_0618/article/details/54581457