【Java进阶学习 第八篇】石头迷阵游戏

发布于:2025-03-16 ⋅ 阅读:(20) ⋅ 点赞:(0)

绘制页面

首先绘制指定宽和高的窗体

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(514,595);
        frame.setTitle("石头迷阵单机版v1.0");
        //想让游戏一直在屏幕的最上层
        frame.setAlwaysOnTop(true);
        //想让窗体开始时在屏幕的居中位置
        frame.setLocationRelativeTo(null);

        frame.setVisible(true);

这里的窗体就是上一章的代码,其中为了让游戏一直在我们屏幕的最上层,使用了setAlwaysOnTop方法;并且想让游戏开始时就在屏幕的居中位置,使用了setLocationRelativeTo方法。

效果:

绘制背景

图像用JLabel里的ImageIcon添加就可以,那么是先添加石头方块还是先添加背景图呢

应该是先添加石头方块,因为在同一重叠区域内,后添加的JLabel会放在图层最底下

确定第一块石头的坐标(46,50)和大小(100,100);我们就可以添加所有的石头方块了,先手动添加

public class GameWidget {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(514,595);
        frame.setTitle("石头迷阵单机版v1.0");
        //想让游戏一直在屏幕的最上层
        frame.setAlwaysOnTop(true);
        //想让窗体开始时在屏幕的居中位置
        frame.setLocationRelativeTo(null);
        //取消默认布局
        frame.setLayout(null);
        //第一个方块左边是(50,90)
        JLabel label0 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\0.png"));
        label0.setBounds(50,90,100,100);
        frame.getContentPane().add(label0);

        JLabel label1 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\1.png"));
        label1.setBounds(150,90,100,100);
        frame.getContentPane().add(label1);

        JLabel label2 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\2.png"));
        label2.setBounds(250,90,100,100);
        frame.getContentPane().add(label2);

        JLabel label3 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\3.png"));
        label3.setBounds(350,90,100,100);
        frame.getContentPane().add(label3);

        JLabel label4 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\4.png"));
        label4.setBounds(50,190,100,100);
        frame.getContentPane().add(label4);

        JLabel label5 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\5.png"));
        label5.setBounds(150,190,100,100);
        frame.getContentPane().add(label5);

        JLabel label6 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\6.png"));
        label6.setBounds(250,190,100,100);
        frame.getContentPane().add(label6);

        JLabel label7 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\7.png"));
        label7.setBounds(350,190,100,100);
        frame.getContentPane().add(label7);

        JLabel label8 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\8.png"));
        label8.setBounds(50,290,100,100);
        frame.getContentPane().add(label8);

        JLabel label9 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\9.png"));
        label9.setBounds(150,290,100,100);
        frame.getContentPane().add(label9);

        JLabel label10 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\10.png"));
        label10.setBounds(250,290,100,100);
        frame.getContentPane().add(label10);

        JLabel label11 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\11.png"));
        label11.setBounds(350,290,100,100);
        frame.getContentPane().add(label11);

        JLabel label12 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\12.png"));
        label12.setBounds(50,390,100,100);
        frame.getContentPane().add(label12);

        JLabel label13= new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\13.png"));
        label13.setBounds(150,390,100,100);
        frame.getContentPane().add(label13);

        JLabel label14 = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\14.png"));
        label14.setBounds(250,390,100,100);
        frame.getContentPane().add(label14);

        JLabel label15= new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\15.png"));
        label15.setBounds(350,390,100,100);
        frame.getContentPane().add(label15);

        JLabel label = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\background.png"));
        label.setBounds(26,30,450,484);
        frame.getContentPane().add(label);
        //设置窗口可见
        frame.setVisible(true);

 效果为

 


代码优化

二维数组加循环嵌套

我们可以将图像从0到15共16个数字作为二维数组的索引,0,1,2,3为第一行;这样我们在后续调用图像的时候,图像路径直接调用data[i][j]就可以了。

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(514,595);
        frame.setTitle("石头迷阵单机版v1.0");
        //想让游戏一直在屏幕的最上层
        frame.setAlwaysOnTop(true);
        //想让窗体开始时在屏幕的居中位置
        frame.setLocationRelativeTo(null);
        //取消默认布局
        frame.setLayout(null);

