俄罗斯方块和贪吃蛇

贪吃蛇

一、创建新项目

创建一个新的项目,并命名。

创建一个名为images的文件夹用来存放游戏相关图片。

然后再在项目的src文件下创建一个com.xxx.view的包用来存放所有的图形界面类,

创建一个com.xxx.controller的包用来存放启动的入口类(控制类)

二、游戏界面 

 
  1. package com.snake.view;
    
    
    import java.awt.Color;
    
    import java.awt.EventQueue;
    
    import java.awt.Font;
    
    import java.awt.Frame;
    
    import java.awt.Graphics;
    
    import java.awt.Image;
    
    import java.util.ArrayList;
    
    import java.util.List;
    
    import java.util.Random;
    
    
    import javax.swing.ImageIcon;
    
    import javax.swing.JFrame;
    
    import javax.swing.JOptionPane;
    
    import javax.swing.JPanel;
    
    import javax.swing.Timer;
    
    import javax.swing.border.EmptyBorder;
    
    
    
    import java.awt.event.ActionEvent;
    
    import java.awt.event.ActionListener;
    
    import java.awt.event.KeyAdapter;
    
    import java.awt.event.KeyEvent;
    
    
    public class SnakeJPanel extends JPanel implements ActionListener{
    
    
    private boolean start;//当前游戏状态
    
    
    private int speed;//速度
    
    
    private boolean exist;//当前是否存在食物
    
    
    private int foodType;//食物种类
    
    
    private int x;//豆子的横坐标
    
    private int y;//豆子的纵坐标
    
    
    private ArrayList<int[]> localList;//蛇
    
    
    
    public String direction;//方向
    
    
    private String direction2;//引导方向
    
    
    public boolean flag;
    
    
    Random rand = new Random();
    
    
    private ImageIcon up;
    
    
    private ImageIcon down;
    
    
    private ImageIcon right;
    
    
    private ImageIcon left;
    
    
    private ImageIcon body;
    
    
    private ImageIcon food;
    
    
    private ImageIcon title;
    
    
    Timer time;
    
    
    private int score;//当前得分情况
    
    
    private int num;//吃到的食物个数
    
    
    // private Image offScreenImage; //图形缓存
    
    
    
    //图片绘制
    
    @Override
    
    public void paint(Graphics g) {
    
    
    direction = direction2;
    
    
    g.setColor(Color.WHITE);
    
    g.fillRect(0, 0, 900, 700);
    
    
    //绘制游戏框
    
    //标题框
    
    // g.drawRect(25, 30, 800, 75);
    
    title.paintIcon(this, g, 25, 10);
    
    
    //内容框
    
    g.setColor(Color.black);
    
    g.fillRect(25, 75, 850, 600);
    
    
    //绘制食物的坐标位置
    
    if(!exist) {//如果当前不存在豆子,随机绘制一个豆子
    
    if(num % 5 == 0) {
    
    foodType = 1;
    
    }else {
    
    foodType = 0;
    
    }
    
    boolean isProduce = true;
    
    while(isProduce) {
    
    isProduce = false;
    
    x = rand.nextInt(33) * 25 + 25;
    
    y = rand.nextInt(23) * 25 + 75;
    
    for (int[] arr:localList) {
    
    if(x == arr[0] && y == arr[1]) {
    
    isProduce = true;
    
    break;
    
    }
    
    }
    
    
    }
    
    System.out.println(x + "---" + y);
    
    }
    
    
    if(eat()) {
    
    exist = false;
    
    }else {
    
    exist = true;
    
    }
    
    
    
    if(foodType == 0) {
    
    //绘制食物
    
    g.setColor(Color.blue);
    
    // g.fillRect(x, y, 25, 25);
    
    g.drawImage(food.getImage(),x, y, 25, 25,null);
    
    }else {
    
    //绘制食物
    
    g.setColor(Color.WHITE);
    
    g.fillRect(x, y, 25, 25);
    
    // g.drawImage(food.getImage(),x, y, 25, 25,null);
    
    }
    
    
    
    //绘制头
    
    g.setColor(Color.red);
    
    // g.fillRect(localList.get(0)[0], localList.get(0)[1], 25, 25);
    
    ImageIcon head = null;
    
    //判断当前方向
    
    if(direction.equals("R")) {
    
    head = right;
    
    }else if(direction.equals("L")) {
    
    head = left;
    
    }else if(direction.equals("U")) {
    
    head = up;
    
    }else if(direction.equals("D")) {
    
    head = down;
    
    }
    
    // g.drawImage(head.getImage(), localList.get(0)[0], localList.get(0)[1], 25, 25,null);
    
    head.paintIcon(this, g,localList.get(0)[0], localList.get(0)[1]);
    
    
    //绘制身体
    
    g.setColor(Color.white);
    
    for (int i = 1; i < localList.size(); i++) {
    
    // g.fillRect(localList.get(i)[0], localList.get(i)[1], 25, 25);
    
    // g.drawImage(body.getImage(), localList.get(i)[0], localList.get(i)[1], 25, 25,null);
    
    body.paintIcon(this, g, localList.get(i)[0], localList.get(i)[1]);
    
    }
    
    // g.fillRect(localList.get(1)[0], localList.get(1)[1], 25, 25);
    
    // g.fillRect(localList.get(2)[0], localList.get(2)[1], 25, 25);
    
    
    
    //绘制分数和长度
    
    //长度
    
    g.setColor(Color.GREEN);
    
    g.setFont(new Font("宋体", Font.BOLD, 18));
    
    g.drawString("长度:" + (localList.size() - 1), 25, 30);
    
    
    //分数
    
    g.drawString("分数:" + score, 25, 48);
    
    
    if(!start) {//如果游戏未启动,结束移动和重绘
    
    g.setColor(Color.white);
    
    g.setFont(new Font("宋体", Font.BOLD, 30));
    
    g.drawString("暂停/开始(请按任意键开始,空格键暂停)", 150, 300);
    
    time.stop();
    
    
    }else {
    
    time.start();
    
    }
    
    
    // speed();
    
    //移动后进行下一次绘制
    
    // move();//移动
    
    // repaint();//重新绘制
    
    }
    
    
    // //解决闪烁问题
    
    // //如果为JFrame 为重量级 程序不会调用update()方法
    
    // //如果为Frame 为轻量级 重写update()方法 做双缓冲
    
    // //如果为JPanel 不会闪烁
    
    // @Override
    
    // public void update(Graphics g)
    
    // {
    
    // System.out.println("update");
    
    // if(offScreenImage == null)
    
    // offScreenImage = this.createImage(900, 700); //新建一个图像缓存空间,这里图像大小为800*600
    
    // Graphics gImage = offScreenImage.getGraphics(); //把它的画笔拿过来,给gImage保存着
    
    // paint(gImage); //将要画的东西画到图像缓存空间去
    
    // g.drawImage(offScreenImage, 0, 0, null); //然后一次性显示出来
    
    // }
    
    
    
    @Override
    
    public void actionPerformed(ActionEvent e) {
    
    //移动后进行下一次绘制
    
    move();//移动
    
    repaint();//重新绘制
    
    
    }
    
    
    /**
    
    * 绘制速度
    
    */
    
    // private void speed() {
    
    // try {//按一定速度进行移动
    
    // Thread.sleep(speed);//控制移动速度
    
    // } catch (InterruptedException e) {
    
    // // TODO 自动生成的 catch 块
    
    // e.printStackTrace();
    
    // }
    
    // }
    
    
    /**
    
    * 初始化图片
    
    */
    
    private void drawImage() {
    
    up = new ImageIcon("images/up.png");
    
    down = new ImageIcon("images/down.png");
    
    right = new ImageIcon("images/right.png");
    
    left = new ImageIcon("images/left.png");
    
    body = new ImageIcon("images/body.png");
    
    food = new ImageIcon("images/food.png");
    
    title = new ImageIcon("images/title.jpg");
    
    }
    
    
    private boolean eat() {
    
    if(localList.get(0)[0] == x && localList.get(0)[1] == y) {//如果当前蛇头吃到了豆子
    
    System.out.println("eat");
    
    num++;
    
    if(foodType == 0) {
    
    score += 10;
    
    }else {
    
    score += (rand.nextInt(5) * 10 + 10);
    
    }
    
    int last = localList.size() - 1;//蛇尾
    
    //在蛇尾后面添加一节身体
    
    localList.add(new int[] {localList.get(last)[0],localList.get(last)[1]});
    
    return true;
    
    }
    
    return false;
    
    }
    
    
    //移动方法
    
    public void move() {
    
    //判断是否游戏结束
    
    if(isbody()) {
    
    System.out.println("game over");
    
    start = false;//结束游戏移动
    
    JOptionPane.showMessageDialog(null,"游戏已结束!");
    
    time.stop();
    
    init();
    
    }
    
    
    if(flag && localList != null) {//如果长度不为空且游戏未结束
    
    int last = localList.size() - 1;//记录蛇尾
    
    
    for (int i = last; i > 0; i--) {//从蛇尾开始,每节身体移动到前一节身体的位置上
    
    localList.set(i,new int[] {localList.get(i - 1)[0],localList.get(i - 1)[1]});
    
    }
    
    
    //记录头位置
    
    int[] local = localList.get(0);
    
    //判断当前方向,并进行模拟移动,判断是否与边界重合
    
    if(direction.equals("R")) {
    
    if(local[0] >= 850) {
    
    local[0] = 25;
    
    }else {
    
    local[0] += 25;
    
    }
    
    
    }else if(direction.equals("L")) {
    
    if(local[0] <= 25) {
    
    local[0] = 850;
    
    }else {
    
    local[0] -= 25;
    
    }
    
    
    }else if(direction.equals("U")) {
    
    
    if(local[1] <= 75) {
    
    local[1] = 650;
    
    }else {
    
    local[1] -= 25;
    
    }
    
    
    }else if(direction.equals("D")) {
    
    if(local[1] >= 650) {
    
    local[1] = 75;
    
    }else {
    
    local[1] += 25;
    
    }
    
    
    }
    
    
    //更改头的位置
    
    localList.set(0, local);
    
    }
    
    }
    
    
    //判断下一步是否为蛇身
    
    private boolean isbody() {
    
    // TODO 自动生成的方法存根
    
    //记录头位置
    
    int x = localList.get(0)[0];
    
    int y = localList.get(0)[1];
    
    
    //判断当前方向,并进行模拟移动,判断是否与边界重合
    
    if(direction.equals("R")) {
    
    x += 25;
    
    }else if(direction.equals("L")) {
    
    x -= 25;
    
    }else if(direction.equals("U")) {
    
    y -= 25;
    
    }else if(direction.equals("D")) {
    
    y += 25;
    
    }
    
    
    for (int i = 1; i < localList.size(); i++) {
    
    if(localList.get(i)[0] == x && localList.get(i)[1] == y) {
    
    return true;
    
    }
    
    }
    
    return false;
    
    
    }
    
    
    // //判断下一步是否为边界
    
    // private boolean isborder() {
    
    // // TODO 自动生成的方法存根
    
    // //记录头位置
    
    // // TODO 自动生成的方法存根
    
    // //记录头位置
    
    // int x = localList.get(0)[0];
    
    // int y = localList.get(0)[1];
    
    //
    
    // //判断当前方向,并进行模拟移动,判断是否与边界重合
    
    // if(direction.equals("R")) {
    
    // x += 25;
    
    // }else if(direction.equals("L")) {
    
    // x -= 25;
    
    // }else if(direction.equals("U")) {
    
    // y -= 25;
    
    // }else if(direction.equals("D")) {
    
    // y += 25;
    
    // }
    
    //
    
    // if(x < 25 || x > (33 * 25 + 25)) {
    
    // return true;//当x坐标超出边界,则返回true
    
    // }
    
    // if(y < 105 || y > (23 * 25 + 105)) {
    
    // return true;//当y坐标超出边界,则返回true
    
    // }
    
    // return false;//蛇头移动后未超出边界,返回false
    
    //
    
    // }
    
    
    /**
    
    * Create the frame.
    
    */
    
    public SnakeJPanel(int speed) {
    
    
    this.speed = speed; //初始化速度
    
    
    //初始化游戏面板的基本信息
    
    this.setSize(900, 700);
    
    this.setLocation(0, 30);
    
    this.setFocusable(true);
    
    
    init();//初始化界面
    
    drawImage();//绘制图片
    
    moveByKey();//给界面添加一个键盘监听
    
    
    }
    
    
    /*
    
    * 键盘监听
    
    * 通过键盘输入上下左右来控制当前蛇头移动的方向
    
    * 先判断当前蛇头方向,再来改变引导方向
    
    * 当进行绘制时再修改蛇的方向
    
    * 保证不会因为在短时间内快速变换方向导致蛇头逆向转向
    
    */
    
    private void moveByKey() {
    
    addKeyListener(new KeyAdapter() {
    
    @Override
    
    public void keyPressed(KeyEvent e) {
    
    int key = e.getKeyCode();
    
    //边界值判断
    
    switch(key) {
    
    case 65:
    
    case 37:{//向左走
    
    if(!direction.equals("R")) {
    
    direction2 = "L";
    
    
    }
    
    break;
    
    }
    
    case 87:
    
    case 38:{//向上走
    
    if(!direction.equals("D")) {
    
    direction2 = "U";
    
    }
    
    break;
    
    }
    
    case 68:
    
    case 39:{//向右走
    
    if(!direction.equals("L")) {
    
    direction2 = "R";
    
    }
    
    break;
    
    }
    
    case 83:
    
    case 40:{//向下走
    
    if(!direction.equals("U")) {
    
    direction2 = "D";
    
    }
    
    break;
    
    }
    
    case KeyEvent.VK_SPACE:{//如果当前键盘输入为空格
    
    start = !start;//调整游戏状态
    
    System.out.println("暂停/开始");
    
    repaint();//重绘
    
    }
    
    }
    
    
    //任意键开始
    
    if(!start && key != KeyEvent.VK_SPACE) {//如果当前状态为暂停状态,且键盘输入不是空格
    
    start = true;
    
    repaint();//重绘
    
    
    }
    
    }
    
    });
    
    }
    
    
    /**
    
    * 初始化游戏基本信息
    
    */
    
    private void init() {
    
    start = false;
    
    
    exist = true;
    
    
    direction2 = "U";
    
    
    flag = true;
    
    
    localList = new ArrayList<int[]>();
    
    
    localList.add(0,new int[] {75,125});//蛇头
    
    localList.add(1,new int[] {75,150});//蛇身1
    
    localList.add(2,new int[] {75,175});//蛇身2
    
    
    //创建第一个食物的位置
    
    //通过循环保证当前生成的食物不在身体所在的坐标上
    
    boolean isProduce = true;
    
    while(isProduce) {//循环生成食物坐标
    
    isProduce = false;//结束本次循环
    
    x = rand.nextInt(33) * 25 + 25;
    
    y = rand.nextInt(23) * 25 + 75;
    
    for (int[] arr:localList) {//循环遍历蛇头及蛇身的坐标
    
    if(x == arr[0] && y == arr[1]) {//如果食物坐标和蛇的某一节坐标重合
    
    isProduce = true;//跳转循环状态,继续下一次食物生成
    
    break;
    
    }
    
    }
    
    //蛇身遍历完成,没有重合坐标,结束食物坐标生成
    
    
    }
    
    
    time = new Timer(speed, this);
    
    setLayout(null);
    
    
    score = 0;
    
    
    num = 0;
    
    
    foodType = 0;
    
    
    // repaint();
    
    
    }
    
    
    
    }

