首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Swing俄罗斯方块游戏(2): 需要处理的关键点

2013-08-01 
Swing俄罗斯方块游戏(二): 需要处理的关键点上一篇博文介绍了俄罗斯方块游戏的图形选择与变换:Swing俄罗斯

Swing俄罗斯方块游戏(二): 需要处理的关键点

上一篇博文介绍了俄罗斯方块游戏的图形选择与变换:
Swing俄罗斯方块游戏(一): 图形选择与变换 --> [url]http://mouselearnjava.iteye.com/blog/1914513 [/url]
.

本文将介绍实现俄罗斯方块需要处理的关键点,这些关键点有如下几点:

1. 键盘事件的处理
2. 满行及其消行操作
3. 游戏结束判断
4. 游戏进度存储和加载
5. 游戏玩家得分排行榜
... ...

下面就结合代码一个一个地介绍这些点的实现:
1. 键盘事件的处理
键盘事件的处理包括5个部分:
a)向左

public void moveLeft(int flag[][]) {if (!isAlive) {return;}for (int i = 0; i < grid.length; i++) {tempX[i] = grid[i].x - 1;tempY[i] = grid[i].y;}if (tempX[0] >= RussiaGameConstant.LEFT&& flag[tempX[0]][tempY[0]] == 0&& tempX[1] >= RussiaGameConstant.LEFT&& flag[tempX[1]][tempY[1]] == 0&& tempX[2] >= RussiaGameConstant.LEFT&& flag[tempX[2]][tempY[2]] == 0&& tempX[3] >= RussiaGameConstant.LEFT&& flag[tempX[3]][tempY[3]] == 0) {for (int i = 0; i < grid.length; i++) {grid[i].x = tempX[i];}}}


b)向右与向左类似
c)向下与向下类似
d)空格键直接下降到底部

按下空格键一直向下的操作,其实就是在可以动的范围下,一直调用moveDown()方法e)向上键处理图形变换

每个图形,或有一种变换,或者有2种或者有四种变换,可以根据图形的特性进行处理。
比如,将“T字型”图型按照顺时针旋转,拥有四种变换,创建对象的时候已经确定了state是多少(state确定初始的位置是哪里),此后的变换只要对state加1并对4求余就可以知道怎么变换。
/** * @author Eric * @vesion 1.0 * @desc T字型方块 */public class RussiaSquareThree extends RussiaSquare {private static final long serialVersionUID = -180232612076846292L;public RussiaSquareThree(){state = (int)(Math.random() * 4);switch(state){case 0:grid[0].x = 4;grid[0].y = 0;grid[1].x = grid[0].x - 1;grid[1].y = grid[0].y + 1;grid[2].x = grid[0].x;grid[2].y = grid[0].y + 1;grid[3].x = grid[0].x + 1;grid[3].y = grid[0].y + 1;break;case 1:grid[0].x = 4;grid[0].y = 0;grid[1].x = grid[0].x;grid[1].y = grid[0].y + 1;grid[2].x = grid[0].x + 1;grid[2].y = grid[0].y + 1;grid[3].x = grid[0].x;grid[3].y = grid[0].y + 2;break;case 2:grid[0].x = 4;grid[0].y = 0;grid[1].x = grid[0].x + 1;grid[1].y = grid[0].y;grid[2].x = grid[0].x + 2;grid[2].y = grid[0].y;grid[3].x = grid[0].x + 1;grid[3].y = grid[0].y + 1;break;case 3:grid[0].x = 4;grid[0].y = 0;grid[1].x = grid[0].x - 1;grid[1].y = grid[0].y + 1;grid[2].x = grid[0].x;grid[2].y = grid[0].y + 1;grid[3].x = grid[0].x;grid[3].y = grid[0].y + 2;break;default:break;}}public void changeState(int flag[][]){switch(state){case 0:tempX[0] = grid[0].x;tempY[0] = grid[0].y;tempX[1] = tempX[0];tempY[1] = tempY[0] + 1;tempX[2] = tempX[0] + 1;tempY[2] = tempY[0] + 1;tempX[3] = tempX[0];tempY[3] = tempY[0] + 2;isAllowChangeState(flag, 4);break;case 1:tempX[0] = grid[0].x - 1;tempY[0] = grid[0].y + 1;tempX[1] = tempX[0] + 1;tempY[1] = tempY[0];tempX[2] = tempX[0] + 2;tempY[2] = tempY[0];tempX[3] = tempX[0] + 1;tempY[3] = tempY[0] + 1;isAllowChangeState(flag, 4);break;case 2:tempX[0] = grid[0].x + 1;tempY[0] = grid[0].y - 1;tempX[1] = tempX[0] - 1;tempY[1] = tempY[0] + 1;tempX[2] = tempX[0];tempY[2] = tempY[0] + 1;tempX[3] = tempX[0];tempY[3] = tempY[0] + 2;isAllowChangeState(flag, 4);break;case 3:tempX[0] = grid[0].x;tempY[0] = grid[0].y;tempX[1] = tempX[0] - 1;tempY[1] = tempY[0] + 1;tempX[2] = tempX[0];tempY[2] = tempY[0] + 1;tempX[3] = tempX[0] + 1;tempY[3] = tempY[0] + 1;isAllowChangeState(flag, 4);break;default:break;}}}


