【Java小游戏】俄罗斯方块

文章目录

  • 规则
  • 准备工作
  • 编写小方块类
  • 编写四方格父类
  • 创建7种不同的形状
  • 编写俄罗斯方块主类
    • 初始化7种形状
  • 随机生成四方格
  • 创建游戏场景
  • 绘制游戏
    • 绘制游戏背景
    • 绘制游戏主区域
    • 绘制正在下落的四方格
    • 绘制下一个下落的四方格
    • 绘制游戏得分
    • 绘制游戏状态
  • 编写游戏逻辑
    • 判断方块是否出界
    • 判断方块是否重合
    • 按键一次左移一次和右移一次
    • 四方格变形
      • 初始化7个形状的相对坐标
      • 顺时针旋转四方格
      • 逆时针旋转四方格
      • 基础图像顺时针旋转
    • 判断游戏是否结束
    • 消行并记分
    • 判断四方格能否下落
    • 按键一次四方格下落一个
    • 瞬间下落
  • 调用游戏逻辑完成游戏操作
    • 键盘监听事件并且设置四方格自动下落
    • 游戏逻辑封装在方法中

规则

俄罗斯方块相信大家小时候都玩过,今天我们用Java来实现简易版俄罗斯方块。我们先了解其基本规则:

  1. 方块会从上方缓慢下落,玩家可以通过键盘上的上下左右键来控制方块。
  2. 方块移到区域最下方或是着地到其他方块上无法移动时,就会固定在该处,而新的方块出现在区域上方开始落下。
  3. 当区域中某一列横向格子全部由方块填满,则该列会消失并成为玩家的得分。同时删除的列数越多,得分指数上升。
  4. 当固定的方块堆到区域最上方而无法消除层数时或者大于游戏区域时,则游戏结束。

tip: 这里的规则图形是由4个小型正方形组成的,英文称为Tetromino,中文通称为方块共有7种,分别以S、Z、L、J、I、O、T这7个字母的形状来命名。

趣味小知识: 你知道为什么俄罗斯方块只有这几种形状吗?

答案:如果这四个小正方形拼起来只有一层,那么只有一种形状,我们可以把这种形状称为 “长条”,如果这四个小正方形拼起来形成两层,那么可以有两种情况:“上一下三"和"上二下二”,对于"上二下二”的情况,显然也有三种拼法,我们从左到右,把这三种形状分别称为 “左二二形”,“四方形"和"右二二形”.

准备工作

编译软件:IntelliJ IDEA
JDK版本:8.0
使用素材:

小方块和背景图片:链接
源码:链接

编写小方块类

由于基本方块是由4个小方块组成,所以我们可以把小方块单独抽象为Cell类.

小方块属性:小方块的行,列坐标以及每个单元格的图片
小方块的方法:左移一格,右移一格,下移一格。

import java.awt.image.BufferedImage;


/**
 * 描述:小方块类
 * 属性:行,列以及单元格的图片
 * 方法: 左移一格,右移一格,下移一格
 */

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;
    }
    //左移
    public void left() {
        col--;
    }
    //右移
    public void right() {
        col++;
    }
    //下移
    public void soft() {
        row++;
    }
}

编写四方格父类

四方格都是由四格小方块组成,都可以进行左移,右移,下移以及它特有的变形(变形相对复杂,暂时不写)

/**
 * 描述:四方格父类
 * 属性:Cell[]数组用于创建4个小方块
 * 方法:左移一格,右移一格,下移一格,变形(等会写)
 */

public class Tetromino {
    protected Cell[] cells = new Cell[4];

    //左移
    public void moveLeft() {
        for (Cell cell : cells) {
            cell.left();
        }
    }
    //右移
    public void moveRight() {
        for (Cell cell : cells) {
            cell.right();
        }
    }
    //下移
    public void sftDrop() {
        for (Cell cell : cells) {
            cell.drop();
        }
    }
}

创建7种不同的形状

7 个不同的形状分别使用 I、 T、 L、 J、 S、 Z、 O 表示,并且继承四方个父类用于初始化小方块的位置达到形成基本形状的作用。

  • I
public class I extends Tetromino{
}
  • J
public class J extends Tetromino{
}
  • L
public class L extends Tetromino{
}
  • O
public class O extends Tetromino{
}
  • S
public class S extends Tetromino{
}
  • T
public class T extends Tetromino{
}
  • Z
public class Z extends Tetromino{
}

编写俄罗斯方块主类

编写俄罗斯方块主类并并且继承JPanel框架,然后静态载入图片:

  • Tetris
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

//俄罗斯方块主类
public class Tetris extends JPanel {
    //静态载入图片
    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;

    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"));

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

初始化7种形状

按照图片规则来放置小方块,方便变形

