[Java学习日记]拼图小游戏

实现具体步骤:

1.创建窗口类继承于JFrame,并在构造方法里面初始化窗口(设置大小,设置标题,设置居中,设置关闭方式,设置游戏界面总在上方,设置为可见,设置layout为空,使得组件不会默认居中),提取成初始化方法

2.创建JMBJMJMI,再把JMIJM,把JMJMB,把JBJF

3.初始化图片initImage方法,把图片放到JLJL相当于是图片的容器!)里面,再把JL放到窗口的隐藏容器里面,在方法中给图片添边框,移动图片到窗口正中间:(在初始化图片的时候添加坐标即可)

4.打乱图片initDate顺序

5.添加背景图片(在初始化拼图图片后)

6.给游戏添加键盘监听(不是点击图片):增加上下左右四种情况:并且在InitImage里面去删除原来的图片,并刷新一下界面

7.添加查看完整图片功能,按住A显示完整图片,松开A显示随机打乱的图片

8.作弊功能:按下按钮W,游戏方块全部回到原位

9.显示胜利:在加载图片前判断就行(为了让胜利显示在最上层):之前的想法是在键盘监听中判断:但是那样无效的键盘监听也会有代码运行。游戏胜利之后无法再次按按键

10.添加计步功能:不会添加文字,在按下上下左右键之后count++即可定义全局变量,也需要在initImage里面初始化

11.添加重新游戏功能:设置重新点击动作,再把数据重新init就可以咯

12.添加新的菜单栏:更换图片:更换图片里面有三个小选项

13.把图片存储位置先提取出来。添加转换图片功能额:增加三个小监听即可,随机图片就是改个路径即可:由于是全局变量,按A也能够显示对应的图片