private class KeyHandler implements KeyListener {public void keyPressed(KeyEvent event) {if (!gameState.isRunState()) {return;}int keyCode = event.getKeyCode();switch (keyCode) {case KeyEvent.VK_LEFT:sr1.moveLeft(flag);break;case KeyEvent.VK_RIGHT:sr1.moveRight(flag);break;case KeyEvent.VK_UP:sr1.changeState(flag);break;case KeyEvent.VK_DOWN:sr1.moveDown(flag);break;case KeyEvent.VK_SPACE:while (sr1.isAlive) {sr1.moveDown(flag);}default:break;}repaint();}public void keyReleased(KeyEvent event) {}public void keyTyped(KeyEvent event) {}}


2. 满行及其消行操作
用一个二维数组记录当前屏幕上的方块状态,0表示没有方块,1表示有方块。
满行的判断就归结到某一行1的个数是否等于该行列的总数,如果是就满足满行条件。

当有满行情况出现的时候,需要进行消除和计分操作。

消除行的一个做法就是将该行以上的行通通往下移,移动之后在将第一行的flag全部置为0.
public class RussiaGamePanel extends JPanel {private class TimerAction implements ActionListener, Serializable {private static final long serialVersionUID = -6117702515382009989L;public void actionPerformed(ActionEvent event) {if (!gameState.isRunState()) {return;}//满行的个数int num = 0;sr1.moveDown(flag);if (!sr1.isAlive) {for (int i = 0; i < 4; i++) {flag[sr1.grid[i].x][sr1.grid[i].y] = 1;color[sr1.grid[i].x][sr1.grid[i].y] = sr1.color;}judgeGameOver();for (int i = RussiaGameConstant.UP; i <= RussiaGameConstant.DOWN; i++) {int count = 0;for (int j = RussiaGameConstant.LEFT; j <= RussiaGameConstant.RIGHT; j++) {count += flag[j][i];}/* * flag[i][j] =1 表示这个位置有小方块,如果一行的位置都有小方块,那么满行的个数num加1. * 并且消除行。 */if (count == RussiaGameConstant.GRID_COLUMN_NUMBER) {num++;/** * 消除行操作。 */for (int m = i; m > RussiaGameConstant.UP; m--) {for (int n = RussiaGameConstant.LEFT; n <= RussiaGameConstant.RIGHT; n++) {flag[n][m] = flag[n][m - 1];color[n][m] = color[n][m - 1];}}/* * 重新将第一行的flag[s][0]置为0 */for (int s = RussiaGameConstant.LEFT; s <= RussiaGameConstant.RIGHT; s++) {flag[s][RussiaGameConstant.UP] = 0;}}}/* * 将下一个图形作为当前运动的图形,并随机产生下一个图形。 */sr1 = sr2;sr2 = RussiaSquareFactory.generateNextRussiaSquareByRandom();}// 计算分数calculateScore(num);repaint();}}/** * @param num *            方块满行的个数 */private void calculateScore(int num){switch(num){case 1: score += 10; break;case 2: score += 20; break;case 3: score += 50; break;case 4: score += 100; break;default: break;}}}


3. 游戏结束判断

俄罗斯方块游戏结束的判断其实很简单,只要判断第一行的标记位是否有1即可。
private boolean isTopTouched() {for (int i = RussiaGameConstant.LEFT; i <= RussiaGameConstant.RIGHT; i++) {if (flag[i][RussiaGameConstant.UP] == 1) {return true;}}return false;}


4. 游戏进度存储和加载
5. 游戏玩家得分排行榜


关于4,5两点,本文不在这里展开,因为这些功能以前在写贪吃蛇游戏的博文中介绍了。
Swing贪吃蛇游戏(三):增加游戏进度存储和加载功能 >>>
http://mouselearnjava.iteye.com/blog/1914225

Swing贪吃蛇游戏(四):增加游戏得分排行榜功能  >>>
http://mouselearnjava.iteye.com/blog/1914316

拥有所有功能的详细代码请参考附件MyRussiaGame.7z

俄罗斯方块游戏的界面如下:










热点排行