Java小白实现数字华容道

本人是一名Java小白(有其他语言的基础),最近在跟着网上的资源学习,今天做了一个初步的数字华容道游戏,觉得很有意思,做完也很有成就感,记录一下开发过程啦 哈哈哈

一:用到的技术和知识

面向对象思想、JavaGUI编程、枚举数据类型、项目思维

二、具体过程

准备过程

创建一个DigtalStone_Game的工程、以及两个一模一样的(4*4)二维数组(其中一个要设置成final修饰的默认类型)

一、初始化一个界面

首先要搞出一个一个页面,设置Title、Size、关闭窗口时自动结束程序等初始化参数

大家记得要设置一下绝对布局哈:可以用于设置组件的布局管理器为null,表示取消使用默认的布局管理器,允许手动定位和大小调整组件。这样可以更自由地控制组件的位置和大小,但需手动管理

    private void initFrame() {
        this.setTitle("石头迷阵");
        this.setSize(470,560);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);// 打开时页面处于中心位置


        // 设置绝对布局
        this.setLayout(null); 
    }

二、将二维数组和小方块图片进行绑定并嵌入窗口中

注意:initImgFrame()方法里,在后期开发到移动物块这里要想到,在每次移动完物块要重新加载页面前要移除窗口上原本的panel(可以通过这条代码:this.getContentPane().removeAll(); ),不然后添加的会被原来添加的panel覆盖。

private void initImgFrame() {
        //由于操作后相当于铺上了一层新的panel布,所以要进行时时刷新桌布
        this.getContentPane().removeAll();

        JLabel COUNT_TEXT=new JLabel("当前移动"+count_+"步");
        COUNT_TEXT.setBounds(350,0,100,20);
        this.add(COUNT_TEXT);

        // 每次移动完成后都判断是否已经成功还原
        if(ISRIGHT()){
//            JOptionPane.showMessageDialog(this,"恭喜你,游戏胜利!");
//            this.initMIXLayout();
            JLabel jLabel = new JLabel(new ImageIcon(IMG_PATH+"win.png"));
            jLabel.setBounds(120,260,450,500);
            this.add(jLabel);
        }

        for(int i=0;i<img_numpy.length;i++)
            for(int j=0;j<img_numpy[i].length;j++)
            {
                JLabel jlabel=new JLabel(new ImageIcon(IMG_PATH+img_numpy[i][j]+".png"));
                jlabel.setBounds(j*100+20,i*100+60,100,100);
                this.add(jlabel);
            }
        // 添加背景图片
        JLabel backgrounD =new JLabel(new ImageIcon(IMG_PATH+"background.png"));
        backgrounD.setBounds(3,-3,450,500);
        this.add(backgrounD);

        // 时时刷新图层,重新绘制
        this.repaint();
    }
        JLabel COUNT_TEXT=new JLabel("当前移动"+count_+"步");
        COUNT_TEXT.setBounds(350,0,100,20);
        this.add(COUNT_TEXT);

        在窗口右上角增添记录操作步数的弹窗

三、打乱数组

我们需要将原始的二维数组打乱,注意之打乱那个没有被final修饰的数组,打乱后再调用第二步的方法,也可以在构造器中将第三步的方法写在第二步的方法之前,我们开发中按照正常思路是应该:先将图片和数组一一对应,然后再打乱数组,然后再将打乱后的数组找到其对应的图片并填充到窗口的panel上

    private void initMIXLayout() {
        // 设计一个合理的打乱算法
        for(int i=0;i<img_numpy.length;i++)
            for(int j=0;j<img_numpy[i].length;j++){
                int Temp_Row1=(int) (Math.random()*4);
                int Temp_Col1=(int) (Math.random()*4);

                int Temp_Row2=(int) (Math.random()*4);
                int Temp_Col2=(int) (Math.random()*4);

                int temp=img_numpy[Temp_Row1][Temp_Col1];
                img_numpy[Temp_Row1][Temp_Col1]=img_numpy[Temp_Row2][Temp_Col2];
                img_numpy[Temp_Row2][Temp_Col2]=temp;
            }
//        for(int k=0;k<img_numpy.length;k++)
//            for(int l=0;l<img_numpy[k].length;l++)
//            {System.out.print(img_numpy[k][l]);
//                System.out.print(" ");}
        initImgFrame();
    }

注意:本人目前算法较弱,其实这个算法是有问题的,因为如果完全随机打乱,可能会导致打乱后的数组无法被还原,大家如果有兴趣可以去研究一下数字华容道的算法实现

四、设置基本菜单栏

