java实现俄罗斯方块

主页附完整资源(俄罗斯方块.zip)
下面是代码和素材

utils包

package com.zdq.utils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 静态资源加载工具类
 */
public class SourceUtil {
    /**
     * 静态图片资源
     */
    public static BufferedImage iImage;
    public static BufferedImage jImage;
    public static BufferedImage lImage;
    public static BufferedImage oImage;
    public static BufferedImage sImage;
    public static BufferedImage tImage;
    public static BufferedImage zImage;
    public static BufferedImage backgroundImage;
    public static BufferedImage tetrisLogoImage;

    /**
     * 静态代码块,加载一次静态资源
     */
    static {
        /**
         * ImageIO.read()方法可以读取项目下的静态资源文件
         */
        try {
//            iImage = ImageIO.read(SourceUtil.class.getResource("../image/I.png"));
            iImage = ImageIO.read(SourceUtil.class.getResourceAsStream("/com/zdq/image/I.png"));
            jImage = ImageIO.read(SourceUtil.class.getResourceAsStream("/com/zdq/image/J.png"));
            lImage = ImageIO.read(SourceUtil.class.getResourceAsStream("/com/zdq/image/L.png"));
            oImage = ImageIO.read(SourceUtil.class.getResourceAsStream("/com/zdq/image/O.png"));
            sImage = ImageIO.read(SourceUtil.class.getResourceAsStream("/com/zdq/image/S.png"));
            tImage = ImageIO.read(SourceUtil.class.getResourceAsStream("/com/zdq/image/T.png"));
            zImage = ImageIO.read(SourceUtil.class.getResourceAsStream("/com/zdq/image/Z.png"));
            backgroundImage = ImageIO.read(SourceUtil.class.getResourceAsStream("/com/zdq/image/background.png"));
            tetrisLogoImage = ImageIO.read(SourceUtil.class.getResourceAsStream("/com/zdq/image/tetrisLogo.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

main包
(1)KeyActionListener

package com.zdq.main;

import com.zdq.domain.Cell;
import com.zdq.domain.TetrisModel;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Date;

/**
 * 自定义行为动作监听器,实现人机交互
 */
public class KeyActionListener extends KeyAdapter implements ActionListener {
    //统计消去行的个数
    private int linesCount = 0;

    //在类中创建一个 TetrisPanel对象,以便获取和更新方块对象
    private TetrisPanel tetrisPanel;

    //关卡级别: 默认为 1级
    protected static int level = 1;

    //当前分数
    protected int score = 0;

    //游戏暂停与继续切换标志
    private boolean flag = true;

    //控制下落速度:默认为 1000毫秒
    protected int delay = 800;
    protected Timer timer = new Timer(delay, this);

    //开始游戏的时间
    protected Date startTime;

    //前面累计的游戏时间
    protected long preGameTime;

    public KeyActionListener(TetrisPanel tetrisPanel) {
        this.tetrisPanel = tetrisPanel;
    }

    public KeyActionListener() {
    }

    /**
     * 监听俄罗斯方块对象的动作
     * @param e
     */
    @Override
    public void actionPerformed(ActionEvent e) {
        // 获取当前方块对象,调用下落方法
        boolean ifCanDrop = ifCanDrop();

        if(ifCanDrop) {
            //表示可以下落
            tetrisPanel.currentBlock.moveDrop();
        } else {
            //表示不可下落,但是需要根据实际情况判断 游戏是否终止
            if(ifGameOver()) {
                //游戏结束,终止游戏,并给出友情提示
                timer.stop();

                int confirmDialog = JOptionPane.showConfirmDialog(null, "Game Over! 是否再来一局?");
                if(confirmDialog == JOptionPane.YES_OPTION) {
                    //继续玩
                    // 初始化单元格,重启游戏
                    tetrisPanel.wall = new Cell[20][10];
                    preGameTime = 0;
                    score = 0;
                    delay = 800;
                    level = 0;
                    startTime = new Date();
                    timer.restart();
                } else if(confirmDialog == JOptionPane.NO_OPTION) {
                    //不玩了,关闭程序即可
                    System.exit(0);
                }
            } else {
                //游戏还未结束
                //将方块定格在最后落下的位置
                landToWall();
                //判断是否可以消去一行,并执行
                vanishLine();

                //将下一个要下落的方块赋给当前要下落的方块
                //再生成新的 下一个要下落的方块
                //即 将下落和即将下落构成闭环,不断地落下方块
                tetrisPanel.currentBlock = tetrisPanel.nextBlock;
                tetrisPanel.nextBlock = TetrisModel.randomBlock();
            }
        }
        //重新绘制画布
        tetrisPanel.repaint();
    }

    /**
     * 重写键盘监听器中的键盘键点击事件
     * @param e ==
     */
    @Override
    public void keyPressed(KeyEvent e) {
        //获取监听到的点击的键盘键
        //此方法返回键盘上实际键的整数代码。
        int keyCode = e.getKeyCode();
        switch (keyCode) {
            case KeyEvent.VK_LEFT:
                //按 ←键方块左移
                if(flag) {
                    moveLeftAction();
                    //右移后重新绘制,移动则不会出现卡顿感
                    tetrisPanel.repaint();
                }
                break;
            case KeyEvent.VK_RIGHT:
                //按 →键方块右移
                if(flag) {
                    moveRightAction();
                    //右移后重新绘制,移动则不会出现卡顿感
                    tetrisPanel.repaint();
                }
                break;
            case KeyEvent.VK_DOWN:
                //按 ↓键方块下移
                if(flag) {
                    movePerformed(null);
                }
                break;
            case KeyEvent.VK_UP:
                //按 ↑键方块旋转
                if(flag) {
                    moveRoteAction();
                    //右移后重新绘制,旋转则不会出现卡顿感
                    tetrisPanel.repaint();
                }
                break;
            case KeyEvent.VK_ENTER:
                //按 ENTER键切换游戏暂停或开始
                if(flag) {
                    //暂停游戏时间
                    timer.stop();
                    //算出累计游戏时间
                    Date stopTime = new Date();
                    preGameTime += stopTime.getTime() - startTime.getTime();
                    //游戏暂停
                    flag = false;
                } else {
                    //继续游戏时间
                    timer.start();
                    //游戏继续后,重新设置游戏时间
                    startTime = new Date();
                    flag = true;
                    tetrisPanel.repaint();
                }
                break;
            default:
                break;
        }
    }

    /**
     * 方块旋转实现
     */
    private void moveRoteAction() {
//        if(canStartRote()) {
            tetrisPanel.currentBlock.rotateRight();
//        }

        if(!canRote()) {
            tetrisPanel.currentBlock.rotateLeft();
        }
    }

    /**
     * 判断方块是否出界
     */
    private boolean canStartRote() {
        Cell[] cells = tetrisPanel.currentBlock.cells;

        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();
            if(row <= 0) {
                return false;
            }

            if(row > tetrisPanel.wall.length - 1 || col <= 0 || col >= tetrisPanel.wall[0].length - 1) {
                return false;
            }
        }

        return true;
    }

    /**
     * 判断方块是否重合
     */
    private boolean canRote() {
        Cell[] cells = tetrisPanel.currentBlock.cells;

        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();

            if(row >= 20 || row < 0 || col < 0 || col > 9) {
                return false;
            }

            if(tetrisPanel.wall[row][col] != null) {
                return false;
            }
        }

        return true;
    }

    /**
     * 方块下移实现
     * @param o
     */
    private void movePerformed(Object o) {
        if(ifCanDrop()) {
            tetrisPanel.currentBlock.moveDrop();
            tetrisPanel.repaint();
        }
    }

    /**
     * 方块右移实现
     */
    private void moveRightAction() {
        if(ifCanRight()) {
            tetrisPanel.currentBlock.moveRight();
        }
    }

    /**
     * 单独判断当前方块是否能够右移
     */
    private boolean ifCanRight() {
        Cell[] cells = tetrisPanel.currentBlock.cells;

        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();

            // 判断右侧是否碰到墙体,右侧是墙体则返回false
            if (col == 9) {
                return false;
            }

            //判断右侧是否有方块,有方块也不能右移,返回false
            if (tetrisPanel.wall[row][col + 1] != null) {
                return false;
            }
        }

        //如果方块相邻右侧的位置 即没有方块也不是墙体,则返回true
        return true;
    }

    /**
     * 方块左移实现
     */
    private void moveLeftAction() {
        if(ifCanLeft()) {
            tetrisPanel.currentBlock.moveLeft();
        }
    }

    /**
     * 判断当前方块是否能够左移
     */
    private boolean ifCanLeft() {
        Cell[] cells = tetrisPanel.currentBlock.cells;

        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();

            // 判断左侧是否碰到墙体,左侧是墙体则返回false
            if(col == 0) {
                return false;
            }

            //判断左侧是否有方块,有方块也不能左移,返回false
            if(tetrisPanel.wall[row][col - 1] != null) {
                return false;
            }
        }

        //如果方块相邻左侧的位置 即没有方块也不是墙体,则返回true
        return true;
    }

    /**
     * 将当前下落的方块最后落下的位置 定格到 wall中
     */
    private void landToWall() {
        Cell[] cells = tetrisPanel.currentBlock.cells;

        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();
            tetrisPanel.wall[row][col] = cell;
        }
    }