三、构造启动类

 
  1. p

    ackage com.snake.controller;
    
    
    import javax.swing.JFrame;
    
    import javax.swing.JOptionPane;
    
    
    import com.snake.view.SnakeJPanel;
    
    
    public class SnakeStart {
    
    public static void main(String[] args) {
    
    
    int speed = 0;
    
    String showInputDialog = null;//初始化时间
    
    //得到速度
    
    while(true) {
    
    showInputDialog = JOptionPane.showInputDialog("蛇移动速度(1 - 5)","3");
    
    
    if(showInputDialog == null) {
    
    showInputDialog = "3";//默认速度
    
    break;
    
    }
    
    if(showInputDialog.length() > 1) {
    
    continue;
    
    }
    
    char[] a = showInputDialog.toCharArray();
    
    if(a[0] >= '1' && a[0] <= '5') {
    
    break;
    
    }
    
    }
    
    
    speed = Integer.parseInt(showInputDialog) * 50;
    
    
    
    SnakeJPanel snakeJPanel = new SnakeJPanel(speed);
    
    
    //创建一个JFrame窗口,将游戏面板添加进行窗口中
    
    JFrame jFrame = new JFrame();
    
    //设置窗口的某些属性
    
    jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
    jFrame.setSize(920, 750);
    
    jFrame.add(snakeJPanel);
    
    jFrame.setLocationRelativeTo(null);
    
    jFrame.setVisible(true);
    
    }
    
    
    }

