《俄罗斯方块》是一款由俄罗斯人阿列克谢·帕基特诺夫于1984年6月发明的经典休闲游戏,其基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。

下面介绍用Java开发《俄罗斯方块》。

 

创建一个普通Java项目,按如下结构创建类以及导入图片资源:

java小游戏俄罗斯方块代码 基于java的俄罗斯方块游戏_游戏


主要代码如下:

1、单个小方块

/**
 * 格子
 */
public class Cell {
	/**
	 * 行
	 */
	private int row;

	/**
	 * 列
	 */
	private int col;

	/**
	 * 贴图
	 */
	private BufferedImage image;

	public Cell(int row, int col, BufferedImage image) {
		super();
		this.row = row;
		this.col = col;
		this.image = image;
	}

	public int getRow() {
		return row;
	}
	public void setRow(int row) {
		this.row = row;
	}
	public int getCol() {
		return col;
	}
	public void setCol(int col) {
		this.col = col;
	}
	public BufferedImage getImage() {
		return image;
	}
	public void setImage(BufferedImage image) {
		this.image = image;
	}


	/**
	 * 往下落
	 */
	public void softDrop() {
		row++;
	}

	/**
	 * 往左移
	 */
	public void moveLeft() {
		col--;
	}

	/**往右移
	 *
	 */
	public void moveRight() {
		col++;
	}
}

2、四个小方块组合

/**
 * 表示4块格子
 */
public  abstract class Tetromino {
	/**
	 * 方块数组
	 */
	protected Cell[] cells = new Cell[4];

	/**
	 * 旋转状态数据
	 */
	protected State[] states;

	/**
	 * 旋转状态数据序号
	 */
	protected int index = 10000;
	
	protected class State{
		int row0,col0,row1,col1,
		    row2,col2,row3,col3;
		public State(int row0, int col0, int row1, int col1, int row2, int col2,
				int row3, int col3) {
			this.row0 = row0;
			this.col0 = col0;
			this.row1 = row1;
			this.col1 = col1;
			this.row2 = row2;
			this.col2 = col2;
			this.row3 = row3;
			this.col3 = col3;
		}
	}

	/**
	 * 随机产生4块放个
	 */
	public static Tetromino randomOne() {
		Random r = new Random();
		int type = r.nextInt(7);
		switch (type) {
		case 0:return new T();
		case 1:return new I();
		case 2:return new S();
		case 3:return new Z();
		case 4:return new O();
		case 5:return new L();
		case 6:return new J();
		default:return null;
		}
	}

	/**
	 * 下落
	 */
	public void softDrop() {
		for (int i = 0; i < cells.length; i++) {
			cells[i].softDrop();
		}
	}

	/**
	 * 左移
	 */
	public void moveLeft() {
		for (int i = 0; i < cells.length; i++) {
			cells[i].moveLeft();
		}
	}

	/**
	 * 右移
	 */
	public void moveRight() {
		for (int i = 0; i < cells.length; i++) {
			cells[i].moveRight();
		}
	}


	/**
	 * 右旋转
	 */
	public void rotateRight(){
		index++;
		State s = states[index%states.length];
		Cell o = this.cells[0];
		int row = o.getRow();
		int col = o.getCol();
		cells[1].setRow(row + s.row1);
		cells[1].setCol(col + s.col1);
		cells[2].setRow(row + s.row2);
		cells[2].setCol(col + s.col2);
		cells[3].setRow(row + s.row3);
		cells[3].setCol(col + s.col3);
	}

	/**
	 * 左旋转
	 */
	public void rotateLeft(){
		index--;
		State s = states[index%states.length];
		Cell o = this.cells[0];
		int row = o.getRow();
		int col = o.getCol();
		cells[1].setRow(row + s.row1);
		cells[1].setCol(col + s.col1);
		cells[2].setRow(row + s.row2);
		cells[2].setCol(col + s.col2);
		cells[3].setRow(row + s.row3);
		cells[3].setCol(col + s.col3);
	}
}

/**
 * T形方块
 */