        //用二维数组记录图像的id
        int[][] data= {
                {0,1,2,3},
                {4,5,6,7},
                {8,9,10,11},
                {12,13,14,15}
        };
        for(int i=0;i<4;i++)
        {
            for(int j=0;j<4;j++)
            {
                //第一个方块左边是(50,90)
                JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\"+data[i][j]+".png"));
                imagelabel.setBounds(100*j+50,100*i+90,100,100);
                frame.getContentPane().add(imagelabel);
            }
        }
        //加背景图像
        JLabel bglabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\background.png"));
        bglabel.setBounds(26,30,450,484);
        frame.getContentPane().add(bglabel);

        //设置窗口可见
        frame.setVisible(true);

我们把行数看做i,列数看做j;可以看见我们每个方块的坐标其实可以用j*100+50和i*100+50表示。


继承优化

为了方便我们自己添加后续的功能,我们可以自己创建一个窗口类去继承JFrame

public class MainFrame extends JFrame {
    
}

 继承好JFrame后,我们可以把之前的代码粘贴过来,并且把所有关于窗体的代码放在一个方法里面,所有绘制石头的代码放在一个方法里面

    public void paintStone(){
        for(int i=0;i<4;i++)
        {
            for(int j=0;j<4;j++)
            {
                //第一个方块左边是(50,90)
                JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\"+data[i][j]+".png"));
                imagelabel.setBounds(100*j+50,100*i+90,100,100);
                frame.getContentPane().add(imagelabel);
            }
        }
        //加背景图像
        JLabel bglabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\background.png"));
        bglabel.setBounds(26,30,450,484);
        frame.getContentPane().add(bglabel);
    }

这里我们会发现frame会报错,但是不需要将其添加为成员变量;因为我们继承了JFrame,JFrame类中的方法我们都有,所以我们可以将frame变成super,而且我们并没有对父类JFrame中的方法进行重写,所以super可以省略,最终两个方法代码为:

public class MainFrame extends JFrame {
    //用二维数组记录图像的id
    int[][] data= {
            {0,1,2,3},
            {4,5,6,7},
            {8,9,10,11},
            {12,13,14,15}
    };
    public void widgetInit(){
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(514,595);
        setTitle("石头迷阵单机版v1.0");
        //想让游戏一直在屏幕的最上层
        setAlwaysOnTop(true);
        //想让窗体开始时在屏幕的居中位置
        setLocationRelativeTo(null);
        //取消默认布局
        setLayout(null);
        //设置窗口可见
        setVisible(true);
    }

    public void paintStone(){
        for(int i=0;i<4;i++)
        {
            for(int j=0;j<4;j++)
            {
                //第一个方块左边是(50,90)
                JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\"+data[i][j]+".png"));
                imagelabel.setBounds(100*j+50,100*i+90,100,100);
                getContentPane().add(imagelabel);
            }
        }
        //加背景图像
        JLabel bglabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\background.png"));
        bglabel.setBounds(26,30,450,484);
        getContentPane().add(bglabel);
    }

 我们希望两个方法+窗口visible显示在这个Mainframe创建对象的时候就显示,那么我们可以写入构造函数中

    public MainFrame() {
        widgetInit();
        paintStone();
        //设置窗口可见
        setVisible(true);
    }

我们在test文件中创建Mainframe的对象,进行测试,效果正常。


打乱石头方块

我们只需要对二维数组中的索引进行打乱就可以

使用random.nextInt(4)分别作为当前二维数组元素要交换的索引下标的行数和列数,遍历一遍二维数组,进行交换就可以

    public void dataInit(){
        Random rand = new Random();

        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                int x=rand.nextInt(4);
                int y=rand.nextInt(4);
                int temp=data[x][y];
                data[x][y]=data[i][j];
                data[i][j]=temp;
            }
        }
    }

效果为


移动业务

首先要给我们的窗体增加键盘输入上下左右的监听

        //之前的键盘监听格式是窗口对象frame.addKeyListener(KeyListener的实现类)
        //第一个this是代表本类MainFrame的对象
        //第二个this代表实现类KeyListener的对象
        this.addKeyListener(this);

像这段代码中注释所示,为了不让我们的代码更加繁琐,我们可以用this(代表本类的对象)去分别代表窗体Mainframe类的对象以及实现类KeyListener的对象去加入键盘的监听事件。