四、游戏启动

设置游戏速度

游戏界面

 俄罗斯方块

游戏规则:

由小方块组成的不同形状的板块陆续从屏幕上方落下来,玩家通过调整板块的位置和方向,使它们在屏幕底部拼出完整的一条或几条。这些完整的横条会随即消失,给新落下来的板块腾出空间,与此同时,玩家得到分数奖励。没有被消除掉的方块不断堆积起来,一旦堆到屏幕顶端,玩家便告输,游戏结束。

整体代码分为三个模块:方格模块,七种图形模块,俄罗斯方块主模块。

小方块类:Cell

 
  1. package com.zhao.demo.block;
    
    
    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++;
    
    }
    
    }

 四方格图形的父类:Tetromino

 
  1. package com.zhao.demo.block;
    
    
    import com.zhao.demo.shape.*;
    
    
    /**
    
    * @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 +
    
    '}';
    
    }
    
    }
    
    }

七种图形类:I、J、L、O、S、T、Z

 I

 
  1. package com.zhao.demo.shape;
    
    
    import com.zhao.demo.App.Tetris;
    
    import com.zhao.demo.block.Cell;
    
    import com.zhao.demo.block.Tetromino;
    
    
    /**
    
    * @author xiaoZhao
    
    * @date 2022/5/11
    
    * @describe
    
    */
    
    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);
    
    }
    
    
    }

