Java-Swing俄罗斯方块

1.效果图

2. 实现的过程

Step1:先画面板

主要是三个方法:initWindow()初始化窗口,initGameInit()初始化面板;initExplainPanel()初始化解释面板,init()初始化参数

public void initWindow(){
        this.setSize(600, 850);
        this.setLocationRelativeTo(null);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setTitle("俄罗斯方块");
    }

    public void initGameInit(){
        JPanel game_main=new JPanel();
        game_main.setLayout(new GridLayout(game_x,game_y,1,1));
        for(int i=0;i<text.length;i++){
            for(int j=0;j<text[i].length;j++){
                text[i][j]=new JTextArea(game_x,game_y);
                text[i][j].setBackground(Color.WHITE);
                text[i][j].addKeyListener(this);
                if((j==0) || (j==text[i].length-1) || (i==text.length-1)){
                    text[i][j].setBackground(Color.MAGENTA);
                    data[i][j]=1;
                }
                text[i][j].setEditable(false);
                game_main.add(text[i][j]);
            }
        }
        this.setLayout(new BorderLayout());
        this.add(game_main,BorderLayout.CENTER);
    }

    public void initExplainPanel(){
        JPanel explain_left=new JPanel();
        JPanel explain_right=new JPanel();
        explain_left.setLayout(new GridLayout(4,1));
        explain_right.setLayout(new GridLayout(2,1));
        explain_left.add(new JLabel("按空格键,方块变形"));
        explain_left.add(new JLabel("按左箭头,方块左移"));
        explain_left.add(new JLabel("按右箭头,方块右移"));
        explain_left.add(new JLabel("按下箭头,方块下落"));
      //  explain_left.add(new JLabel("按'P',游戏暂停"));
        label1.setForeground(Color.red);
        explain_right.add(label);
        explain_right.add(label1);
        this.add(explain_left,BorderLayout.WEST);
        this.add(explain_right,BorderLayout.EAST);

    }
    /***
     * 初始化
     */
    private void init() {
        text=new JTextArea[game_x][game_y];
        data=new int[game_x][game_y];
        label1=new JLabel("游戏状态:正在游戏中");
        label=new JLabel("游戏分数为:0");
        isRunning=true;
        allRect=new int[]{0x00cc,0x8888,0x000f,0x888f,0xf8888,0xf111,0x111f,0x0eee,0xffff,0x0008,0x0888,0x000e,0x0088,0x000c
        ,0x08c8,0x00e4,0x04c4,0x004e,0x08c4,0x006c,0x04c8,0x00c6};
    }

Step2:参数设定以及生成方块

参数:

 private static final int game_x=26;
    private static final int game_y=12;
    JTextArea[][] text;
    int[][] data;
    JLabel label1;
    JLabel label;
    boolean isRunning;
    int[] allRect;//存放所有方块
    int rect;//存储当前方块的变量
    //当前方块的坐标
    int x,y;
    //线程休眠时间
    int time=1000;
    int score=0;
    boolean game_pause=false;
    int pause_time=0;

 方块:

方块的表示方法我是用十六进制数进行表示

首先看一下一个方块:

 其他的方块都可以这样表示:

 

 

 /**8
     * 生成一个随机的方块
     */
    public void ranRect(){
        Random random=new Random();
        rect=allRect[random.nextInt(22)];
    }

 Step3:设置游戏开始: 

