首页 > 编程 > Java > 正文

java实现俄罗斯方块小游戏

2019-11-26 09:53:03
字体:
来源:转载
供稿:网友

本文实例为大家分享了java实现俄罗斯方块的具体代码,供大家参考,具体内容如下

使用一个二维数组保存游戏的地图:

// 游戏地图格子,每个格子保存一个方块,数组纪录方块的状态private State map[][] = new State[rows][columns];

游戏前先将所有地图中的格子初始化为空:

/* 初始化所有的方块为空 */for (int i = 0; i < map.length; i++) {  for (int j = 0; j < map[i].length; j++) {    map[i][j] = State.EMPTY;  }}

玩游戏过程中,我们能够看到界面上的方块,那么就得将地图中所有的方块绘制出来,当然,除了需要绘制方块外,游戏积分和游戏结束的字符串在必要的时候也需要绘制:

/** * 绘制窗体内容,包括游戏方块,游戏积分或结束字符串 */@Overridepublic void paint(Graphics g) {  super.paint(g);  for (int i = 0; i < rows; i++) {    for (int j = 0; j < columns; j++) {      if (map[i][j] == State.ACTIVE) { // 绘制活动块        g.setColor(activeColor);        g.fillRoundRect(j * BLOCK_SIZE, i * BLOCK_SIZE + 25,            BLOCK_SIZE - 1, BLOCK_SIZE - 1, BLOCK_SIZE / 5,            BLOCK_SIZE / 5);      } else if (map[i][j] == State.STOPED) { // 绘制静止块        g.setColor(stopedColor);        g.fillRoundRect(j * BLOCK_SIZE, i * BLOCK_SIZE + 25,            BLOCK_SIZE - 1, BLOCK_SIZE - 1, BLOCK_SIZE / 5,            BLOCK_SIZE / 5);      }    }  }  /* 打印得分 */  g.setColor(scoreColor);  g.setFont(new Font("Times New Roman", Font.BOLD, 30));  g.drawString("SCORE : " + totalScore, 5, 70);  // 游戏结束,打印结束字符串  if (!isGoingOn) {    g.setColor(Color.RED);    g.setFont(new Font("Times New Roman", Font.BOLD, 40));    g.drawString("GAME OVER !", this.getWidth() / 2 - 140,        this.getHeight() / 2);  }}

通过随机数的方式产生方块所组成的几种图形,一般七种图形:条形、田形、正7形、反7形、T形、Z形和反Z形,如生成条形:

map[0][randPos] = map[0][randPos - 1] = map[0][randPos + 1]         = map[0][randPos + 2] = State.ACTIVE;

生成图形后,实现下落的操作。如果遇到阻碍,则不能再继续下落:

isFall = true; // 是否能够下落// 从当前行检查,如果遇到阻碍,则停止下落for (int i = 0; i < blockRows; i++) {  for (int j = 0; j < columns; j++) {    // 遍历到行中块为活动块,而下一行块为静止块,则遇到阻碍    if (map[rowIndex - i][j] == State.ACTIVE        && map[rowIndex - i + 1][j] == State.STOPED) {      isFall = false; // 停止下落      break;    }  }  if (!isFall)    break;}

如果未遇到阻碍,则下落的时候,方块图形整体向下移动一行:

// 图形下落一行for (int i = 0; i < blockRows; i++) {  for (int j = 0; j < columns; j++) {    if (map[rowIndex - i][j] == State.ACTIVE) { // 活动块向下移动一行      map[rowIndex - i][j] = State.EMPTY; // 原活动块变成空块      map[rowIndex - i + 1][j] = State.ACTIVE; // 下一行块变成活动块    }  }}

向左、向右方向移动时是类似的操作:

/** * 向左走 */private void left() {  // 标记左边是否有阻碍  boolean hasBlock = false;  /* 判断是否左边有阻碍 */  for (int i = 0; i < blockRows; i++) {    if (map[rowIndex - i][0] == State.ACTIVE) { // 判断左边是否为墙      hasBlock = true;      break; // 有阻碍,不用再循环判断行    } else {      for (int j = 1; j < columns; j++) { // 判断左边是否有其它块        if (map[rowIndex - i][j] == State.ACTIVE            && map[rowIndex - i][j - 1] == State.STOPED) {          hasBlock = true;          break; // 有阻碍,不用再循环判断列        }      }      if (hasBlock)        break; // 有阻碍,不用再循环判断行    }  }  /* 左边没有阻碍,则将图形向左移动一个块的距离 */  if (!hasBlock) {    for (int i = 0; i < blockRows; i++) {      for (int j = 1; j < columns; j++) {        if (map[rowIndex - i][j] == State.ACTIVE) {          map[rowIndex - i][j] = State.EMPTY;          map[rowIndex - i][j - 1] = State.ACTIVE;        }      }    }    // 重绘    repaint();  }}

向下加速移动时,就是减小每次正常状态下落的时间间隔:

/** * 向下直走 */private void down() {  // 标记可以加速下落  immediate = true;}

如何变换图形方向,这里仅使用了非常简单的方法来实现方向变换,当然可以有更优的算法实现方向变换操作,大家可以自己研究:

/** * 旋转方块图形 */private void rotate() {  try {    if (shape == 4) { // 方形,旋转前后是同一个形状      return;    } else if (shape == 0) { // 条状      // 临时数组,放置旋转后图形      State[][] tmp = new State[4][4];      int startColumn = 0;      // 找到图形开始的第一个方块位置      for (int i = 0; i < columns; i++) {        if (map[rowIndex][i] == State.ACTIVE) {          startColumn = i;          break;        }      }      // 查找旋转之后是否有阻碍,如果有阻碍,则不旋转      for (int i = 0; i < 4; i++) {        for (int j = 0; j < 4; j++) {          if (map[rowIndex - 3 + i][j + startColumn] == State.STOPED) {            return;          }        }      }      if (map[rowIndex][startColumn + 1] == State.ACTIVE) { // 横向条形,变换为竖立条形        for (int i = 0; i < 4; i++) {          tmp[i][0] = State.ACTIVE;          for (int j = 1; j < 4; j++) {            tmp[i][j] = State.EMPTY;          }        }        blockRows = 4;      } else { // 竖立条形,变换为横向条形        for (int j = 0; j < 4; j++) {          tmp[3][j] = State.ACTIVE;          for (int i = 0; i < 3; i++) {            tmp[i][j] = State.EMPTY;          }        }        blockRows = 1;      }      // 将原地图中图形修改为变换后图形      for (int i = 0; i < 4; i++) {        for (int j = 0; j < 4; j++) {          map[rowIndex - 3 + i][startColumn + j] = tmp[i][j];        }      }    } else {      // 临时数组,放置旋转后图形      State[][] tmp = new State[3][3];      int startColumn = columns;      // 找到图形开始的第一个方块位置      for (int j = 0; j < 3; j++) {        for (int i = 0; i < columns; i++) {          if (map[rowIndex - j][i] == State.ACTIVE) {            startColumn = i < startColumn ? i : startColumn;          }        }      }      // 判断变换后是否会遇到阻碍      for (int i = 0; i < 3; i++) {        for (int j = 0; j < 3; j++) {          if (map[rowIndex - 2 + j][startColumn + 2 - i] == State.STOPED)            return;        }      }      // 变换      for (int i = 0; i < 3; i++) {        for (int j = 0; j < 3; j++) {          tmp[2 - j][i] = map[rowIndex - 2 + i][startColumn + j];        }      }      // 将原地图中图形修改为变换后图形      for (int i = 0; i < 3; i++) {        for (int j = 0; j < 3; j++) {          map[rowIndex - 2 + i][startColumn + j] = tmp[i][j];        }      }      // 重绘      repaint();      // 重新修改行指针      for (int i = 0; i < 3; i++) {        for (int j = 0; j < 3; j++) {          if (map[rowIndex - i][startColumn + j] != null              || map[rowIndex - i][startColumn + j] != State.EMPTY) {            rowIndex = rowIndex - i;            blockRows = 3;            return;          }        }      }    }  } catch (Exception e) {   // 遇到数组下标越界,说明不能变换图形形状,不作任何处理  }}

当图形下落遇到阻碍时停止,我们就需要判断这时是否有某一行或几行可以消除掉,这时可以先获取每行中方块的个数,然后再进行判断:

int[] blocksCount = new int[rows]; // 记录每行有方块的列数int eliminateRows = 0; // 消除的行数/* 计算每行方块数量 */for (int i = 0; i < rows; i++) {  blocksCount[i] = 0;  for (int j = 0; j < columns; j++) {    if (map[i][j] == State.STOPED)      blocksCount[i]++;  }}

如果有满行的方块,则消除掉该行方块:

/* 实现有满行的方块消除操作 */for (int i = 0; i < rows; i++) {  if (blocksCount[i] == columns) {    // 清除一行    for (int m = i; m >= 0; m--) {      for (int n = 0; n < columns; n++) {        map[m][n] = (m == 0) ? State.EMPTY : map[m - 1][n];      }    }      eliminateRows++; // 记录消除行数  }}

最后我们再重绘显示积分就可以了。

重复以上的生成图形、图形下落、左右下移动、判断消除行的操作,一个简单的俄罗斯方块就完成了。

运行效果:

完整示例代码:俄罗斯方块

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持武林网。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表