public class App {
    public static void main(String[] args) {
        new GameFrame();
    }
}
public class GameFrame extends JFrame implements KeyListener {
    //data代表装图片Label的坐标:定义final表示地址不变,值可以变
    private static int x,y;
    private static int count = 0;
    private final static int[][] data = new int[4][4];
    private static final int[][] win = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};
    private static String path = "JAVA基础\\src\\Day16\\image\\animal\\animal3\\";

    //构造方法,可以初始化数据:创建最外面的窗体,
    public GameFrame(){
        initJFrame();
        initJMenuBar();
        initData();
        initImage();
        //并且让界面可视: 建议写在最后
        this.setVisible(true);
    }

    //初始化窗口
    private void initJFrame(){
        //设置标题
        this.setTitle("拼图单机版");
        //设置窗口大小
        this.setSize(603,680);
        //设置关闭模式:关掉这个界面——程序停止,3:每个数字代表一种关闭模式,这个是关掉虚拟机
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置JFrame界面居中
        this.setLocationRelativeTo(null);
        //取消默认的居中模式,不然添加组件会默认居中
        this.setLayout(null);
        //添加键盘监听事件,在这里相当于这个对象实现了接口,也就是说,这个类既是JF的子类,也是AL的实现类,所以能传这个类的对象(好抽象的写法)
        //第一个this:给本界面添加键盘监听。第二个this:事件被触发,会执行本类中的重写实现KeyListener中的方法
        this.addKeyListener(this);
    }

    //初始化菜单
    private void initJMenuBar(){
        //创建整个菜单对象
        JMenuBar jMenuBar = new JMenuBar();

        //菜单上面的两个对象
        JMenu functionMenu = new JMenu("功能");
        JMenu aboutMenu = new JMenu("关于我们");
        JMenu changePicturesMenu = new JMenu("更换图片");

        //创建选项下面的条目对象
        JMenuItem replayItem = new JMenuItem("重新游戏");
        JMenuItem reLoginItem = new JMenuItem("重新登录");
        JMenuItem closeItem = new JMenuItem("关闭游戏");
        JMenuItem accountItem = new JMenuItem("公众号");

        JMenuItem animalItem = new JMenuItem("动物");
        JMenuItem girlItem = new JMenuItem("美女");
        JMenuItem sportItem = new JMenuItem("运动");

        //在选项中加入条目对象
        functionMenu.add(changePicturesMenu);
        functionMenu.add(replayItem);
        functionMenu.add(reLoginItem);
        functionMenu.add(closeItem);
        aboutMenu.add(accountItem);
        changePicturesMenu.add(animalItem);
        changePicturesMenu.add(girlItem);
        changePicturesMenu.add(sportItem);

        //在菜单中加入两个选项
        jMenuBar.add(functionMenu);
        jMenuBar.add(aboutMenu);

        //在窗体中加入菜单
        this.setJMenuBar(jMenuBar);

        //绑定点击事件
        //重新开始
        replayItem.addActionListener(e -> {
            System.out.println("重新游戏");
            initData();
            initImage();
        });
        //重新登录
        reLoginItem.addActionListener(e -> {
            //关闭当前界面,打开登陆界面,登录界面先不做了。。。
            this.setVisible(false);
        });
        //关闭游戏
        closeItem.addActionListener(e -> System.exit(0));
        //公众号
        accountItem.addActionListener(e -> {
            System.out.println("弹出公众号");
            //创建弹框
            JDialog dialog = new JDialog();
            JLabel label = new JLabel(new ImageIcon("JAVA基础\\src\\Day16\\image\\about.png"));
            label.setBounds(0,0,258,258);
            dialog.getContentPane().add(label);
            dialog.setSize(344,344);
            dialog.setAlwaysOnTop(true);
            dialog.setLocationRelativeTo(null);
            //弹框不关闭无法设置下面的界面
            dialog.setModal(true);
            dialog.setVisible(true);
        });

        Random random = new Random();
        //动物更换
        animalItem.addActionListener(e -> {
            path = "JAVA基础\\src\\Day16\\image\\animal\\animal"+(random.nextInt(8)+1)+"\\";
            initData();
            initImage();
        });
        //美女更换
        girlItem.addActionListener(e -> {
            path = "JAVA基础\\src\\Day16\\image\\girl\\girl"+(random.nextInt(11)+1)+"\\";
            initData();
            initImage();
        });
        //运动更换
        sportItem.addActionListener(e -> {
            path = "JAVA基础\\src\\Day16\\image\\sport\\sport"+(random.nextInt(10)+1)+"\\";
            initData();
            initImage();
        });
    }

    //初始化二维数组数据:先打乱一维数组再放到二维数组里面。当然如果可以的话也能直接打乱二维,这里就不尝试了
    private void initData() {
        //计步器清零
        count = 0;
        int[] arr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        Random random = new Random();
        for (int i = 0; i < arr.length; i++) {
            int index = random.nextInt(arr.length);
            int temp = arr[i];
            arr[i] =  arr[index];
            arr[index] = temp;
        }
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == 0){
                x=i/4;
                y=i%4;
            }
            data[i/4][i%4] = arr[i];
        }
    }

    //初始化图片
    //看完老师的写法之后再简化代码:原本的做法是用了JLabel数组和String数组,还需要记数组下标,不太方便。
    //这里就是直接再循环里面使用data数组创建新的对象就可以了。
    private void initImage(){
        //删除已经出现的所有图片
        this.getContentPane().removeAll();
        if(winOrNot()){
            showWin();
        }
        showStepCount();
        //添加拼图
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                int num = data[i][j];
                //关于坐标0:找不到图片不会显示:但是本身这里传进去的是一个错误的地址,还是能够new一个JLabel。
                String str = path+num+".jpg";
                JLabel jLabel = new JLabel(new ImageIcon(str));
                jLabel.setBounds(j*105+83,i*105+134,105,105);
                //这里传进去的是接口,可以传Java中已经实现的类:传递的值代表不同样式:因为是变量静态的所以可以直接使用类名调用
                jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED));
                this.getContentPane().add(jLabel);
            }
        }
        showImageBackground();
        //刷新界面
        this.getContentPane().repaint();
    }

    //加载背景图片,添加图片,先写的图片在上层,后写的图片在下层
    private void showImageBackground(){
        //绝对路径:从盘符开始的路径。相对路径基于当前项目
        String backgroundPath = "JAVA基础\\src\\Day16\\image\\background.png";
        JLabel backgroundLabel = new JLabel(new ImageIcon(backgroundPath));
        backgroundLabel.setBounds(40,40,508,560);
        this.getContentPane().add(backgroundLabel);
    }

    //展示步数
    private void showStepCount(){
        JLabel stepCount = new JLabel("步数:"+count);
        stepCount.setBounds(50,30,100,20);
        this.getContentPane().add(stepCount);
    }

    //展示完整图片
    private void showImageAll(){
        this.getContentPane().removeAll();
        JLabel jLabel = new JLabel(new ImageIcon(path+"all.jpg"));
        jLabel.setBounds(83,134,420,420);
        this.getContentPane().add(jLabel);
        showImageBackground();
        this.getContentPane().repaint();
    }

    //作弊胜利
    private void cheat(){
        //这里之前的做法是复制的initImage方法:但是不需要这么做:可以直接改数组!!!!!!
        for (int i = 0; i < 16; i++) {
            data[i/4][i%4]=win[i/4][i%4];
        }
        //发现全部复位之后,空格的位置没有变,多出来了空格,全局变量再改改
        x=3;y=3;
        initImage();
    }

    //判断是否胜利,可以返回bool类型,减少变量定义
    private boolean winOrNot() {
        for (int i = 0; i < 16; i++) {
            if (data[i/4][i%4]!=win[i/4][i%4]){
                return false;
            }
        }
        return true;
    }

    //展示胜利
    private void showWin(){
        String winPath = "JAVA基础\\src\\Day16\\image\\win.png";
        JLabel winLabel = new JLabel(new ImageIcon(winPath));
        winLabel.setBounds(203,283,197,73);
        this.getContentPane().add(winLabel);
    }

    //由于实现了KeyListener,所以不用写多个匿名内部类了,调用自己重写的方法即可
    @Override
    public void keyReleased(KeyEvent e) {
        if(winOrNot()){
            return;
        }
        //在刷新界面的时候:需要把图片清空!再刷新图片!两步写在initImage里面
        int code = e.getKeyCode();//左上右下37- 40;
        if (code==37){
            System.out.println("向左移动");
            if (y==3) return;
            //我的xy一直都整反了。x代表纵向位置,y代表横向位置
            data[x][y]=data[x][y+1];
            data[x][y+1]=0;
            //空白方块的位置变了!记得跟踪。
            y++;
            count++;
            initImage();
        }else if (code==38){
            System.out.println("向上移动");
            if (x==3)return;
            data[x][y]=data[x+1][y];
            data[x+1][y]=0;
            x++;
            count++;
            initImage();
        }else if (code==39){
            System.out.println("向右移动");
            if (y==0)return;
            data[x][y]=data[x][y-1];
            data[x][y-1]=0;
            y--;
            count++;
            initImage();
        }else if(code == 40){
            System.out.println("向下移动");
            if (x==0)return;
            data[x][y]=data[x-1][y];
            data[x-1][y]=0;
            x--;
            count++;
            initImage();
        }else if ('A'==e.getKeyCode()){
            initImage();
        }else if('W'==e.getKeyCode()){
            System.out.println("按下W直接胜利!");
            cheat();
        }
    }
    @Override
    public void keyPressed(KeyEvent e) {
        if(winOrNot()){
            return;
        }
        //按住A显示完整图片,松开A显示随机打乱的图片
        if ('A'==e.getKeyCode()){
            System.out.println("按下A");
            showImageAll();
        }
    }
    @Override
    public void keyTyped(KeyEvent e) {}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值