  • I
    【Java小游戏】俄罗斯方块_第1张图片
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);
    }
}
  • J
    【Java小游戏】俄罗斯方块_第2张图片
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);
    }
}
  • L
    【Java小游戏】俄罗斯方块_第3张图片
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);
    }
}
  • O
    【Java小游戏】俄罗斯方块_第4张图片
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);
    }
}
  • S

【Java小游戏】俄罗斯方块_第5张图片

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);
    }
}
  • T
    【Java小游戏】俄罗斯方块_第6张图片
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);
    }
}
  • Z

【Java小游戏】俄罗斯方块_第7张图片

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);
    }
}

随机生成四方格

在四方格父类种编写随机生成7种形状的静态方法:

    //随机生成四方格
    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;
    }

在俄罗斯方块类 Tetris 中,抽象相应的成员:

currentOne 表示正在下落的方块
nextOnt 表示将要下落的方块
wall 表示游戏主区域

    //声明正在下落的方块
    private Tetromino currentOne = Tetromino.randomOne();
    //声明将要下落的方块
    private Tetromino nextOne = Tetromino.randomOne();
    //声明游戏主区域
    private Cell[][] wall = new Cell[18][9];

创建游戏场景

在俄罗斯方块主类中创建main方法,并且创建游戏窗口(810 * 940)

    public static void main(String[] args) {
        //创建窗口对象
        JFrame frame = new JFrame("俄罗斯方块");
        //设置可见
        frame.setVisible(true);
        //设置窗口尺寸
        frame.setSize(810,940);
        //设置窗口居中
        frame.setLocationRelativeTo(null);
        //设置窗口关闭时程序中止
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

绘制游戏

绘制游戏背景

  1. 在main方法中,先创建游戏界面并嵌入到窗口中
    public static void main(String[] args) {
        //创建窗口对象
        JFrame frame = new JFrame("俄罗斯方块");
        //创建游戏窗口(即面板)
        Tetris panel = new Tetris();
        //把面板嵌入到窗口中
        frame.add(panel);
        //设置可见
        frame.setVisible(true);
        //设置窗口尺寸
        frame.setSize(810,940);
        //设置窗口居中
        frame.setLocationRelativeTo(null);
        //设置窗口关闭时程序中止
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
  1. 重写paint方法

【Java小游戏】俄罗斯方块_第8张图片
增加代码和运行图如下:

绘制游戏主区域

绘制游戏主区域(18行9列的二维数组),由于小方块的像素为48,所以在绘制主区域时要把每个单元格的宽度和高度设置为48像素,

  1. 声明单元格像素为48像素

【Java小游戏】俄罗斯方块_第9张图片

  1. 绘制游戏主区域

【Java小游戏】俄罗斯方块_第10张图片
效果图:
【Java小游戏】俄罗斯方块_第11张图片
我们发现游戏主区域不在左上角,所以我们要添加偏移值,效果图:
【Java小游戏】俄罗斯方块_第12张图片

绘制正在下落的四方格

首先获取随机生成四方格赋给 Cell 数组,然后遍历 Cell 数组,取得每个小方格的行号和列号乘以宽度值,将每个小方格作为图片画到游戏主区域中,然后再在 paint 方法中调用,
【Java小游戏】俄罗斯方块_第13张图片

绘制下一个下落的四方格

原理同上,但是要设置偏移值,因为它应该出现在右边第一个方框中;

【Java小游戏】俄罗斯方块_第14张图片

绘制游戏得分

创建存储分数的一系列变量:

scores_pool表示游戏分数池,一行1分,两行2分,三行5分,四行10分。
totalScore 表示当前获得的总分
totalLine 表示当前已消除的总行数

    //游戏分数池
    int[] scores_pool = {0, 1, 2, 5, 10};
    //游戏总分
    private int totalScore = 0;
    //游戏消除总行数
    private int totalLine = 0;

在游戏主区域上显示当前游戏得分

  1. 编写paintScore方法作用是显示分数
  2. g.setFont 设置字符串的格式,g.drawString 用于绘制字符串

【Java小游戏】俄罗斯方块_第15张图片

绘制游戏状态

游戏共有三种状态:游戏中,暂停游戏,游戏结束,用常量来标记;再用一个常量表面当前状态:

【Java小游戏】俄罗斯方块_第16张图片

用一个数组来显示当前游戏状态:

【Java小游戏】俄罗斯方块_第17张图片

在paint中编写paintState(g)方法显示当前游戏状态

【Java小游戏】俄罗斯方块_第18张图片

编写游戏逻辑

判断方块是否出界

    //判断方块是否出界,出界返回true,没有则返回false
    public boolean outOfBounds() {
        Cell[] cells = currentOne.cells;
        for (Cell cell : cells) {
            int col = cell.getCol();
            int row = cell.getRow();
            if (col < 0 || col > COL - 1 || row < 0 || row > ROW - 1) {
                return true;
            }
        }
        return false;
    }
  • 我们用静态变量代表当前的行列
    【Java小游戏】俄罗斯方块_第19张图片

判断方块是否重合

    //判断方块是否重合,重合返回true,没有返回false
    public boolean coincide() {
        Cell[] cells = currentOne.cells;
        for (Cell cell : cells) {
            int col = cell.getCol();
            int row = cell.getRow();
            if (wall[row][col] != null) {
                return true;
            }
        }
        return false;
    }

按键一次左移一次和右移一次

    //按键←触发左移
    public void moveLeftAction() {
        currentOne.moveLeft();
        //判断是否越界或者重合,如果是则右移恢复原来的状态,不是则左移
        if (outOfBounds() || coincide()) {
            currentOne.moveRight();
        }
    }
    //按键→触发右移
    public void moveRightAction() {
        currentOne.moveRight();
        //判断是否越界或者重合,如果是则左移恢复原来的状态,不是则右移
        if (outOfBounds() || coincide()) {
            currentOne.moveLeft();
        }
    }

四方格变形

记录每个方块在不同形状时相对于序号为0的小方块的位置

首先,在四方格父类 Tetromino 中添加**旋转状态属性和计数器,**计数器的取值最好设置为能被 4 整除的数.用计数器对当前状态取余即可得到当前旋转状态。
在四方格父类中编写一个内部类旋转状态 State,属性:存储四方格各元素的相对位置

   //编写旋转状态
    protected State[] states;
    //声明旋转次数
    protected int count = 10000;
    /**描述:四方格旋转状态的内部类
     * 属性:记录四方格的相对位置
     */
    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 getRow1() {
            return row1;
        }

        public void setRow1(int row1) {
            this.row1 = row1;
        }

        public int getRow2() {
            return row2;
        }

        public void setRow2(int row2) {
            this.row2 = row2;
        }

        public int getRow3() {
            return row3;
        }

        public void setRow3(int row3) {
            this.row3 = row3;
        }

        public int getCol0() {
            return col0;
        }

        public void setCol0(int col0) {
            this.col0 = col0;
        }

        public int getCol1() {
            return col1;
        }

        public void setCol1(int col1) {
            this.col1 = col1;
        }

        public int getCol2() {
            return col2;
        }

        public void setCol2(int col2) {
            this.col2 = col2;
        }

        public int getCol3() {
            return col3;
        }

        public void setCol3(int col3) {
            this.col3 = col3;
        }
    }

初始化7个形状的相对坐标

  • I 共计有两种旋转状态,在 I 无参构造方法中初始化两种状态的相对坐标:
    【Java小游戏】俄罗斯方块_第20张图片
    【Java小游戏】俄罗斯方块_第21张图片
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);
    }
}
  • T 共计有四种旋转状态,在 T 无参构造方法中初始化四种状态的相对坐标:
    【Java小游戏】俄罗斯方块_第22张图片
    【Java小游戏】俄罗斯方块_第23张图片
    【Java小游戏】俄罗斯方块_第24张图片
    【Java小游戏】俄罗斯方块_第25张图片
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);

        //4种状态
        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);
    }
}
  • L 共计有四种旋转状态,在 L 无参构造方法中初始化四种状态的相对坐标,