J

 
  1. package com.zhao.demo.shape;
    
    
    import com.zhao.demo.App.Tetris;
    
    import com.zhao.demo.block.Cell;
    
    import com.zhao.demo.block.Tetromino;
    
    
    /**
    
    * @author xiaoZhao
    
    * @date 2022/5/11
    
    * @describe
    
    */
    
    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);
    
    }
    
    }

 L

 
  1. package com.zhao.demo.shape;
    
    
    import com.zhao.demo.App.Tetris;
    
    import com.zhao.demo.block.Cell;
    
    import com.zhao.demo.block.Tetromino;
    
    
    /**
    
    * @author xiaoZhao
    
    * @date 2022/5/11
    
    * @describe
    
    */
    
    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);
    
    }
    
    }

O

 
  1. package com.zhao.demo.shape;
    
    
    import com.zhao.demo.App.Tetris;
    
    import com.zhao.demo.block.Cell;
    
    import com.zhao.demo.block.Tetromino;
    
    
    /**
    
    * @author xiaoZhao
    
    * @date 2022/5/11
    
    * @describe
    
    */
    
    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];
    
    }
    
    }

 
  1. package com.zhao.demo.shape;
    
    
    import com.zhao.demo.App.Tetris;
    
    import com.zhao.demo.block.Cell;
    
    import com.zhao.demo.block.Tetromino;
    
    
    /**
    
    * @author xiaoZhao
    
    * @date 2022/5/11
    
    * @describe
    
    */
    
    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);
    
    }
    
    }

 
  1. package com.zhao.demo.shape;
    
    
    import com.zhao.demo.App.Tetris;
    
    import com.zhao.demo.block.Cell;
    
    import com.zhao.demo.block.Tetromino;
    
    
    /**
    
    * @author xiaoZhao
    
    * @date 2022/5/11
    
    * @describe
    
    */
    
    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);
    
    }
    
    }

 
  1. package com.zhao.demo.shape;
    
    
    import com.zhao.demo.App.Tetris;
    
    import com.zhao.demo.block.Cell;
    
    import com.zhao.demo.block.Tetromino;
    
    
    /**
    
    * @author xiaoZhao
    
    * @date 2022/5/11
    
    * @describe
    
    */
    
    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);
    
    }
    
    }

俄罗斯方块游戏主类:Tetris

 
  1. package com.zhao.demo.App;
    
    
    import com.zhao.demo.block.Cell;
    
    import com.zhao.demo.block.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;
    
    
    /**
    
    * @author xiaoZhao
    
    * @date 2022/5/11
    
    * @describe 俄罗斯方块游戏主类
    
    */
    
    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();
    
    }
    
    }

三、效果展示

游戏开始,方快下落,右边区域展示即将下落的方块图、分数、消除的行数以及游戏切换的状态。

按下空格键,方块瞬间下落, 按下P键游戏暂停,消除一行分数为1(此处由分数池进行控制)

  按下C键游戏继续。

方块占满,游戏结束,此时可以按下S键重新开始游戏。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值