class T extends Tetromino {
	public T() {
		cells[0] = new Cell(0, 4, TetrisGame.T);
		cells[1] = new Cell(0, 3, TetrisGame.T);
		cells[2] = new Cell(0, 5, TetrisGame.T);
		cells[3] = new Cell(1, 4, TetrisGame.T);
		states = new State[4];
		states[0]=new State(0,0,0,-1,0,1,1,0);//S0
		states[1]=new State(0,0,-1,0,1,0,0,-1);//S1
		states[2]=new State(0,0,0,1,0,-1,-1,0);//S2
		states[3]=new State(0,0,1,0,-1,0,0,1);//S3
	}
}

/**
 * I形方块
 */
class I extends Tetromino {
	public I() {
		cells[0] = new Cell(0, 4, TetrisGame.I);
		cells[1] = new Cell(0, 3, TetrisGame.I);
		cells[2] = new Cell(0, 5, TetrisGame.I);
		cells[3] = new Cell(0, 6, TetrisGame.I);
		states = new State[2];
		states[0] = new State(0,0,0,-1,0,1,0,2);
		states[1] = new State(0,0,-1,0,1,0,2,0);
	}
}

/**
 * S形方块
 */
class S extends Tetromino {
	public S() {
		cells[0] = new Cell(1, 4, TetrisGame.S);
		cells[1] = new Cell(1, 3, TetrisGame.S);
		cells[2] = new Cell(0, 4, TetrisGame.S);
		cells[3] = new Cell(0, 5, TetrisGame.S);
		states = new State[2];
		states[0] = new State(0,0,0,-1,-1,0,-1,1);
		states[1] = new State(0,0,-1,0,0,1,1,1);
	}
}

/**
 * Z形方块
 */
class Z extends Tetromino {
	public Z() {
		cells[0] = new Cell(1, 4, TetrisGame.Z);
		cells[1] = new Cell(0, 3, TetrisGame.Z);
		cells[2] = new Cell(0, 4, TetrisGame.Z);
		cells[3] = new Cell(1, 5, TetrisGame.Z);
		states = new State[2];
		states[0] = new State(0,0,-1,-1,-1,0,0,1);
		states[1] = new State(0,0,-1,1,0,1,1,0);
	}
}

/**
 * O形方块
 */
class O extends Tetromino {
	public O() {
		cells[0] = new Cell(0, 4, TetrisGame.O);
		cells[1] = new Cell(0, 5, TetrisGame.O);
		cells[2] = new Cell(1, 4, TetrisGame.O);
		cells[3] = new Cell(1, 5, TetrisGame.O);
		states = new State[2];
		states[0] = new State(0,0,0,1,1,0,1,1);
		states[1] = new State(0,0,0,1,1,0,1,1);
	}
}

/**
 * L形方块
 */
class L extends Tetromino {
	public L() {
		cells[0] = new Cell(0, 4, TetrisGame.L);
		cells[1] = new Cell(0, 3, TetrisGame.L);
		cells[2] = new Cell(0, 5, TetrisGame.L);
		cells[3] = new Cell(1, 3, TetrisGame.L);
		states = new State[4];
		states[0] = new State(0,0,0,1,0,-1,-1,1);
		states[1] = new State(0,0,1,0,-1,0,1,1);
		states[2] = new State(0,0,0,-1,0,1,1,-1);
		states[3] = new State(0,0,-1,0,1,0,-1,-1);
	}
}

/**
 * J形方块
 */
class J extends Tetromino {
	public J() {
		cells[0] = new Cell(0, 4, TetrisGame.J);
		cells[1] = new Cell(0, 3, TetrisGame.J);
		cells[2] = new Cell(0, 5, TetrisGame.J);
		cells[3] = new Cell(1, 5, TetrisGame.J);
		states = new State[4];
		states[0] = new State(0,0,0,-1,0,1,1,1);
		states[1] = new State(0,0,-1,0,1,0,1,-1);
		states[2] = new State(0,0,0,1,0,-1,-1,-1);
		states[3] = new State(0,0,1,0,-1,0,-1,1);
	}
}

3、游戏主类

/**
 * 俄罗斯方块
 */
public class TetrisGame extends JPanel {
    //背景图片
    private static BufferedImage background;
    //暂停图片
    private static BufferedImage pause;
    //游戏结束图片
    private static BufferedImage gameover;

    public static BufferedImage T;
    public static BufferedImage S;
    public static BufferedImage I;
    public static BufferedImage L;
    public static BufferedImage J;
    public static BufferedImage O;
    public static BufferedImage Z;