我设置了一个基本菜单栏,添加了“重新开始”和“退出游戏”两个选项,大家自己开发的时候也可以添加音乐、难易程度等其他选项

    // 增加菜单栏,包含重新开始和退出游戏两个选项
    private void initMenubutton() {
        JMenuBar jMenuBar = new JMenuBar();// 创建一个菜单栏
        JMenu jMenu = new JMenu("系统菜单");
        JMenuItem jMenuItem1 = new JMenuItem("重新开始");// 创建一个菜单项
        // 为菜单项添加监听器
        jMenuItem1.addActionListener(e -> {
            count_=0;
            initMIXLayout(); // 重启之————把数组顺序打乱
            initImgFrame(); //重组之————重新布局图片并刷新
        });

        JMenuItem jMenuItem2 = new JMenuItem("退出游戏");
        // 为菜单项添加监听器
        jMenuItem2.addActionListener(e -> {this.dispose();});
        jMenu.add(jMenuItem1);
        jMenu.add(jMenuItem2);
        jMenuBar.add(jMenu);
        this.setJMenuBar(jMenuBar);
    }

五、设置上下左右的事件监听器

这里我们可以通过lambda语法,int KeyCode=e.getKeyCode();来读入键盘输入的“上”“下”“左”“右”,并根据读入的操作数据调用方法传入不同的参数来对原数组进行交换,然后再调用

initImgFrame();方法
    private void initKeyPress() {
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int keyCode = e.getKeyCode(); // 程序自动记录用户通过键盘输入的键
                switch(keyCode){
                    case KeyEvent.VK_UP:
                        System.out.println("向上");
                        swithc_move(KeyPressd.UP);
                        break;
                    case KeyEvent.VK_DOWN:
                        System.out.println("向下");
                        swithc_move(KeyPressd.DOWN);
                        break;
                    case KeyEvent.VK_LEFT:
                        System.out.println("向左");
                        swithc_move(KeyPressd.LEFT);
                        break;
                    case KeyEvent.VK_RIGHT:
                        System.out.println("向右");
                        swithc_move(KeyPressd.RIGHT);
                        break;
                }
            }
        });
    }

六、数组(方块)交换的具体实现

我们要先找到空白色块的位置,以空白色块作为中心,与其上下左右方块进行交换,实现移动

设计一个方法,根据上一步传入的参数进行数组交换,注意:要考虑最后呈现的效果,如:如果空白快已经在第一行,那么就无法与其上一行进行交换,可以添加 if(null_row>1) 语句等

    private void swithc_move(KeyPressd direction){
        //首先拿到当前空白色块的位置
        OUT:
        for(int i=0;i<img_numpy.length;i++)
            for (int j=0;j<img_numpy[i].length;j++)
                if(img_numpy[i][j]==0)
                {  null_row= i;
                    null_col=j;
                    break OUT;}
        switch (direction){
            case KeyPressd.UP :
                if(null_row>0){
                    int temp =img_numpy[null_row][null_col];
                    img_numpy[null_row][null_col]=img_numpy[null_row-1][null_col];
                    img_numpy[null_row-1][null_col]=temp;
                    null_row--; //更新移动后空白色块的位置
                    count_++;
                }
                break;
            case KeyPressd.DOWN :
                if(null_row<3){
                    int temp =img_numpy[null_row][null_col];
                    img_numpy[null_row][null_col]=img_numpy[null_row+1][null_col];
                    img_numpy[null_row+1][null_col]=temp;
                    null_row++;
                    count_++;
                }
                break;
            case KeyPressd.LEFT :
                if(null_col>0)
                    {
                        int temp =img_numpy[null_row][null_col];
                        img_numpy[null_row][null_col]=img_numpy[null_row][null_col-1];
                        img_numpy[null_row][null_col-1]=temp;
                        null_col--;
                        count_++;
                    }
                break;
            case KeyPressd.RIGHT :
                if(null_col<3)
                {
                    int temp =img_numpy[null_row][null_col];
                    img_numpy[null_row][null_col]=img_numpy[null_row][null_col+1];
                    img_numpy[null_row][null_col+1]=temp;
                    null_col++;
                    count_++;
                }
                break;
        }
        initImgFrame();//重新布局

    }

七、其余代码(非核心)

就是一些创建对象,枚举类之类的方法,话不多说,直接贴代码

package com.xiaoxiao.www;

public enum KeyPressd {
    UP,DOWN,LEFT,RIGHT;
}
import com.xiaoxiao.www.MainFrame;
import com.xiaoxiao.www.MainFrame;

public class APP {
    public static void main(String[] args) {
        MainFrame app = new MainFrame();
        app.setVisible(true);
    }
}

八、实现效果

个人感觉这个小游戏的开发对于一个Java小白来说还是很有挑战性的,所以写了这篇文章,总结的同时也顺便锻炼一下自己的编程思维。最后,感谢网课资源老师~(黑马程序员磊哥)!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值