其中包括的方法主要是:game_run(),先随机生成方块,再判断方块是否可以下落,如果可以下落,先改变data的值表示这里有方块,再判断移除的条件,最后判断游戏失败的条件

 public void game_begin(){
        while(true){
            if(!isRunning){
                break;
            }
            game_run();
        }
        label1.setText("游戏状态:游戏结束!");
    }

    /***
     * 游戏run
     */
    private void game_run()  {
        ranRect();
        x=0;
        y=5;
        for(int i=0;i<game_x;i++){
            try {
                Thread.sleep(time);
                if(game_pause){
                    i--;
                }else{
                    //判断方块是否可以下落
                    if(!canFall(x,y)){
                        //将data置为1,表示有方块占用
                        changData(x,y);
                        //4是表示方块是4*4的方块
                        for(int j=x;j<x+4;j++){
                            int sum=0;
                            for(int k=1;k<=(game_y-2);k++){
                                /***
                                 * 表示这里有方块
                                 * sum+1
                                 */
                                if(data[j][k]==1){
                                    sum++;
                                }
                            }
                            /***
                             * 如果sum为game_y-2
                             * 说明这行可以消除
                             */
                            if(sum==(game_y-2)){
                                removeRow(j);
                            }
                        }
                        /**8
                         * 游戏失败的条件是:
                         * 前四行有方块
                         * 只需要第四行有方块就游戏结束
                         */
                        for(int j=1;j<=(game_y-2);j++){
                            if(data[3][j]==1){
                                isRunning=false;
                                break;
                            }
                        }
                        break;
                    }else{
                        x++;
                        //方块下落一格
                        fall(x,y);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

 方块是否可以下落:直接通过data数组进行判断,之间在下落的时间会将data数组的i,j位置置于1,如果此时该位置的data数组不为1就可以下落

private boolean canFall(int x, int y) {
        int temp=0x8000;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if((temp& rect) !=0){
                    //判断该位置的下一行是否有方块
                    if(data[x+1][y]==1){
                        return false;
                    }
                }
                y++;
                temp = temp >> 1;
            }
            x++;
            y=y-4;
        }
        return true;
    }

下落的方法:直接清除掉上一层的方块,再重新绘制下一层的方块

 /**
     * 方块下落
     * @param m
     * @param n
     */
    private void fall(int m,int n) {
        if(m>0){
            //清除上一层的方块
            clear(m-1,n);
        }
        //重新绘制
        draw(m,n);
    }

    /***
     * 绘制方块
     * @param m
     * @param n
     */
    private void draw(int m, int n) {
        int temp=0x8000;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if((temp& rect) !=0){
                    text[m][n].setBackground(Color.BLUE);
                }
                n++;
                temp = temp >> 1;
            }
            m++;
            n=n-4;
        }
    }

    /**
     * 清除这行
     * 就是将文本域的颜色设为白色就可
     * @param m
     * @param n
     */
    private void clear(int m, int n) {
        int temp=0x8000;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if((temp& rect) !=0){
                    text[m][n].setBackground(Color.WHITE);
                }
                n++;
                temp = temp >> 1;
            }
            m++;
            n=n-4;
        }
    }

当有一行可以消除时,移除某一行方法:主要是通过改变文本块颜色进行移除

  /***
     * 移除某一行
     * @param row
     */
    private void removeRow(int row) {
        int temp=100;
        for(int i=row;i>=1;i--){
           for(int j=1;j<(game_y-2);j++){
               data[i][j]=data[i-1][j];
           }
        }
       //刷新游戏区域
        reflesh(row);
       //游戏加速
        if(time>temp){
            time-=temp;
        }
        score+=temp;
        label.setText("游戏得分: "+score);
    }

    private void reflesh(int row) {
        for(int i=row;i>=1;i--){
            for(int j=1;j<(game_y-2);j++){
                if(data[i][j]>=1){
                    text[i][j].setBackground(Color.BLUE);
                }else{
                    text[i][j].setBackground(Color.WHITE);
                }
            }
        }
    }

改变data值:

private void changData(int x, int y) {
        int temp=0x8000;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if((temp& rect) !=0){
                   data[x][y]=1;
                }
                y++;
                temp = temp >> 1;
            }
            x++;
            y=y-4;
        }
    }

Step4:鼠标监听事件:

通过进行鼠标的左移、右移、下移、变形进行操作,主要是继承KeyListener重写三个方法