    private static int[] scoreTable = {0, 10, 50, 80, 200};//计分板

    public static final int ROWS = 20;//背景墙行数
    public static final int COLS = 10;//背景墙列数
    public static final int CELL_SIZE = 26;//格子大小
    public static final int FONT_COLOR = 0x667799;//字体颜色
    public static final int FONT_SIZE = 24;//字体大小
    public static final int RUNNING = 0;//运行
    public static final int PAUSE = 1;//暂停
    public static final int GAME_OVER = 2;//游戏结束

    static {
        try {
            background = ImageIO.read(TetrisGame.class.getResource("/tetris.png"));
            pause = ImageIO.read(TetrisGame.class.getResource("/pause.png"));
            gameover = ImageIO.read(TetrisGame.class.getResource("/gameover.png"));
            T = ImageIO.read(TetrisGame.class.getResource("/T.png"));
            S = ImageIO.read(TetrisGame.class.getResource("/S.png"));
            I = ImageIO.read(TetrisGame.class.getResource("/I.png"));
            L = ImageIO.read(TetrisGame.class.getResource("/L.png"));
            J = ImageIO.read(TetrisGame.class.getResource("/J.png"));
            O = ImageIO.read(TetrisGame.class.getResource("/O.png"));
            Z = ImageIO.read(TetrisGame.class.getResource("/Z.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private int score;//分数
    private int lines;//销毁的行数
    private Cell[][] wall;//背景墙
    private Tetromino tetromino;//正在下落的四块方格
    private Tetromino nextOne;//下一个四格方块
    private Timer timer;//定时器
    private int intervel = 10;//下落时间间隔10毫秒
    private int state;//游戏状态
    private int speed;//下落速度
    private int level;//难度级别
    private int index;//下落计数器,当index % speed == 0时候下落一次

    @Override
    public void paint(Graphics g) {
        g.drawImage(background, 0, 0, null);//画背景
        g.translate(15, 15);//坐标系平移
        paintWall(g);//画墙
        paintTetromino(g);//画正在下落的四块方格
        paintNextOne(g);//画下一个要下落的四块方块
        paintScore(g);//绘制分数
        paintState(g);//画游戏状态
    }

    /**
     * 画墙
     *
     * @param g 画笔
     */
    private void paintWall(Graphics g) {
        for (int row = 0; row < wall.length; row++) {
            Cell[] line = wall[row];//每一行row
            for (int col = 0; col < line.length; col++) {
                Cell cell = line[col];//每行中的每个格子
                int x = col * CELL_SIZE;
                int y = row * CELL_SIZE;
                if (cell == null) {
                    g.drawRect(x, y, CELL_SIZE, CELL_SIZE);//空白部分绘制边框
                } else {
                    g.drawImage(cell.getImage(), x, y, null);
                }
            }
        }
    }

    /**
     * 画正在下落的方块
     *
     * @param g 画笔
     */
    private void paintTetromino(Graphics g) {
        if (tetromino == null) {
            return;
        }
        Cell[] cells = tetromino.cells;
        for (int i = 0; i < cells.length; i++) {
            //i = 1,2,3,4
            Cell cell = cells[i];
            int x = cell.getCol() * CELL_SIZE;
            int y = cell.getRow() * CELL_SIZE;
            g.drawImage(cell.getImage(), x, y, null);
        }

    }

    /**
     * 画下一个要下落的方块
     *
     * @param g 画笔
     */
    private void paintNextOne(Graphics g) {
        if (nextOne == null) {
            return;
        }
        Cell[] cells = nextOne.cells;
        for (int i = 0; i < cells.length; i++) {
            Cell cell = cells[i];
            //即将下落的四块方格的位置在右上角
            int x = (cell.getCol() + 10) * CELL_SIZE;
            int y = (cell.getRow() + 1) * CELL_SIZE;
            g.drawImage(cell.getImage(), x, y, null);
        }
    }

    /**
     * 画分数
     *
     * @param g 画笔
     */
    private void paintScore(Graphics g) {
        int x = 290;
        int y = 160;
        g.setColor(new Color(FONT_COLOR));//给画笔设置字体颜色
        Font font = g.getFont();//取得画笔g当前字体
        font = new Font(font.getName(), font.getStyle(), FONT_SIZE);//重新设置字体大小
        g.setFont(font);//更改g的字体
        g.drawString("SCORE:" + score, x, y);
        y += 60;
        g.drawString("LINES:" + lines, x, y);
        y += 60;
        g.drawString("LEVEL:" + level, x, y);
    }

    /**
     * 画游戏状态
     *
     * @param g 画笔
     */
    private void paintState(Graphics g) {
        switch (state) {
            case PAUSE:
                g.drawImage(pause, -15, -15, null);
                break;
            case GAME_OVER:
                g.drawImage(gameover, -15, -15, null);
                break;
        }
    }

    /**
     * 判断是否出界
     */
    private boolean outOfBounds() {
        Cell[] cells = tetromino.cells;
        for (int i = 0; i < cells.length; i++) {
            Cell cell = cells[i];
            int col = cell.getCol();
            int row = cell.getRow();
            if (row < 0 || row >= ROWS || col < 0 || col >= COLS) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断正在下落的方块是否和墙上的方块重叠
     */
    private boolean coincide() {
        Cell[] cells = tetromino.cells;
        for (int i = 0; i < cells.length; i++) {
            Cell cell = cells[i];
            int col = cell.getCol();
            int row = cell.getRow();
            //如果墙上的(row,col)位置不是null,那就重叠了
            if (wall[row][col] != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * 右移
     */
    private void moveRightAction() {
        tetromino.moveRight();
        if (outOfBounds() || coincide()) {
            tetromino.moveLeft();
        }
    }

    /**
     * 左移
     */
    private void moveLeftAction() {
        tetromino.moveLeft();
        if (outOfBounds() || coincide()) {
            tetromino.moveRight();
        }
    }

    /**
     * 下落流程控制
     */
    private void softDropAction() {
        if (canDrop()) {
            tetromino.softDrop();
        } else {
            landIntoWall();
            int lines = destoryLines();
            this.lines += lines;
            this.score += scoreTable[lines];
            if (isGameOver()) {
                state = GAME_OVER;
            } else {
                tetromino = nextOne;
                nextOne = Tetromino.randomOne();//重新赋值
            }
        }
    }

    /**
     * 快速下落流程控制
     */
    private void hardDropAction() {
        while (canDrop()) {//一直循环执行下落动作
            tetromino.softDrop();
        }
        landIntoWall();
        int lines = destoryLines();
        this.lines += lines;
        this.score += scoreTable[lines];
        if (isGameOver()) {
            state = GAME_OVER;
        } else {
            tetromino = nextOne;
            nextOne = Tetromino.randomOne();//重新赋值
        }
    }

    /**
     * 右旋转
     */
    private void rotateRightAction() {
        tetromino.rotateRight();
        if (outOfBounds() || coincide()) {
            tetromino.rotateLeft();
        }
    }

    /**
     * 左旋转
     */
    private void rotateLeftAction() {
        tetromino.rotateLeft();
        if (outOfBounds() || coincide()) {
            tetromino.rotateRight();
        }
    }


    /**
     * 判断是否能下落
     */
    private boolean canDrop() {
        Cell[] cells = tetromino.cells;
        for (int i = 0; i < cells.length; i++) {
            Cell cell = cells[i];
            int row = cell.getRow();
            int col = cell.getCol();
            if (row == (ROWS - 1) || wall[row + 1][col] != null) {
                return false;
            }
        }
        return true;
    }

    /**
     * 固定到墙上
     */
    private void landIntoWall() {
        Cell[] cells = tetromino.cells;
        for (int i = 0; i < cells.length; i++) {
            Cell cell = cells[i];
            int row = cell.getRow();
            int col = cell.getCol();
            wall[row][col] = cell;
        }
    }

    /**
     * 销毁满行
     *
     * @return lines 销毁行的数量
     */
    private int destoryLines() {
        int lines = 0;//销毁行的数量
        for (int row = 0; row < ROWS; row++) {//遍历行
            if (fullCells(row)) {
                deleteRow(row);
                lines++;
            }
        }
        return lines;
    }

    /**
     * 删除行
     */
    private void deleteRow(int row) {
        for (int i = row; i >= 1; i--) {//i从满的那行开始
            System.arraycopy(wall[i - 1], 0, wall[i], 0, COLS);//把i-1行复制到i行
        }
        Arrays.fill(wall[0], null);//把第一行全部填null值
    }


    /**
     * 判断是否满行
     */
    private boolean fullCells(int row) {
        Cell[] cells = wall[row];//行
        for (int i = 0; i < cells.length; i++) {
            Cell cell = cells[i];//行中每格
            if (cell == null) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断游戏是否结束
     */
    private boolean isGameOver() {
        /*
         * 下一个出场方块没有位置放了,就是游戏结束
         * 即下一个出场方块每个格子行列对应的墙上如果有格子,就游戏结束
         */
        Cell[] cells = nextOne.cells;
        for (int i = 0; i < cells.length; i++) {
            Cell cell = cells[i];
            int row = cell.getRow();
            int col = cell.getCol();
            if (wall[row][col] != null) {
                return true;
            }
        }
        return false;
    }

    /**
     * RUNNING状态下中操作
     */
    private void processRunningKey(int key) {
        switch (key) {
            case KeyEvent.VK_Q:
                System.exit(0);
                break;//按q退出游戏
            case KeyEvent.VK_DOWN:
                softDropAction();
                break;//按↓下落
            case KeyEvent.VK_RIGHT:
                moveRightAction();
                break;//按→右移
            case KeyEvent.VK_LEFT:
                moveLeftAction();
                break;//按←左移
            case KeyEvent.VK_SPACE:
                hardDropAction();
                break;//按空格快速下落
            case KeyEvent.VK_UP:
                rotateRightAction();
                break;//按↑右旋转
            case KeyEvent.VK_Z:
                rotateLeftAction();
                break;//按z左旋转
            case KeyEvent.VK_P:
                state = PAUSE;
                break;//按p暂停
        }
    }

    /**
     * PAUSE状态下中操作
     */
    private void processPauseKey(int key) {
        switch (key) {
            case KeyEvent.VK_Q:
                System.exit(0);
                break;//按q退出游戏
            case KeyEvent.VK_C:
                index = 1;
                state = RUNNING;
                break;//按c继续游戏
        }
    }

    /**
     * GAME_OVER状态下中操作
     */
    private void processGameoverKey(int key) {
        switch (key) {
            case KeyEvent.VK_Q:
                System.exit(0);
                break;//按q退出游戏
            case KeyEvent.VK_S://按s重新开始游戏
                this.lines = 0;
                this.score = 0;
                this.wall = new Cell[ROWS][COLS];
                this.tetromino = Tetromino.randomOne();
                this.nextOne = Tetromino.randomOne();
                this.state = RUNNING;
                this.index = 0;
        }
    }


    /**
     * 游戏启动方法action:初始化
     */
    public void action() {
        wall = new Cell[ROWS][COLS];
        tetromino = Tetromino.randomOne();//tetromino实例化
        nextOne = Tetromino.randomOne();//nextOne
        state = RUNNING;


        /**
         * 键盘监听事件
         */
        KeyAdapter event = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {//键盘按下事件
                int key = e.getKeyCode();
                switch (state) {
                    case RUNNING:
                        processRunningKey(key);
                        break;
                    case PAUSE:
                        processPauseKey(key);
                        break;
                    case GAME_OVER:
                        processGameoverKey(key);
                        break;
                }
                repaint();

            }
        };
        this.requestFocus();//请求此 Component 获取输入焦点。
        this.addKeyListener(event);

        timer = new Timer();
        timer.schedule(new TimerTask() {//创建定时器任务
            @Override
            public void run() {
                //下落速度控制逻辑
                speed = 40 - (score / 1000);
                speed = speed <= 1 ? 1 : speed;
                level = 41 - speed;
                if (index % speed == 0) {
                    if (state == RUNNING) {
                        softDropAction();
                    }
                }
                index++;
                repaint();
            }
        }, intervel, intervel);
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame("俄罗斯方块");
        TetrisGame tetrisGame = new TetrisGame();
        frame.add(tetrisGame);
        frame.setSize(550, 600);//设置窗口初始大小
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);//设置窗口初始位置
        frame.setVisible(true);//设置窗体是否显示
        tetrisGame.action();//游戏启动
    }
}

编译项目:

java小游戏俄罗斯方块代码 基于java的俄罗斯方块游戏_java小游戏俄罗斯方块代码_02


启动项目:运行TetrisGame类的main()方法:

java小游戏俄罗斯方块代码 基于java的俄罗斯方块游戏_java_03