    /**
     * 如果该行已经填满方块,则消去该行
     */
    private void vanishLine() {
        int singleLinesCount = 0;

        //获取正在下落的方块对象的单元格数组
        Cell[] cells = tetrisPanel.currentBlock.cells;
        for (Cell cell : cells) {
            //取出每个单元格的行号
            int row = cell.getRow();
            while(row < 20) {
                if (isFullLine(row)) {//如果当前行已填满
                    //
                    singleLinesCount++;

                    //重置当前行的单元格
                    tetrisPanel.wall[row] = new Cell[10];

                    //上面的位置下移
                    for (int i = row; i > 0; i--) {
                        System.arraycopy(tetrisPanel.wall[i - 1], 0, tetrisPanel.wall[i], 0, 10);
                    }

                    //在墙体的最顶端新增一行空的单元格
                    tetrisPanel.wall[0] = new Cell[10];
                }
                row++;
            }
        }
        //消行计分的规则 消4行——70分 消3行——50分 消2行——30分 消1行——10分
        score += (20 * singleLinesCount);

        if (score == 200 * level && level <= 10) {
            level++;
            delay -= 30;
        }
    }

    /**
     * 判断当前行是否已经填满单元格
     */
    private boolean isFullLine(int row) {
        //获取 wall当前行的数组,存入一维数组中
        Cell[] cells = tetrisPanel.wall[row];

        for (Cell cell : cells) {
            //如果该行有单元格是null,则表示该行还没填满
            if(cell == null) {
                return false;
            }
        }

        return true;
    }