这里主要是进行变形的时候需要注意

 @Override
    public void keyTyped(KeyEvent e) {
        if(e.getKeyChar()=='p'){
            if(! isRunning){
                return;
            }
            pause_time++;
            if(pause_time==1){
                game_pause=true;
                label1.setText("游戏暂停");
            }
            if(pause_time==2){
                game_pause=false;
                pause_time=0;
                label1.setText("游戏继续");
            }
        }
        if(e.getKeyChar()==KeyEvent.VK_SPACE){
            if(! isRunning){
                return;
            }
            if(game_pause){
                return;
            }
            int old;
            for(old=0;old<allRect.length;old++){
                if(rect==allRect[old]){
                    break;
                }
            }
            int next;
            if(old==0||old==7||old==8||old==9){
                return;
            }
            clear(x,y);
            if(old==1 || old==2){
                next=allRect[old==1 ?2:1];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old>=3 && old<=6){
                next=allRect[old+1>6 ? 3:old+1];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old==10 || old==11){
                next=allRect[old==10 ?11:10];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old==12 || old==13){
                next=allRect[old==12 ?13:12];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old>=14 && old<=17){
                next=allRect[old+1>17 ? 14:old+1];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old==18 || old==19){
                next=allRect[old==18 ?19:18];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old==20 || old==21){
                next=allRect[old==20 ?21:20];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            draw(x,y);
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if(keyCode==KeyEvent.VK_LEFT){
            if(!isRunning){
                return;
            }
            if(y<=1){
                return;
            }
            if(game_pause){
                return;
            }
            int temp=0x8000;
            for(int i=x;i<x+4;i++){
                for(int j=y;j<y+4;j++){
                    if((temp&rect)!=0){
                        if(data[i][j-1]!=0){
                            return;
                        }
                    }
                    temp>>=1;
                }
            }
            clear(x,y);
            y--;
            draw(x,y);
        }
        if(keyCode==KeyEvent.VK_RIGHT){
            if(!isRunning){
                return;
            }
            if(game_pause){
                return;
            }
            int temp=0x8000;
            int m=x;
            int n=y;
            int num=1;
            for(int i=0;i<4;i++){
                for(int j=0;j<4;j++){
                    if((temp&rect)!=0){
                        if(n>num){
                            num=n;
                        }
                    }
                    n++;
                    temp>>=1;
                }
                m++;
                n=n-4;
            }
            if(num>=(game_y-2)){
                return;
            }
            temp=0x8000;
            for(int i=x;i<x+4;i++){
                for(int j=y;j<y+4;j++){
                    //temp&rect为1表示这里有方块
                    if((temp&rect)!=0){
                        if(data[i][j+1]!=0){
                            return;
                        }
                    }
                    temp>>=1;
                }
            }
            clear(x,y);
            y++;
            draw(x,y);
        }

        if(keyCode==KeyEvent.VK_DOWN){
            System.out.println("down");
            if(!isRunning){
                return;
            }
            if(!canFall(x,y)){
                return;
            }
            if(game_pause){
                return;
            }
            clear(x,y);
            x++;
            draw(x,y);
        }


    }

    private boolean canTurn(int next, int x, int y) {
        int temp=0x8000;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if((temp&next)!=0){
                    if(data[x][y]==1){
                        return false;
                    }
                }
                y++;
                temp>>=1;
            }
            x++;
            y=y-4;
        }
        System.out.println("ttur");
        return true;
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

 

Step5:主函数调用

 public static void main(String[] args) {
        MyTertris myTertris=new MyTertris();
        myTertris.game_begin();
    }

3.完整代码

package com.tetris.study;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;


public class MyTertris extends JFrame  implements KeyListener{
    private static final int game_x=26;
    private static final int game_y=12;
    JTextArea[][] text;
    int[][] data;
    JLabel label1;
    JLabel label;
    boolean isRunning;
    int[] allRect;//存放所有方块
    int rect;//存储当前方块的变量
    //当前方块的坐标
    int x,y;
    //线程休眠时间
    int time=1000;
    int score=0;
    boolean game_pause=false;
    int pause_time=0;


    public MyTertris() {

        init();
        initGameInit();
        initExplainPanel();
        initWindow();
    }

    public void initWindow(){
        this.setSize(600, 850);
        this.setLocationRelativeTo(null);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setTitle("俄罗斯方块");
    }

    public void initGameInit(){
        JPanel game_main=new JPanel();
        game_main.setLayout(new GridLayout(game_x,game_y,1,1));
        for(int i=0;i<text.length;i++){
            for(int j=0;j<text[i].length;j++){
                text[i][j]=new JTextArea(game_x,game_y);
                text[i][j].setBackground(Color.WHITE);
                text[i][j].addKeyListener(this);
                if((j==0) || (j==text[i].length-1) || (i==text.length-1)){
                    text[i][j].setBackground(Color.MAGENTA);
                    data[i][j]=1;
                }
                text[i][j].setEditable(false);
                game_main.add(text[i][j]);
            }
        }
        this.setLayout(new BorderLayout());
        this.add(game_main,BorderLayout.CENTER);
    }

    public void initExplainPanel(){
        JPanel explain_left=new JPanel();
        JPanel explain_right=new JPanel();
        explain_left.setLayout(new GridLayout(4,1));
        explain_right.setLayout(new GridLayout(2,1));
        explain_left.add(new JLabel("按空格键,方块变形"));
        explain_left.add(new JLabel("按左箭头,方块左移"));
        explain_left.add(new JLabel("按右箭头,方块右移"));
        explain_left.add(new JLabel("按下箭头,方块下落"));
      //  explain_left.add(new JLabel("按'P',游戏暂停"));
        label1.setForeground(Color.red);
        explain_right.add(label);
        explain_right.add(label1);
        this.add(explain_left,BorderLayout.WEST);
        this.add(explain_right,BorderLayout.EAST);

    }
    /***
     * 初始化
     */
    private void init() {
        text=new JTextArea[game_x][game_y];
        data=new int[game_x][game_y];
        label1=new JLabel("游戏状态:正在游戏中");
        label=new JLabel("游戏分数为:0");
        isRunning=true;
        allRect=new int[]{0x00cc,0x8888,0x000f,0x888f,0xf8888,0xf111,0x111f,0x0eee,0xffff,0x0008,0x0888,0x000e,0x0088,0x000c
        ,0x08c8,0x00e4,0x04c4,0x004e,0x08c4,0x006c,0x04c8,0x00c6};
    }

    public void game_begin(){
        while(true){
            if(!isRunning){
                break;
            }
            game_run();
        }
        label1.setText("游戏状态:游戏结束!");
    }

    /***
     * 游戏run
     */
    private void game_run()  {
        ranRect();
        x=0;
        y=5;
        for(int i=0;i<game_x;i++){
            try {
                Thread.sleep(time);
                if(game_pause){
                    i--;
                }else{
                    //判断方块是否可以下落
                    if(!canFall(x,y)){
                        //将data置为1,表示有方块占用
                        changData(x,y);
                        //4是表示方块是4*4的方块
                        for(int j=x;j<x+4;j++){
                            int sum=0;
                            for(int k=1;k<=(game_y-2);k++){
                                /***
                                 * 表示这里有方块
                                 * sum+1
                                 */
                                if(data[j][k]==1){
                                    sum++;
                                }
                            }
                            /***
                             * 如果sum为game_y-2
                             * 说明这行可以消除
                             */
                            if(sum==(game_y-2)){
                                removeRow(j);
                            }
                        }
                        /**8
                         * 游戏失败的条件是:
                         * 前四行有方块
                         * 只需要第四行有方块就游戏结束
                         */
                        for(int j=1;j<=(game_y-2);j++){
                            if(data[3][j]==1){
                                isRunning=false;
                                break;
                            }
                        }
                        break;
                    }else{
                        x++;
                        //方块下落一格
                        fall(x,y);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * 方块下落
     * @param m
     * @param n
     */
    private void fall(int m,int n) {
        if(m>0){
            //清除上一层的方块
            clear(m-1,n);
        }
        //重新绘制
        draw(m,n);
    }

    /***
     * 绘制方块
     * @param m
     * @param n
     */
    private void draw(int m, int n) {
        int temp=0x8000;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if((temp& rect) !=0){
                    text[m][n].setBackground(Color.BLUE);
                }
                n++;
                temp = temp >> 1;
            }
            m++;
            n=n-4;
        }
    }

    /**
     * 清除这行
     * 就是将文本域的颜色设为白色就可
     * @param m
     * @param n
     */
    private void clear(int m, int n) {
        int temp=0x8000;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if((temp& rect) !=0){
                    text[m][n].setBackground(Color.WHITE);
                }
                n++;
                temp = temp >> 1;
            }
            m++;
            n=n-4;
        }
    }

    /***
     * 移除某一行
     * @param row
     */
    private void removeRow(int row) {
        int temp=100;
        for(int i=row;i>=1;i--){
           for(int j=1;j<(game_y-2);j++){
               data[i][j]=data[i-1][j];
           }
        }
       //刷新游戏区域
        reflesh(row);
       //游戏加速
        if(time>temp){
            time-=temp;
        }
        score+=temp;
        label.setText("游戏得分: "+score);
    }

    private void reflesh(int row) {
        for(int i=row;i>=1;i--){
            for(int j=1;j<(game_y-2);j++){
                if(data[i][j]>=1){
                    text[i][j].setBackground(Color.BLUE);
                }else{
                    text[i][j].setBackground(Color.WHITE);
                }
            }
        }
    }

    private void changData(int x, int y) {
        int temp=0x8000;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if((temp& rect) !=0){
                   data[x][y]=1;
                }
                y++;
                temp = temp >> 1;
            }
            x++;
            y=y-4;
        }
    }

    private boolean canFall(int x, int y) {
        int temp=0x8000;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if((temp& rect) !=0){
                    //判断该位置的下一行是否有方块
                    if(data[x+1][y]==1){
                        return false;
                    }
                }
                y++;
                temp = temp >> 1;
            }
            x++;
            y=y-4;
        }
        return true;
    }

    /**8
     * 生成一个随机的方块
     */
    public void ranRect(){
        Random random=new Random();
        rect=allRect[random.nextInt(22)];
    }


    public static void main(String[] args) {
        MyTertris myTertris=new MyTertris();
        myTertris.game_begin();
    }

    @Override
    public void keyTyped(KeyEvent e) {
        if(e.getKeyChar()=='p'){
            if(! isRunning){
                return;
            }
            pause_time++;
            if(pause_time==1){
                game_pause=true;
                label1.setText("游戏暂停");
            }
            if(pause_time==2){
                game_pause=false;
                pause_time=0;
                label1.setText("游戏继续");
            }
        }
        if(e.getKeyChar()==KeyEvent.VK_SPACE){
            if(! isRunning){
                return;
            }
            if(game_pause){
                return;
            }
            int old;
            for(old=0;old<allRect.length;old++){
                if(rect==allRect[old]){
                    break;
                }
            }
            int next;
            if(old==0||old==7||old==8||old==9){
                return;
            }
            clear(x,y);
            if(old==1 || old==2){
                next=allRect[old==1 ?2:1];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old>=3 && old<=6){
                next=allRect[old+1>6 ? 3:old+1];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old==10 || old==11){
                next=allRect[old==10 ?11:10];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old==12 || old==13){
                next=allRect[old==12 ?13:12];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old>=14 && old<=17){
                next=allRect[old+1>17 ? 14:old+1];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old==18 || old==19){
                next=allRect[old==18 ?19:18];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            if(old==20 || old==21){
                next=allRect[old==20 ?21:20];
                if(canTurn(next,x,y)){
                    rect =next;
                }
            }
            draw(x,y);
        }
    }

    @Override
    public void keyPressed(KeyEvent e) {
        int keyCode = e.getKeyCode();
        if(keyCode==KeyEvent.VK_LEFT){
            if(!isRunning){
                return;
            }
            if(y<=1){
                return;
            }
            if(game_pause){
                return;
            }
            int temp=0x8000;
            for(int i=x;i<x+4;i++){
                for(int j=y;j<y+4;j++){
                    if((temp&rect)!=0){
                        if(data[i][j-1]!=0){
                            return;
                        }
                    }
                    temp>>=1;
                }
            }
            clear(x,y);
            y--;
            draw(x,y);
        }
        if(keyCode==KeyEvent.VK_RIGHT){
            if(!isRunning){
                return;
            }
            if(game_pause){
                return;
            }
            int temp=0x8000;
            int m=x;
            int n=y;
            int num=1;
            for(int i=0;i<4;i++){
                for(int j=0;j<4;j++){
                    if((temp&rect)!=0){
                        if(n>num){
                            num=n;
                        }
                    }
                    n++;
                    temp>>=1;
                }
                m++;
                n=n-4;
            }
            if(num>=(game_y-2)){
                return;
            }
            temp=0x8000;
            for(int i=x;i<x+4;i++){
                for(int j=y;j<y+4;j++){
                    //temp&rect为1表示这里有方块
                    if((temp&rect)!=0){
                        if(data[i][j+1]!=0){
                            return;
                        }
                    }
                    temp>>=1;
                }
            }
            clear(x,y);
            y++;
            draw(x,y);
        }

        if(keyCode==KeyEvent.VK_DOWN){
            System.out.println("down");
            if(!isRunning){
                return;
            }
            if(!canFall(x,y)){
                return;
            }
            if(game_pause){
                return;
            }
            clear(x,y);
            x++;
            draw(x,y);
        }


    }

    private boolean canTurn(int next, int x, int y) {
        int temp=0x8000;
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if((temp&next)!=0){
                    if(data[x][y]==1){
                        return false;
                    }
                }
                y++;
                temp>>=1;
            }
            x++;
            y=y-4;
        }
        System.out.println("ttur");
        return true;
    }

    @Override
    public void keyReleased(KeyEvent e) {

    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值