【Java小游戏】俄罗斯方块_第26张图片
【Java小游戏】俄罗斯方块_第27张图片
【Java小游戏】俄罗斯方块_第28张图片
【Java小游戏】俄罗斯方块_第29张图片

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);
        //4种状态
        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 共计有四种旋转状态,在 J 无参构造方法中初始化四种状态的相对坐标:

【Java小游戏】俄罗斯方块_第30张图片
【Java小游戏】俄罗斯方块_第31张图片
【Java小游戏】俄罗斯方块_第32张图片
【Java小游戏】俄罗斯方块_第33张图片

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);
        //4种状态
        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);
    }
}
  • S 共计有两种旋转状态,在 S 无参构造方法中初始化两种状态的相对坐标:

【Java小游戏】俄罗斯方块_第34张图片
【Java小游戏】俄罗斯方块_第35张图片

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);
        //2种状态
        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);
    }
}
  • Z 共计有两种旋转状态,在 Z 无参构造方法中初始化两种状态的相对坐标:

【Java小游戏】俄罗斯方块_第36张图片
【Java小游戏】俄罗斯方块_第37张图片

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);
    }
}
  • O 共计有零种旋转状态
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);
        //0种状态
        states = new State[0];
    }
}

顺时针旋转四方格

在四方格父类 Tetromino 类中创建顺时针旋转四方格方法 rotateRight

    //编写顺时针旋转四方格方法
    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() {
        //旋转次数加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 rotateRightAction() {
        currentOne.rotateRight();
        //判断是否越界或者重合,否则恢复原来的状态
        if (outOfBounds() || coincide()) {
            currentOne.rotateLeft();
        }
    }

