java实现俄罗斯方块小游戏

本文实例为大家分享了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;
  }
}

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

/**
 * 绘制窗体内容,包括游戏方块,游戏积分或结束字符串
 */
@Override
public 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++; // 记录消除行数
  }
}

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

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

运行效果:

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

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

(0)

相关推荐

  • java实现五子棋小游戏

    java实现五子棋小游戏 package Gomoku; import java.awt.Toolkit; import javax.swing.JFrame; public class GomokuFrame extends JFrame { //定义一个操作面板 OperatorPane op=null; public GomokuFrame() { //设置名称 this.setTitle("五子棋"); //设置窗口大小 this.setSize(510,510); //设置窗

  • Java实现的打地鼠小游戏完整示例【附源码下载】

    本文实例讲述了Java实现的打地鼠小游戏.分享给大家供大家参考,具体如下: 这里涉及到java线程和GUI的相关知识,一个简单的java小游戏打地鼠,有兴趣的朋友可以优化一下.先来看看运行效果: 具体代码: Mouse.java: import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt

  • Java编写猜数字小游戏

    本文实例讲述了java实现的简单猜数字游戏代码.分享给大家供大家参考. 以下是Java语言写的一个猜数字小游戏引用片段: import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanner; //主函数 public class calssOne { public static void main(String[] args) { //shit+Ctrl+o int result; //随机产生一个

  • java实现猜数字小游戏

    java 实现猜数字游戏 随机给定一个数字,猜大小直到正确 package com.swift; import java.util.Random; import java.util.Scanner; public class GuessBigSmall { public static void main(String[] args) { Scanner scan=new Scanner(System.in); Random random = new Random(); int number =

  • Java实现打飞机小游戏(附完整源码)

    写在前面 技术源于分享,所以今天抽空把自己之前用java做过的小游戏整理贴出来给大家参考学习.java确实不适合写桌面应用,这里只是通过这个游戏让大家理解oop面向对象编程的过程,纯属娱乐.代码写的很简单,也很容易理解,并且注释写的很清楚了,还有问题,自己私下去补课学习. 效果如下 完整代码 敌飞机 import java.util.Random; 敌飞机: 是飞行物,也是敌人 public class Airplane extends FlyingObject implements Enemy

  • Java俄罗斯方块小游戏

    去年就已经学了这个技术了,一直没去写,现在抽个时间写了个俄罗斯方块游戏. 只有简单的新游戏,暂停,继续,积分功能.简单的实现了俄罗斯的经典功能. 不介绍了,有兴趣的自己运行一下,后面贴出了图片. 代码: package cn.hncu; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.Act

  • Java编写迷宫小游戏

    缘起: 去年(大三上学期)比较喜欢写小游戏,于是想试着写个迷宫试一下. 程序效果: 按下空格显示路径: 思考过程: 迷宫由一个一个格子组成,要求从入口到出口只有一条路径. 想了一下各种数据结构,似乎树是比较合适的,从根节点到每一个子节点都只有一条路径.假设入口是根节点,出口是树中某个子节点,那么,从根节点到该子节点的路径肯定是唯一的. 所以如果能构造一棵树把所有的格子都覆盖到,也就能够做出一个迷宫了. 另外还要求树的父节点和子节点必须是界面上相邻的格子. 在界面显示时,父节点和子节点之间共用的边

  • Java编程实现打地鼠文字游戏实例代码

    控制台输入数字,与随机数匹配,匹配正确则返回"打中了!" 匹配错误则返回"太遗憾!没打中!" package hitmouse; import java.util.Random; import java.util.Scanner; public class HitMouse { public static void main(String[] args) { // TODO Auto-generated method stub int[] map = new int

  • Java完美实现2048小游戏

    完美地模仿了2048游戏,是根据网友的一个2048改的. Block.java import javax.swing.*; import java.awt.*; public class Block extends JLabel { private int value; public Block() { value = 0;//初始化值为0 setFont(new Font("font", Font.PLAIN, 40));//设定字体 setBackground(Color.gray

  • java编写贪吃蛇小游戏

    废话不多说,直接奉上代码: Frame.java package snake; import java.awt.Graphics; import java.awt.Menu; import java.awt.MenuBar; import java.awt.MenuItem; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import

随机推荐