    /**
     * 判断当前方块是否可以继续下落
     * @return
     */
    private boolean ifCanDrop() {
        //先获取当前即将下落的方块对象
        TetrisModel currentBlock = tetrisPanel.currentBlock;
        //获取方块对象包含的单元格数组
        Cell[] cells = currentBlock.cells;
        //对包含的每个单元格所在行进行判断
        for (Cell cell : cells) {
            int row = cell.getRow();
            int col = cell.getCol();
            //如果当前位置是最后一行,则不能下落
            if(row == 19) {
                return false;
            }

            //如果当前位置下面的单元格被占用,则不能下落
            if(tetrisPanel.wall[row + 1][col] != null) {
                return false;
            }
        }

        //
        return true;
    }

    /**
     * 判断游戏是否结束,即是否 game over
     */
    private boolean ifGameOver() {
        //先获取当前下落的方块对象
        TetrisModel currentBlock = tetrisPanel.currentBlock;
        //获取方块对象包含的单元格数组
        Cell[] cells = currentBlock.cells;

        for (Cell cell : cells) {
            int row = cell.getRow();
            //如果当前行已经是第一行,返回 true,即 game over
            if(row <= 0) {
                return true;
            }
        }

        return false;
    }

    // setter
    public void setTetrisPanel(TetrisPanel tetrisPanel) {
        this.tetrisPanel = tetrisPanel;
    }
}

(2)TetrisMain

package com.zdq.main;

import com.zdq.utils.SourceUtil;

import javax.swing.*;

/**
 * 俄罗斯方块游戏入口
 */
public class TetrisMain {
    public static void main(String[] args) {
        // 创建游戏窗口
        JFrame jFrame = new JFrame("俄罗斯方块");

        //设置窗口logo
        jFrame.setIconImage(SourceUtil.tetrisLogoImage);

        //在游戏窗口容器添加画布
        TetrisPanel tetrisPanel = new TetrisPanel();
        jFrame.add(tetrisPanel);

        // 相关属性设置
        jFrame.setSize(535, 595); //窗口尺寸
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 窗口关闭退出
        jFrame.setLocationRelativeTo(null); // 窗口居中
        jFrame.setResizable(false); // 设置窗口尺寸不可变化

        jFrame.setVisible(true); // 窗口可见

        tetrisPanel.start();
    }
}