接下来系统会提示我们对实现类中的方法进行重写,我们挑选KeyPressed方法进行重写,并利用getKeyCode去调用我们要实现的移动业务方法move

    public void move(int keyCode){
        if (keyCode == 37) {
            System.out.println("左移动业务代码执行");
        } else if (keyCode == 38) {
            System.out.println("上移动业务代码执行");
        } else if (keyCode == 39) {
            System.out.println("右移动业务代码执行");
        } else if (keyCode == 40) {
            System.out.println("下移动业务代码执行");
        }
    }


    @Override
    public void keyPressed(KeyEvent e) {
        //判断键盘输入是否为上下左右,对应移动业务
        int keyCode = e.getKeyCode();
        move(keyCode);
    }

 寻找零号元素

    public void dataInit(){
        Random rand = new Random();

        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                int x=rand.nextInt(4);
                int y=rand.nextInt(4);
                int temp=data[x][y];
                data[x][y]=data[i][j];
                data[i][j]=temp;
            }
        }

        //找到0号元素
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if(data[i][j]==0){
                    xindex=i;
                    yindex=j;
                    break;
                }
            }
        }
    }

这里的两个零号元素需要作为成员变量,因为还有move方法要调用


进行判断并移动位置

public class MainFrame extends JFrame implements KeyListener {
    public MainFrame() {
        //之前的键盘监听格式是窗口对象frame.addKeyListener(KeyListener的实现类)
        //第一个this是代表本类MainFrame的对象
        //第二个this代表实现类KeyListener的对象
        this.addKeyListener(this);
        //初始化窗口
        widgetInit();
        //打乱石头顺序
        dataInit();
        //绘制石头方块
        paintStone();
        //设置窗口可见
        setVisible(true);
    }
    //记录零号元素
    int xindex;
    int yindex;
    //用二维数组记录图像的id
    int[][] data= {
            {0,1,2,3},
            {4,5,6,7},
            {8,9,10,11},
            {12,13,14,15}
    };
    public void dataInit(){
        Random rand = new Random();

        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                int x=rand.nextInt(4);
                int y=rand.nextInt(4);
                int temp=data[x][y];
                data[x][y]=data[i][j];
                data[i][j]=temp;
            }
        }

        //找到0号元素
        for(int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if(data[i][j]==0){
                    xindex=i;
                    yindex=j;
                    break;
                }
            }
        }
    }
    public void widgetInit(){
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(514,595);
        setTitle("石头迷阵单机版v1.0");
        //想让游戏一直在屏幕的最上层
        setAlwaysOnTop(true);
        //想让窗体开始时在屏幕的居中位置
        setLocationRelativeTo(null);
        //取消默认布局
        setLayout(null);
    }

    public void paintStone(){
        //为了刷新,我们要先清空之前的Label,要不然直接调用这个方法会放在图层的最底下,不能显示
        getContentPane().removeAll();
        for(int i=0;i<4;i++)
        {
            for(int j=0;j<4;j++)
            {
                //第一个方块左边是(50,90)
                JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\"+data[i][j]+".png"));
                imagelabel.setBounds(100*j+50,100*i+90,100,100);
                getContentPane().add(imagelabel);
            }
        }
        //加背景图像
        JLabel bglabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\background.png"));
        bglabel.setBounds(26,30,450,484);
        getContentPane().add(bglabel);
        //remove后需要repaint进行label的刷新
        getContentPane().repaint();
    }

    public void move(int keyCode){
        if (keyCode == 37) {
            //判断是不是在最右边,不是的话,右边的石头方块就会向左移动
            if(yindex!=3)
            {
                int temp=data[xindex][yindex];
                data[xindex][yindex]=data[xindex][yindex+1];
                data[xindex][yindex+1]=temp;
                yindex++;
            }
            System.out.println("左移动业务代码执行");
        } else if (keyCode == 38) {
            if(xindex!=3)
            {
                int temp=data[xindex][yindex];
                data[xindex][yindex]=data[xindex+1][yindex];
                data[xindex+1][yindex]=temp;
                xindex++;
            }
            System.out.println("上移动业务代码执行");
        } else if (keyCode == 39) {
            if(yindex!=0)
            {
                int temp=data[xindex][yindex];
                data[xindex][yindex]=data[xindex][yindex-1];
                data[xindex][yindex-1]=temp;
                yindex--;
            }
            System.out.println("右移动业务代码执行");
        } else if (keyCode == 40) {
            if(xindex!=0)
            {
                int temp=data[xindex][yindex];
                data[xindex][yindex]=data[xindex-1][yindex];
                data[xindex-1][yindex]=temp;
                xindex--;
            }
            System.out.println("下移动业务代码执行");
        }
    }


    @Override
    public void keyPressed(KeyEvent e) {
        //判断键盘输入是否为上下左右,对应移动业务
        int keyCode = e.getKeyCode();
        move(keyCode);
        //移动后需要刷新
        paintStone();
    }
    //--------------------------------------------------

