先看看效果:

俄罗斯方块_ide

思路:整个游戏界面是一个画布,左边画游戏的地图和当前块,右边是游戏规则。游戏地图map[][]是一个二维int数组。主要是当前块的处理方式,我这里是使用一个四乘四的矩阵来表示的,1表示有格子,0表示空的。然后是边框使用3来说表示,位运算来判断是否与边界或下面的堆积块碰撞。(方块的三维数组可能不太好理解,本来是一个四维数组来的,但四维数组更不好理解,所以就缩减了一维,第一维表示方块的类型,第二维表示方块的变形,第三位有16个数,代表四乘四的矩阵,就是具体方块的形状的表示)

public class Main {
public static void main(String[] args) {
TetrisFrame tFrame = new TetrisFrame();
tFrame.setVisible(true);
}
}


import java.awt.Container;

import javax.swing.JFrame;

public class TetrisFrame extends JFrame{
private static final long serialVersionUID = 1L;
TetrisFrame() {
super("TETRIS");
setBounds(500, 80, 500, 580);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
Container container = getContentPane();

//左边游戏显示
TetrisPanel tPanel = new TetrisPanel();
addKeyListener(tPanel.listener);
container.add(tPanel);
}
}


import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

public class TetrisPanel extends JPanel {
private static final long serialVersionUID = 1L;

private int line = 35;
private int row = 20;
private int score;
private int boxSize = 15;
private int map[][];

// 当前块的信息
private int blockStyle;// 块的类型
private int turnState;// 该类型的第几个
private int x;// 当前块的左上角x坐标(第几列的位置)
private int y;// 当前块的左上角y坐标(第几行的位置)

// 定时器
Timer timer;
int delay = 200;// 初始化为0.2秒走一次

// 监听器
Listener listener = new Listener();

// 方块
int shapes[][][] = new int[][][] {
// I
{ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 } },
// S
{ { 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 } },
// Z
{ { 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } },
// J
{ { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
// O
{ { 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
// L
{ { 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
// T
{ { 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } };

TetrisPanel() {
iniGame();
nextBox();
timer = new Timer(delay, listener);
timer.start();
}

// 初始化游戏
private void iniGame() {
delay = 200;
score = 0;
if(timer != null){// 第一次初始化timer是空的
timer.setDelay(delay);
timer.restart();
}
map = new int[line+1][row+1];
for (int i = 0; i < line; i++) {
map[i][0] = 3;
map[i][row-1] = 3;
}
for (int i = 0; i < row; i++) {
map[line-1][i] = 3;
}
}

// 产生下一个方块
private void nextBox() {
x = 8;
y = 0;
Random random = new Random(System.currentTimeMillis());
blockStyle = random.nextInt(7);
turnState = random.nextInt(4);
repaint();

//游戏结束处理
//产生一个方块的时候判断是否与堆积块碰撞
if(collide(x, y, blockStyle, turnState)==0 && timer.isRunning()){
timer.stop();
int i = JOptionPane.showConfirmDialog(null, "Game Over!真的菜,是否再战一局?","游戏结束",JOptionPane.YES_NO_OPTION);
if(i==JOptionPane.YES_OPTION){
iniGame();
}else if(i==JOptionPane.NO_OPTION){
System.exit(0);
}
}
}

@Override
public void paint(Graphics g) {
super.paint(g);
g.fillRect(boxSize, boxSize, row*boxSize,line*boxSize);
// 当前块
for(int i=0;i<16;i++){
if(shapes[blockStyle][turnState][i]==1){
g.setColor(Color.white);
g.fillRect((i%4+x+1)*boxSize, (i/4+y)*boxSize, boxSize, boxSize);
g.setColor(Color.lightGray);
g.drawRect((i%4+x+1)*boxSize, (i/4+y)*boxSize, boxSize, boxSize);
}
}
// 堆积块+地图
for (int i = 0; i < line; i++) {// 行
for (int j = 0; j < row; j++) {// 列
if(map[i][j]==1){
//画块
g.setColor(Color.gray);
g.fillRect(j*boxSize+boxSize,i*boxSize+boxSize,boxSize,boxSize);
//画块的分界线
g.setColor(Color.lightGray);
g.drawRect(j*boxSize+boxSize,i*boxSize+boxSize,boxSize,boxSize);
}else if(map[i][j]==3){
g.setColor(Color.darkGray);
g.fillRect(j*boxSize+boxSize,i*boxSize+boxSize,boxSize,boxSize);
g.setColor(Color.lightGray);
g.drawRect(j*boxSize+boxSize,i*boxSize+boxSize,boxSize,boxSize);
}
}
}
Font font1 = new Font("方正舒体", Font.BOLD, 22);
Font font2 = new Font("方正楷体", Font.BOLD, 20);
g.setFont(font1);
g.setColor(Color.black);
g.drawString("当前得分:"+score, 330, 100);
g.setFont(font2);
g.drawString("游戏规则", 358, 180);
g.drawString("方向键控制左右", 325, 210);
g.drawString("方向键上控制变形", 325, 240);
g.drawString("空格控制开始暂停", 325, 270);
g.setFont(font1);
g.drawString("作者 :逸川同学", 320, 380);
g.drawString("QQ :1228127092", 315, 415);
}

//判断块是否有碰撞
private int collide(int x,int y, int blockStyle, int turnState){
for (int i = 0; i < 4; i++) {//行
for (int j = 0; j < 4; j++) {//列
// 到达边界,底部
if((shapes[blockStyle][turnState][i*4+j] & map[i+y][j+x])==1) {
return 0;
}
}
}
return 1;
}

// 将块添加到地图
private void addMap(int x, int y) {
for (int i = 0; i < 4; i++) {// 行
for (int j = 0; j < 4; j++) {// 列
if (shapes[blockStyle][turnState][i*4+j] == 1) {
map[y+i][x+j] = 1;
}
}
}
delMap();
}

private void delMap() {
for (int i = 1; i < line-1; i++) {
int t = 1;
for (int j = 1; j < row-1; j++) {
t = t&map[i][j];
}
if(t == 1){
for (int j = i; j > 0; j--) {
for (int k = 1; k < row-1; k++) {
map[j][k] = map[j-1][k];
}
}
score+=10;
delay-=10;
}
}
}

private void down() {
if (collide(x,y+1, blockStyle, turnState)==0){
addMap(x,y);
nextBox();
}else {
y++;
}
repaint();
}
private void change() {
if(collide(x, y, blockStyle, (turnState+1)%4)!=0){
turnState = (turnState+1)%4;
}
}
private void left() {
if(x>0){
x -= collide(x-1, y, blockStyle, turnState);
}
repaint();
}
private void right() {
if(x<row-1){
x += collide(x+1, y, blockStyle, turnState);
}
repaint();
}

class Listener extends KeyAdapter implements ActionListener {
//定时器监听
@Override
public void actionPerformed(ActionEvent e) {
down();
}
//键盘监听
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
change();
break;
case KeyEvent.VK_LEFT:
left();
break;
case KeyEvent.VK_RIGHT:
right();
break;
case KeyEvent.VK_DOWN:
down();
break;
case KeyEvent.VK_SPACE:
if(timer.isRunning()){
timer.stop();
}else {
timer.start();
}
}
}
}
}