(3)TetrisPanel

package com.zdq.main;

import com.zdq.domain.Cell;
import com.zdq.domain.TetrisModel;
import com.zdq.utils.SourceUtil;

import javax.swing.*;
import java.awt.*;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 创建一个游戏画布类
 */
public class TetrisPanel extends JPanel {
    //设置20行,10列的 墙体表格数组
    public Cell[][] wall = new Cell[20][10];

    //设置单元格对象的固定宽高
    private static final int CELL_SIZE = 26;

    //当前下落的俄罗斯方块
    public TetrisModel currentBlock = TetrisModel.randomBlock();

    //下一个下落的俄罗斯方块
    public TetrisModel nextBlock = TetrisModel.randomBlock();

    //获取监听器对象,控制游戏暂停与启动
    private KeyActionListener keyActionListener = new KeyActionListener(this);

    /**
     * 重画父类画图方法
     * @param g 代表画笔
     */
    @Override
    public void paint(Graphics g) {
        //绘制画布背景游戏图
        g.drawImage(SourceUtil.backgroundImage, 0, 0, null);

        //让墙体往右下稍稍偏移,做一个微调
        g.translate(15, 15);

        //绘制主游戏区域的背景墙格子
        paintWall(g);

        //在画布绘制当前下落的俄罗斯方块
        paintCurrentBlock(g);

        //在画布绘制下一个即将下落的俄罗斯方块
        paintNextBlock(g);
    }

    /**
     * 自定义的在画布绘制下一个下落的俄罗斯方块
     * @param g 表示画笔
     */
    private void paintNextBlock(Graphics g) {
        //获取当前方块对象对应的单元格数组
        Cell[] cells = nextBlock.cells;

        for (Cell cell : cells) {
            int x = cell.getCol() * CELL_SIZE + 265;
            int y = cell.getRow() * CELL_SIZE + 25;
            //绘制每个俄罗斯方块对应的单元格即可
            g.drawImage(cell.getImage(), x, y, null);
        }
    }

    /**
     * 自定义地在画布绘制正在下落的俄罗斯方块
     * @param g 表示画笔
     */
    private void paintCurrentBlock(Graphics g) {
        //设置字体相关信息
        Font font = new Font("楷体", Font.CENTER_BASELINE, 22);
        g.setFont(font);
        g.setColor(Color.magenta);

        //关卡信息
        g.drawString("关 卡: " + keyActionListener.level, 285, 160);
        //分数信息
        g.drawString("分 数: " + keyActionListener.score, 285, 220);
        //闯关时间信息
        Date now = new Date();
        //后一阶段的游戏时长 + 之前累计的游戏时长,时间差,毫秒
        long l = now.getTime() - keyActionListener.startTime.getTime() + keyActionListener.preGameTime;
        //对日期时间进行格式化
        SimpleDateFormat format = new SimpleDateFormat("mm分钟ss秒");
        String gameTime = format.format(l);
        g.drawString("时 间: " + gameTime, 285, 275);

        //获取当前方块对象对应的单元格数组
        Cell[] cells = currentBlock.cells;

        for (Cell cell : cells) {
            int x = cell.getCol() * CELL_SIZE;
            int y = cell.getRow() * CELL_SIZE;
            //绘制每个俄罗斯方块对应的单元格即可
            g.drawImage(cell.getImage(), x, y, null);
        }
    }

    /**
     * 自定义的绘制游戏区域
     * @param g 代表画笔
     */
    private void  paintWall(Graphics g) {
        //循环对应的行
        for (int i = 0; i < wall.length; i++) {
            //循环对应的列
            for (int j = 0; j < wall[i].length; j++) {
                //通过 对应的行列坐标获取 对应位置的单元格对象
                Cell cell = wall[i][j];

                //开始初始化单元格对象
                int x = j * CELL_SIZE;
                int y = i * CELL_SIZE;

                //对当前单元格判断,是否存在被占用,即是否被使用
                if(cell == null) {
                    //如果当前位置没有被占用,直接画空的单元格即可
                    g.drawRect(x, y, CELL_SIZE, CELL_SIZE);
                } else {
                    //表示当前单元格已经被其他形状的俄罗斯方块占用,直接绘制对应方块的单元格图片即可
                    g.drawImage(cell.getImage(), x, y, null);
                }
            }
        }
    }