判断游戏是否结束

也就是判断下一个将要出现方块的位置是否有方块:
    //判断游戏是否结束,结束返回true,继续返回false
    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;
    }

消行并记分

当四个方块嵌入墙中,使得行满时则消除该行并将消除行以上的方块下落到对应行数同时计分。
  1. isFullLine方法判断当前行是否满
    //判断当前行是否满,满返回true,没有满返回false
    public boolean isFullLine(int row) {
        Cell[] cells = wall[row];
        for (Cell cell : cells) {
            if (cell == null) {
                return false;
            }
        }
        return true;
    }
  1. 创建销行方法destroyLine:
    //创建销行方法
    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 canDrop() {
        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 sortDropAction() {
        //判断能否下落
        if (canDrop()) {
            //当前四方格下落一格
            currentOne.softDrop();
        } else {
            //把四方格嵌入墙中
            landToWall();
            //判断能否销行
            destroyLine();
            //判断游戏是否结束
            if (isGameOver()) {
                game_state = GAMEOVER;
            } 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 void handDropAction() {
        while (canDrop()) {
            currentOne.softDrop();
        }
        //把四方格嵌入墙中
        landToWall();
        //判断能否销行
        destroyLine();
        //判断游戏是否结束
        if (isGameOver()) {
            game_state = GAMEOVER;
        } else {
            //继续生成四方格
            currentOne = nextOne;
            nextOne = Tetromino.randomOne();
        }
    }

调用游戏逻辑完成游戏操作

编写一个 start 方法,用于调用游戏操作逻辑并监听键盘和描述游戏主要逻辑。

键盘监听事件并且设置四方格自动下落

  1. 通过调用匿名内部类重写 keyPressed 方法实现按键的响应,
  2. 在游戏中时,四方格每隔 0.5 秒下落一次,直到不能下落,则将四方格嵌入墙中,并且判断消行和游戏是否结束,每次下落都需要重绘一次游戏画面
    public void start() {
        game_state = PLAYING;
        KeyListener listener = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int code = e.getKeyCode();
                switch (code) {
                    case KeyEvent.VK_DOWN: //↓
                        sortDropAction(); //下落一格
                        break;
                    case KeyEvent.VK_LEFT://moveLeftAction(); //左移一格
                        break;
                    case KeyEvent.VK_RIGHT: //→
                        moveRightAction(); //右移一格
                        break;
                    case KeyEvent.VK_UP://rotateRightAction();//顺时针旋转
                        break;
                    case KeyEvent.VK_SPACE://空格
                        handDropAction();//瞬间下落
                        break;
                    case KeyEvent.VK_P: //p
                        //判断游戏是否在运行,没有才能暂停
                        if (game_state == PLAYING) {
                            game_state = PAUSE;
                        }
                        break;
                    case KeyEvent.VK_C:
                        //游戏暂停后,才能继续
                        if (game_state == PAUSE) {
                            game_state = PLAYING;
                        }
                        break;
                    case KeyEvent.VK_R:
                        //重新开始游戏,把游戏状态变为正在游戏
                        game_state = PLAYING;
                        //界面清空
                        wall = new Cell[ROW][COL];
                        currentOne = Tetromino.randomOne();
                        nextOne = Tetromino.randomOne();
                        //数据清空
                        totalLine = 0;
                        totalScore = 0;
                        break;

                }
            }
        };
        //把俄罗斯方块窗口设置为焦点
        this.addKeyListener(listener);
        this.requestFocus();

        while(true){
            //判断,当前游戏状态在游戏中时,每隔0.5秒下落
            if(game_state == PLAYING){
                try {
                    Thread.sleep(700);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //判断能否下落
                if(canDrop()){
                    currentOne.softDrop();
                }else{
                    //嵌入到墙中
                    landToWall();
                    //判断能否消行
                    destroyLine();
                    //判断游戏是否结束
                    if(isGameOver()){
                        game_state = GAMEOVER;
                    }else{
                        currentOne = nextOne;
                        nextOne = Tetromino.randomOne();
                    }
                }
            }
            //重新绘制
            repaint();
        }
    }

游戏逻辑封装在方法中

【Java小游戏】俄罗斯方块_第38张图片

你可能感兴趣的:(JavaSE,java,游戏程序)