创建包和文件夹
1.创建小方块类
- package eluosifangkuai;
- import java.awt.image.BufferedImage;
- import java.util.Objects;
-
- /**
- * @author xiaoZhao
- * @date 2022/5/7
- * @describe
- * 小方块类
- * 方法: 左移、右移、下落
- */
- public class Cell {
- // 行
- private int row;
- // 列
- private int col;
- private BufferedImage image;
-
- public Cell() {
- }
-
- public Cell(int row, int col, BufferedImage image) {
- 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;
- }
-
- @Override
- public String toString() {
- return "Cell{" +
- "row=" + row +
- ", col=" + col +
- ", image=" + image +
- '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
-
- if (!(o instanceof Cell)) {
- return false;
- }
- Cell cell = (Cell) o;
- return getRow() == cell.getRow() &&
- getCol() == cell.getCol() &&
- Objects.equals(getImage(), cell.getImage());
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(getRow(), getCol(), getImage());
- }
-
- //左移动一格
- public void left(){
- col--;
- }
-
- //右移动一格
- public void right(){
- col++;
- }
-
- //下移动一格
- public void down(){
- row++;
- }
- }
2.编写四方格父类
- package eluosifangkuai;
-
- import xingzhuang.*;
-
- /**
- * @author xiaoZhao
- * @date 2022/5/11
- * @describe 编写四方格父类
- */
- public class Tetromino {
-
- public Cell[] cells = new Cell[4];
-
- //旋转的状态
- protected State[] states;
- //声明旋转次数
- protected int count = 10000;
-
-
- //左移方法
- public void moveLeft() {
- for (Cell cell : cells) {
- cell.left();
- }
- }
-
- //右移方法
- public void moveRight() {
- for (Cell cell : cells) {
- cell.right();
- }
- }
-
- //单元格下落
- public void moveDrop() {
- for (Cell cell : cells) {
- cell.down();
- }
- }
-
- //编写随机生成四方格
- public static Tetromino randomOne() {
- int num = (int) (Math.random() * 7);
- Tetromino tetromino = null;
- switch (num) {
- case 0:
- tetromino = new I();
- break;
- case 1:
- tetromino = new J();
- break;
- case 2:
- tetromino = new L();
- break;
- case 3:
- tetromino = new O();
- break;
- case 4:
- tetromino = new S();
- break;
- case 5:
- tetromino = new T();
- break;
- case 6:
- tetromino = new Z();
- break;
- }
-
- return tetromino;
- }
-
- //顺时针旋转的方法
- public void rotateRight() {
- if (states.length == 0) {
- return;
- }
-
- //旋转次数+1
- count++;
- State s = states[count % states.length];
- Cell cell = cells[0];
- int row = cell.getRow();
- int col = cell.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() {
- if (states.length == 0) {
- return;
- }
-
- //旋转次数+1
- count--;
- State s = states[count % states.length];
- Cell cell = cells[0];
- int row = cell.getRow();
- int col = cell.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);
- }
-
- //四方格旋转状态的内部类
- protected class State {
- //存储四方格各元素的位置
- int row0, col0, row1, col1, row2, col2, row3, col3;
-
- public State() {
- }
-
- 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;
- }
-
- public int getRow0() {
- return row0;
- }
-
- public void setRow0(int row0) {
- this.row0 = row0;
- }
-
- public int getCol0() {
- return col0;
- }
-
- public void setCol0(int col0) {
- this.col0 = col0;
- }
-
- public int getRow1() {
- return row1;
- }
-
- public void setRow1(int row1) {
- this.row1 = row1;
- }
-
- public int getCol1() {
- return col1;
- }
-
- public void setCol1(int col1) {
- this.col1 = col1;
- }
-
- public int getRow2() {
- return row2;
- }
-
- public void setRow2(int row2) {
- this.row2 = row2;
- }
-
- public int getCol2() {
- return col2;
- }
-
- public void setCol2(int col2) {
- this.col2 = col2;
- }
-
- public int getRow3() {
- return row3;
- }
-
- public void setRow3(int row3) {
- this.row3 = row3;
- }
-
- public int getCol3() {
- return col3;
- }
-
- public void setCol3(int col3) {
- this.col3 = col3;
- }
-
- @Override
- public String toString() {
- return "State{" +
- "row0=" + row0 +
- ", col0=" + col0 +
- ", row1=" + row1 +
- ", col1=" + col1 +
- ", row2=" + row2 +
- ", col2=" + col2 +
- ", row3=" + row3 +
- ", col3=" + col3 +
- '}';
- }
- }
- }
3.编写字母
- package xingzhuang;
-
-
- import sifang.Tetris;
- import eluosifangkuai.Cell;
- import eluosifangkuai.Tetromino;
-
-
- public class I extends Tetromino {
-
- public I() {
- cells[0] = new Cell(0,4, Tetris.I);
- cells[1] = new Cell(0,3, Tetris.I);
- cells[2] = new Cell(0,5, Tetris.I);
- cells[3] = new Cell(0,6, Tetris.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);
- }
-
- }
- package xingzhuang;
-
- import sifang.Tetris;
- import eluosifangkuai.Cell;
- import eluosifangkuai.Tetromino;
-
- public class J extends Tetromino {
- public J() {
- cells[0] = new Cell(0,4, Tetris.J);
- cells[1] = new Cell(0,3, Tetris.J);
- cells[2] = new Cell(0,5, Tetris.J);
- cells[3] = new Cell(1,5, Tetris.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);
- }
- }
- package xingzhuang;
-
- import sifang.Tetris;
- import eluosifangkuai.Cell;
- import eluosifangkuai.Tetromino;
-
-
- public class L extends Tetromino {
- public L() {
- cells[0] = new Cell(0,4, Tetris.L);
- cells[1] = new Cell(0,3, Tetris.L);
- cells[2] = new Cell(0,5, Tetris.L);
- cells[3] = new Cell(1,3, Tetris.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);
- }
- }
- package xingzhuang;
-
- import sifang.Tetris;
- import eluosifangkuai.Cell;
- import eluosifangkuai.Tetromino;
-
- public class O extends Tetromino {
- public O() {
- cells[0] = new Cell(0, 4, Tetris.O);
- cells[1] = new Cell(0, 5, Tetris.O);
- cells[2] = new Cell(1, 4, Tetris.O);
- cells[3] = new Cell(1, 5, Tetris.O);
-
- //无旋转状态
- states = new State[0];
- }
- }
- package xingzhuang;
-
-
- import sifang.Tetris;
- import eluosifangkuai.Cell;
- import eluosifangkuai.Tetromino;
-
-
- public class S extends Tetromino {
- public S() {
- cells[0] = new Cell(0,4, Tetris.S);
- cells[1] = new Cell(0,5, Tetris.S);
- cells[2] = new Cell(1,3, Tetris.S);
- cells[3] = new Cell(1,4, Tetris.S);
-
- //共有两种旋转状态
- states =new State[2];
- //初始化两种状态的相对坐标
- states[0]=new State(0,0,0,1,1,-1,1,0);
- states[1]=new State(0,0,1,0,-1,-1,0,-1);
- }
- }
- package xingzhuang;
-
- import sifang.Tetris;
- import eluosifangkuai.Cell;
- import eluosifangkuai.Tetromino;
-
- public class T extends Tetromino {
- public T() {
- cells[0] = new Cell(0,4, Tetris.T);
- cells[1] = new Cell(0,3, Tetris.T);
- cells[2] = new Cell(0,5, Tetris.T);
- cells[3] = new Cell(1,4, Tetris.T);
-
- states=new State[4];
- states[0]=new State(0,0,0,-1,0,1,1,0);
- states[1]=new State(0,0,-1,0,1,0,0,-1);
- states[2]=new State(0,0,0,1,0,-1,-1,0);
- states[3]=new State(0,0,1,0,-1,0,0,1);
- }
- }
- package xingzhuang;
- import sifang.Tetris;
- import eluosifangkuai.Cell;
- import eluosifangkuai.Tetromino;
-
- public class Z extends Tetromino {
- public Z() {
- cells[0] = new Cell(1,4, Tetris.Z);
- cells[1] = new Cell(0,3, Tetris.Z);
- cells[2] = new Cell(0,4, Tetris.Z);
- cells[3] = new Cell(1,5, Tetris.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);
- }
- }
4.游戏运行主类
- package sifang;
- import eluosifangkuai.Cell;
- import eluosifangkuai.Tetromino;
-
- import javax.imageio.ImageIO;
- import javax.swing.*;
- import java.awt.*;
- import java.awt.event.KeyAdapter;
- import java.awt.event.KeyEvent;
- import java.awt.event.KeyListener;
- import java.awt.image.BufferedImage;
- import java.io.File;
- import java.io.IOException;
- import java.security.cert.Certificate;
-
- public class Tetris extends JPanel {
-
- //正在下落的方块
- private Tetromino currentOne = Tetromino.randomOne();
- //将要下落的方块
- private Tetromino nextOne = Tetromino.randomOne();
- //游戏主区域
- private Cell[][] wall = new Cell[18][9];
- //声明单元格的值
- private static final int CELL_SIZE = 48;
-
- //游戏分数池
- int[] scores_pool = {0, 1, 2, 5, 10};
- //当前游戏的分数
- private int totalScore = 0;
- //当前消除的行数
- private int totalLine = 0;
-
- //游戏三种状态 游戏中、暂停、结束
- public static final int PLING = 0;
- public static final int STOP = 1;
- public static final int OVER = 2;
- //当前游戏状态值
- private int game_state;
- //显示游戏状态
- String[] show_state = {"P[pause]", "C[continue]", "S[replay]"};
-
-
- //载入方块图片
- public static BufferedImage I;
- public static BufferedImage J;
- public static BufferedImage L;
- public static BufferedImage O;
- public static BufferedImage S;
- public static BufferedImage T;
- public static BufferedImage Z;
- public static BufferedImage background;
-
- static {
- try {
- I = ImageIO.read(new File("images/I.png"));
- J = ImageIO.read(new File("images/J.png"));
- L = ImageIO.read(new File("images/L.png"));
- O = ImageIO.read(new File("images/O.png"));
- S = ImageIO.read(new File("images/S.png"));
- T = ImageIO.read(new File("images/T.png"));
- Z = ImageIO.read(new File("images/Z.png"));
- background = ImageIO.read(new File("images/background.png"));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- @Override
- public void paint(Graphics g) {
- g.drawImage(background, 0, 0, null);
- //平移坐标轴
- g.translate(22, 15);
- //绘制游戏主区域
- paintWall(g);
- //绘制正在下落的四方格
- paintCurrentOne(g);
- //绘制下一个将要下落的四方格
- paintNextOne(g);
- //绘制游戏得分
- paintSource(g);
- //绘制当前游戏状态
- paintState(g);
- }
-
- public void start() {
- game_state = PLING;
- KeyListener l = new KeyAdapter() {
- @Override
- public void keyPressed(KeyEvent e) {
- int code = e.getKeyCode();
- switch (code) {
- case KeyEvent.VK_DOWN:
- sortDropActive();
- break;
- case KeyEvent.VK_LEFT:
- moveleftActive();
- break;
- case KeyEvent.VK_RIGHT:
- moveRightActive();
- break;
- case KeyEvent.VK_UP:
- rotateRightActive();
- break;
- case KeyEvent.VK_SPACE:
- hadnDropActive();
- break;
- case KeyEvent.VK_P:
- //判断当前游戏状态
- if (game_state == PLING) {
- game_state = STOP;
- }
- break;
- case KeyEvent.VK_C:
- if (game_state == STOP) {
- game_state = PLING;
- }
- break;
- case KeyEvent.VK_S:
- //重新开始
- game_state = PLING;
- wall = new Cell[18][9];
- currentOne = Tetromino.randomOne();
- nextOne = Tetromino.randomOne();
- totalScore = 0;
- totalLine = 0;
- break;
- }
- }
- };
- //将窗口设置为焦点
- this.addKeyListener(l);
- this.requestFocus();
-
- while (true) {
- if (game_state == PLING) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- if (camDrop()) {
- currentOne.moveDrop();
- } else {
- landToWall();
- destroyLine();
- if (isGameOver()) {
- game_state = OVER;
- } else {
- //游戏没有结束
- currentOne = nextOne;
- nextOne = Tetromino.randomOne();
- }
- }
- }
- repaint();
- }
- }
-
- //创建顺时针旋转
- public void rotateRightActive() {
- currentOne.rotateRight();
- if (outOFBounds() || coincide()) {
- currentOne.rotateLeft();
- }
- }
-
- //瞬间下落
- public void hadnDropActive() {
- while (true) {
- //判断能否下落
- if (camDrop()) {
- currentOne.moveDrop();
- } else {
- break;
- }
- }
- //嵌入到墙中
- landToWall();
- destroyLine();
- if (isGameOver()) {
- game_state = OVER;
- } else {
- //游戏没有结束
- currentOne = nextOne;
- nextOne = Tetromino.randomOne();
- }
- }
-
- //按键一次,下落一格
- public void sortDropActive() {
- if (camDrop()) {
- //当前四方格下落一格
- currentOne.moveDrop();
- } else {
- landToWall();
- destroyLine();
- if (isGameOver()) {
- game_state = OVER;
- } else {
- //游戏没有结束
- currentOne = nextOne;
- nextOne = Tetromino.randomOne();
- }
- }
- }
-
- //单元格嵌入墙中
- private void landToWall() {
- Cell[] cells = currentOne.cells;
- for (Cell cell : cells) {
- int row = cell.getRow();
- int col = cell.getCol();
- wall[row][col] = cell;
- }
- }
-
- //判断四方格能否下落
- public boolean camDrop() {
- Cell[] cells = currentOne.cells;
- for (Cell cell : cells) {
- int row = cell.getRow();
- int col = cell.getCol();
- //判断是否到达底部
- if (row == wall.length - 1) {
- return false;
- } else if (wall[row + 1][col] != null) {
- return false;
- }
- }
- return true;
- }
-
- //消除行
- public void destroyLine() {
- int line = 0;
- Cell[] cells = currentOne.cells;
- for (Cell cell : cells) {
- int row = cell.getRow();
- if (isFullLine(row)) {
- line++;
- for (int i = row; i > 0; i--) {
- System.arraycopy(wall[i - 1], 0, wall[i], 0, wall[0].length);
- }
- wall[0] = new Cell[9];
- }
- }
- //分数池获取分数,累加到总分
- totalScore += scores_pool[line];
- //总行数
- totalLine += line;
- }
-
- //判断当前行是否已经满了
- public boolean isFullLine(int row) {
- Cell[] cells = wall[row];
- for (Cell cell : cells) {
- if (cell == null) {
- return false;
- }
- }
- return true;
- }
-
- //判断游戏是否结束
- public boolean isGameOver() {
- Cell[] cells = nextOne.cells;
- for (Cell cell : cells) {
- int row = cell.getRow();
- int col = cell.getCol();
- if (wall[row][col] != null) {
- return true;
- }
- }
- return false;
- }
-
- private void paintState(Graphics g) {
- if (game_state == PLING) {
- g.drawString(show_state[PLING], 500, 660);
- } else if (game_state == STOP) {
- g.drawString(show_state[STOP], 500, 660);
- } else {
- g.drawString(show_state[OVER], 500, 660);
- g.setColor(Color.RED);
- g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 60));
- g.drawString("GAME OVER!", 30, 400);
- }
- }
-
- private void paintSource(Graphics g) {
- g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 30));
- g.drawString("分数: " + totalScore, 500, 250);
- g.drawString("行数: " + totalLine, 500, 430);
- }
-
- private void paintNextOne(Graphics g) {
- Cell[] cells = nextOne.cells;
- for (Cell cell : cells) {
- int x = cell.getCol() * CELL_SIZE + 370;
- int y = cell.getRow() * CELL_SIZE + 25;
- g.drawImage(cell.getImage(), x, y, null);
- }
- }
-
- private void paintCurrentOne(Graphics g) {
- Cell[] cells = currentOne.cells;
- for (Cell cell : cells) {
- int x = cell.getCol() * CELL_SIZE;
- int y = cell.getRow() * CELL_SIZE;
- g.drawImage(cell.getImage(), x, y, null);
- }
- }
-
- private void paintWall(Graphics g) {
- for (int i = 0; i < wall.length; i++) {
- for (int j = 0; j < wall[i].length; j++) {
- int x = j * CELL_SIZE;
- int y = i * CELL_SIZE;
- Cell cell = wall[i][j];
- //判断是否有小方块
- if (cell == null) {
- g.drawRect(x, y, CELL_SIZE, CELL_SIZE);
- } else {
- g.drawImage(cell.getImage(), x, y, null);
- }
- }
- }
- }
-
- //判断是否出界
- public boolean outOFBounds() {
- Cell[] cells = currentOne.cells;
- for (Cell cell : cells) {
- int col = cell.getCol();
- int row = cell.getRow();
- if (row < 0 || row > wall.length - 1 || col < 0 || col > wall[0].length-1) {
- return true;
- }
- }
- return false;
- }
-
- //按键一次,左移一次
- public void moveleftActive() {
- currentOne.moveLeft();
- //判断是否越界或重合
- if (outOFBounds() || coincide()) {
- currentOne.moveRight();
- }
- }
-
- //按键一次,右移一次
- public void moveRightActive() {
- currentOne.moveRight();
- //判断是否越界或重合
- if (outOFBounds() || coincide()) {
- currentOne.moveLeft();
- }
- }
-
- //判断是否重合
- public boolean coincide() {
- Cell[] cells = currentOne.cells;
- for (Cell cell : cells) {
- int row = cell.getRow();
- int col = cell.getCol();
- if (wall[row][col] != null) {
- return true;
- }
- }
- return false;
- }
-
- public static void main(String[] args) {
- JFrame jFrame = new JFrame("俄罗斯方块");
- //创建游戏界面
- Tetris panel = new Tetris();
- jFrame.add(panel);
- //设置可见
- jFrame.setVisible(true);
- //设置窗口大小
- jFrame.setSize(810, 940);
- //设置剧中
- jFrame.setLocationRelativeTo(null);
- //设置窗口关闭时停止
- jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-
- //游戏主要开始逻辑
- panel.start();
- }
- }
运行结果