    /**
     * 封装了游戏的主要逻辑
     */
    public void start() {
        //面板添加监听事件
        this.addKeyListener(keyActionListener);

        //面板对象设置成焦点
        this.requestFocus();

        //
        Timer timer = keyActionListener.timer;

        //
        Date date = new Date();
        keyActionListener.startTime = date;

        timer.start();
    }
}

domain包
(1) Cell

package com.zdq.domain;

import java.awt.image.BufferedImage;

/**
 * 俄罗斯方块对应的单元格类
 */
public class Cell {
    private int row;//单元格对应的行

    private int col;//单元格对应的类

    private BufferedImage image;//单元格对应的背景颜色

    //构造器
    public Cell(int row, int col, BufferedImage image) {
        this.row = row;
        this.col = col;
        this.image = image;
    }

    public Cell() {
    }

    /**
     * 单元格左移
     */
    public void left() {
        col--;
    }

    /**
     * 单元格右移
     */
    public void right() {
        col++;
    }

    /**
     * 单元格下移
     */
    public void drop() {
        row++;
    }

    //对应的 getter和 setter
    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;
    }
}

(2)I

package com.zdq.domain;

import com.zdq.utils.SourceUtil;

/**
 * 对应的 I形状俄罗斯方块
 */
public class I extends TetrisModel {
    /**
     * 对默认构造方法进行改造,进行属性变量的初始化:
     * 初始化方块中每一个单元格的位置,还有背景图片
     */
    public I() {
        cells[0] = new Cell(0, 4, SourceUtil.iImage);
        cells[1] = new Cell(0, 3, SourceUtil.iImage);
        cells[2] = new Cell(0, 5, SourceUtil.iImage);
        cells[3] = new Cell(0, 6, SourceUtil.iImage);

        //两种旋转状态
        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);
    }
}

(3)J

package com.zdq.domain;

import com.zdq.utils.SourceUtil;

/**
 * 对应的 J形状俄罗斯方块
 */
public class J extends TetrisModel {
    /**
     * 对默认构造方法进行改造,进行属性变量的初始化:
     * 初始化方块中每一个单元格的位置,还有背景图片
     */
    public J() {
        cells[0] = new Cell(0, 4, SourceUtil.jImage);
        cells[1] = new Cell(0, 3, SourceUtil.jImage);
        cells[2] = new Cell(0, 5, SourceUtil.jImage);
        cells[3] = new Cell(1, 3, SourceUtil.jImage);

        //四种旋转状态
        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);
    }
}

(4)L

package com.zdq.domain;

import com.zdq.utils.SourceUtil;

/**
 * 对应的 L形状俄罗斯方块
 */
public class L extends TetrisModel {
    /**
     * 对默认构造方法进行改造,进行属性变量的初始化:
     * 初始化方块中每一个单元格的位置,还有背景图片
     */
    public L() {
        cells[0] = new Cell(0, 4, SourceUtil.lImage);
        cells[1] = new Cell(0, 3, SourceUtil.lImage);
        cells[2] = new Cell(0, 5, SourceUtil.lImage);
        cells[3] = new Cell(1, 5, SourceUtil.lImage);

        //四种旋转状态
        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);

    }
}

(5)O

package com.zdq.domain;

import com.zdq.utils.SourceUtil;

/**
 * 对应的 O形状俄罗斯方块
 */
public class O extends TetrisModel {
    /**
     * 对默认构造方法进行改造,进行属性变量的初始化:
     * 初始化方块中每一个单元格的位置,还有背景图片
     */
    public O() {
        cells[0] = new Cell(0, 4, SourceUtil.oImage);
        cells[1] = new Cell(0, 5, SourceUtil.oImage);
        cells[2] = new Cell(1, 4, SourceUtil.oImage);
        cells[3] = new Cell(1, 5, SourceUtil.oImage);

        states = new State[0];
    }
}

(6)S

package com.zdq.domain;

import com.zdq.utils.SourceUtil;

/**
 * 对应的 S形状俄罗斯方块
 */