假如说我们进行上移动操作,那么我们的空白格需要和下面的石头格子进行交换位置,那就要判断xindex是不是已经是3了,如果是3,那么就撞墙了,不能再进行交换了。

除此之外,我们每进行一次move操作,就需要刷新一下页面。

绘制页面方法需要先对之前的label进行removeall操作,再进行白板添加,再进行repaint进行刷新。 


游戏判定胜利

添加作弊器

当我的getKeyCode为90也就是键入z的时候,我希望能够直接让所有的石头块为正常状态

        }else if (keyCode == 90) {
            data=new int[][]{
                    {1,2,3,4},
                    {5,6,7,8},
                    {9,10,11,12},
                    {13,14,15,0}
            };
        }

判断胜利winJudge方法 

    private boolean winJudge() {
        //将目前的data和windata进行对比
        for (int i=0;i<4;i++){
            for(int j=0;j<4;j++){
                if(data[i][j]!=windata[i][j]){
                    return false;
                }
            }
        }
        //赢了就绘制胜利图像,且应该结束游戏
        return true;
    }

我们先创建胜利状态下的数组windata

    int[][] windata={
            {1,2,3,4},
            {5,6,7,8},
            {9,10,11,12},
            {13,14,15,0}
    };

胜利状态

我们现在需要在绘制页面进行判断,如果已经胜利了,加入胜利标志,而且不能再进行移动了

        //如果胜利,我们需要先加入胜利的Label
        if(winJudge()){
            //第一个方块左边是(50,90)
            JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\win.png"));
            imagelabel.setBounds(124,230,266,88);
            getContentPane().add(imagelabel);
            //此时游戏已经胜利,不应该再移动了
        }
    public void move(int keyCode){
        //游戏胜利不能再移动了
        if(winJudge())
        {
            return;
        }

现在我们用作弊器测试一下效果

老铁没毛病 


统计步数

记录一下我们用了多少步数,增加成员变量count。上下左右移动的时候都count++,最后在paint方法中加入我们的步数label

        //左上角加入步数
        JLabel footcount =new JLabel("目前已用步数:"+count);
        footcount.setBounds(50,20,100,20);
        getContentPane().add(footcount);

重新游戏

在paint方法中加入JButton,需要取消默认布局,取消焦点

点击之后,我们需要重置步数,重置数据,重新绘制

        //添加按钮
        JButton regamebtn =new JButton("重新开始");
        regamebtn.setBounds(350,20,100,20);
        getContentPane().add(regamebtn);
        regamebtn.setFocusable(false);
        //添加按钮的点击监听
        regamebtn.addActionListener(this);

这里我们可以用内部匿名类,也可以再implements接口ActionListener去用this作为ActionListener的实现类对象,然后需要我们重写方法,在重写方法里面进行重置步数等命令

    @Override
    public void actionPerformed(ActionEvent e) {
        //重置步数
        count=0;
        //重置data数据
        dataInit();
        //重新绘制
        paintStone();
    }

运行效果

全体代码

package yuhan;

import javax.swing.*;
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 MainFrame extends JFrame implements KeyListener, ActionListener {
    public MainFrame() {
        //之前的键盘监听格式是窗口对象frame.addKeyListener(KeyListener的实现类)
        //第一个this是代表本类MainFrame的对象
        //第二个this代表实现类KeyListener的对象
        this.addKeyListener(this);
        //初始化窗口
        widgetInit();
        //打乱石头顺序
        dataInit();
        //绘制石头方块
        paintStone();
        //设置窗口可见
        setVisible(true);
    }

    //记录零号元素
    int xindex;
    int yindex;
    //统计步数
    int count;
    //用二维数组记录图像的id
    int[][] data = {
            {0, 1, 2, 3},
            {4, 5, 6, 7},
            {8, 9, 10, 11},
            {12, 13, 14, 15}
    };
    int[][] windata = {
            {1, 2, 3, 4},
            {5, 6, 7, 8},
            {9, 10, 11, 12},
            {13, 14, 15, 0}
    };

    public void dataInit() {
        Random rand = new Random();
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                int x = rand.nextInt(4);
                int y = rand.nextInt(4);
                int temp = data[x][y];
                data[x][y] = data[i][j];
                data[i][j] = temp;
            }
        }
        //找到0号元素
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (data[i][j] == 0) {
                    xindex = i;
                    yindex = j;
                    return;
                }
            }
        }
    }

    public void widgetInit() {
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(514, 595);
        setTitle("石头迷阵单机版v1.0");
        //想让游戏一直在屏幕的最上层
        setAlwaysOnTop(true);
        //想让窗体开始时在屏幕的居中位置
        setLocationRelativeTo(null);
        //取消默认布局
        setLayout(null);
    }

    public void paintStone() {
        //为了刷新,我们要先清空之前的Label,要不然直接调用这个方法会放在图层的最底下,不能显示
        getContentPane().removeAll();
        //左上角加入步数
        JLabel footcount = new JLabel("目前已用步数:" + count);
        footcount.setBounds(50, 20, 100, 20);
        getContentPane().add(footcount);
        //添加按钮
        JButton regamebtn = new JButton("重新开始");
        regamebtn.setBounds(350, 20, 100, 20);
        getContentPane().add(regamebtn);
        regamebtn.setFocusable(false);
        //添加按钮的点击监听
        regamebtn.addActionListener(this);

        //如果胜利,我们需要先加入胜利的Label
        if (winJudge()) {
            //第一个方块左边是(50,90)
            JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\win.png"));
            imagelabel.setBounds(124, 230, 266, 88);
            getContentPane().add(imagelabel);
            //此时游戏已经胜利,不应该再移动了
        }
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                //第一个方块左边是(50,90)
                JLabel imagelabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\" + data[i][j] + ".png"));
                imagelabel.setBounds(100 * j + 50, 100 * i + 90, 100, 100);
                getContentPane().add(imagelabel);
            }
        }
        //加背景图像
        JLabel bglabel = new JLabel(new ImageIcon("D:\\Java资料\\资料\\进阶篇\\day04\\资料\\image\\background.png"));
        bglabel.setBounds(26, 30, 450, 484);
        getContentPane().add(bglabel);
        //remove后需要repaint进行label的刷新
        getContentPane().repaint();
    }

    public void move(int keyCode) {
        //游戏胜利不能再移动了
        if (winJudge()) {
            return;
        }
        if (keyCode == 37) {
            //判断是不是在最右边,不是的话,右边的石头方块就会向左移动
            if (yindex != 3) {
                int temp = data[xindex][yindex];
                data[xindex][yindex] = data[xindex][yindex + 1];
                data[xindex][yindex + 1] = temp;
                yindex++;
                count++;
            }
            System.out.println("左移动业务代码执行");
        } else if (keyCode == 38) {
            if (xindex != 3) {
                int temp = data[xindex][yindex];
                data[xindex][yindex] = data[xindex + 1][yindex];
                data[xindex + 1][yindex] = temp;
                xindex++;
                count++;
            }
            System.out.println("上移动业务代码执行");
        } else if (keyCode == 39) {
            if (yindex != 0) {
                int temp = data[xindex][yindex];
                data[xindex][yindex] = data[xindex][yindex - 1];
                data[xindex][yindex - 1] = temp;
                yindex--;
                count++;
            }
            System.out.println("右移动业务代码执行");
        } else if (keyCode == 40) {
            if (xindex != 0) {
                int temp = data[xindex][yindex];
                data[xindex][yindex] = data[xindex - 1][yindex];
                data[xindex - 1][yindex] = temp;
                xindex--;
                count++;
            }
            System.out.println("下移动业务代码执行");
        } else if (keyCode == 90) {
            data = new int[][]{
                    {1, 2, 3, 4},
                    {5, 6, 7, 8},
                    {9, 10, 11, 12},
                    {13, 14, 15, 0}
            };
        }
    }


    @Override
    public void keyPressed(KeyEvent e) {
        //判断键盘输入是否为上下左右,对应移动业务
        int keyCode = e.getKeyCode();
        move(keyCode);
        //移动后需要刷新
        paintStone();
    }

    private boolean winJudge() {
        //将目前的data和windata进行对比
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (data[i][j] != windata[i][j]) {
                    return false;
                }
            }
        }
        //赢了就绘制胜利图像,且应该结束游戏
        return true;
    }

    //--------------------------------------------------
    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        //重置步数
        count = 0;
        //重置data数据
        dataInit();
        //重新绘制
        paintStone();
    }
}
package yuhan;

public class test {
    public static void main(String[] args) {
        new MainFrame();
    }
}

 效果

至此,石头迷阵游戏代码编写完毕,用了很多之前的类、接口、重写方法、构造方法这些面向对象思想。