public class S extends TetrisModel {
    /**
     * 对默认构造方法进行改造,进行属性变量的初始化:
     * 初始化方块中每一个单元格的位置,还有背景图片
     */
    public S() {
        cells[0] = new Cell(0, 4, SourceUtil.sImage);
        cells[1] = new Cell(0, 5, SourceUtil.sImage);
        cells[2] = new Cell(1, 3, SourceUtil.sImage);
        cells[3] = new Cell(1, 4, SourceUtil.sImage);

        //四种旋转状态
        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);

    }
}

(7)T

package com.zdq.domain;

import com.zdq.utils.SourceUtil;

/**
 * 对应的 T形状俄罗斯方块
 */
public class T extends TetrisModel {
    /**
     * 对默认构造方法进行改造,进行属性变量的初始化:
     * 初始化方块中每一个单元格的位置,还有背景图片
     */
    public T() {
        cells[0] = new Cell(0, 4, SourceUtil.tImage);
        cells[1] = new Cell(0, 3, SourceUtil.tImage);
        cells[2] = new Cell(0, 5, SourceUtil.tImage);
        cells[3] = new Cell(1, 4, SourceUtil.tImage);

        //四种旋转状态
        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);
    }
}

(8)TetrisModel

package com.zdq.domain;

import java.util.Random;

/**
 * 向上抽取的方块父类
 */
public class TetrisModel {
    //以数组的形式封装四个单元格
    public Cell[] cells = new Cell[4];
    //编写旋转状态
    public State[] states;
    //编写旋转次数
    protected int count = 10000;

    //四方格旋转状态的内部类
    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;
        }

        public State() {
        }

        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 +
                    '}';
        }
    }

    /**
     * 方块顺时针旋转
     */
    public void rotateRight() {
        // O形方块不旋转,直接返回
        if(this instanceof O) {
            return;
        }

        //旋转次数增加
        count++;
        State state = states[count % states.length];
        Cell cell = cells[0];
        int row = cell.getRow();
        int col = cell.getCol();
        cells[1].setRow(row + state.row1);
        cells[1].setCol(col + state.col1);
        cells[2].setRow(row + state.row2);
        cells[2].setCol(col + state.col2);
        cells[3].setRow(row + state.row3);
        cells[3].setCol(col + state.col3);
    }

    /**
     * 方块逆时针旋转
     */
    public void rotateLeft() {
        if(this instanceof O) {
            return;
        }

        //旋转次数减少
        count--;
        State state = states[count % states.length];
        Cell cell = cells[0];
        int row = cell.getRow();
        int col = cell.getCol();
        cells[1].setRow(row + state.row1);
        cells[1].setCol(col + state.col1);
        cells[2].setRow(row + state.row2);
        cells[2].setCol(col + state.col2);
        cells[3].setRow(row + state.row3);
        cells[3].setCol(col + state.col3);
    }

    /**
     * 方块左移
     */
    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.drop();
        }
    }

    /**
     * 随机生成不同的俄罗斯方块
     */
    public static TetrisModel randomBlock() {
        //创建 TetrisModel对象
        TetrisModel tetrisModel = new TetrisModel();
        //生成范围 [0,6]的随机整数
        int num = new Random().nextInt(7);

        switch (num) {
            case 0:
                tetrisModel = new I();
                break;
            case 1:
                tetrisModel = new J();
                break;
            case 2:
                tetrisModel = new L();
                break;
            case 3:
                tetrisModel = new O();
                break;
            case 4:
                tetrisModel = new S();
                break;
            case 5:
                tetrisModel = new T();
                break;
            case 6:
                tetrisModel = new Z();
                break;
        }

        //返回随机生成的俄罗斯方块对象
        return tetrisModel;
    }
}

(9)Z

package com.zdq.domain;

import com.zdq.utils.SourceUtil;

/**
 * 对应的 Z形状俄罗斯方块
 */
public class Z extends TetrisModel {
    /**
     * 对默认构造方法进行改造,进行属性变量的初始化:
     * 初始化方块中每一个单元格的位置,还有背景图片
     */
    public Z() {
        cells[0] = new Cell(1, 4, SourceUtil.zImage);
        cells[1] = new Cell(0, 3, SourceUtil.zImage);
        cells[2] = new Cell(0, 4, SourceUtil.zImage);
        cells[3] = new Cell(1, 5, SourceUtil.zImage);

        //四种旋转状态
        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);
    }
}

image包

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值