AI+Java开发项目——石头迷阵游戏

做一个有趣一点的项目,一方面提升编程思维,提升编程能力。同时开发一个实战的游戏,可以跟学java的人员拉开距离。

游戏项目开发的思路:

1.GUI界面编程 :使用Swing技术

2.二维数组

3.程序流程控制:因为在业务的推进过程中,肯定会涉及到一些循环的操作。再包括比如把拼图顺序打乱,肯定需要程序流程控制,循环。

4.面向对象编程:这个界面需要去继承一个Jframe成为一个窗口对象。他们是需要我们的一个面向对象编程的语法来理解的,包括这里面的事件监听器上下左右。给他绑定匿名内部类对象多需要一些匿名内部类的知识。

准备环节

  • 创建一个模块用于开发石头迷阵游戏,模块名称取名为:stone-maze
  • 导入项目需要的资源包到src目录下:主要是一些图片文件,在image文件夹下。
  • 创建项目包:com.itheima.

一、创建石头迷阵界面

  • 定义主界面类,MainFrame继承JFrame.

独立功能独立成方法,在MainFrame.java中不仅要初始化窗口,还要初始化界面,初始化菜单。分三块功能进行制作,所以不要在这里直接写这个代码,最好在无参构造器里面。 当别人调用无参构造器时在其里面进行初始化。这样的话程序比较逻辑清晰。代码复用性比较高,比较优雅。

  • 初始化窗口大小

窗口大小要根据图片的大小和实际项目的需求来进行设定。注意:显示窗口一定要设置到最后,当日常AI生成的代码没有运行没有显示出时,有可能就是这个问题。

  • 初始化界面图片
  • 初始化界面菜单:系统退出,重启游戏。

二、打乱顺序

打乱界面的图片顺序,让游戏具备可玩性:使用方法如下

打乱二维数组中的元素顺序:initRandomArray();

完成代码如下:

package com.itheima;

import javax.swing.*;
//自定义窗口类,创建对象,展示一个主窗口。
public class MainFrame extends JFrame {
    //设置图片位置,将图片位置设置为常量,防止后期改模块名而找不到图片位置
    private static final String imagePath = "stone-maze/src/image/";
    //准备一个数组。用户存储数字色块的行列位置:4行4列
    private int[][] imageData = {
            {1,2,3,4},
            {5,6,7,8},
            {9,10,11,12},
            {13,14,15,0}
    };


    public MainFrame() {
        //1.调用一个初始化方法:初始化窗口大小等信息
        initFrame();
        //4.打乱数组色块的顺序,再展示图片
        initRandomArray();
        //2.初始化界面,展示数字色块。
        initImage();
        //3.初始化系统菜单,点击弹出菜单信息是系统退出,重启游戏
        initMenu();
        //设置窗口的显示.注意显示窗口一定要设置到最后
        this.setVisible(true);
    }

    private void initRandomArray() {
        //打乱二维数组中的元素顺序
        for (int i = 0; i < imageData.length; i++) {
            for (int j = 0; j < imageData[i].length; j++) {
                //随机两个行列位置,让两个位置交换
                int i1 = (int)(Math.random()*imageData.length);
                int j1 = (int)(Math.random()*imageData.length);

                int i2 = (int)(Math.random()*imageData.length);
                int j2 = (int)(Math.random()*imageData.length);

                int temp = imageData[i1][j1];
                imageData[i1][j1] = imageData[i2][j2];
                imageData[i2][j2] = temp;
            }
        }
    }

    private void initMenu() {
        JMenuBar menuBar = new JMenuBar();//创建一个菜单条
        JMenu menu = new JMenu("系统");//创建一个菜单
        JMenuItem exitJi = new JMenuItem("退出");
        menu.add(exitJi);//添加一个菜单项
        exitJi.addActionListener(e -> {
            dispose();//销毁!
        });
        //添加一个菜单,重启
        JMenuItem restartJi = new JMenuItem("重启");
        menu.add(restartJi);
        restartJi.addActionListener(e -> {
            //重启游戏。
        });
        menuBar.add(menu);//添加到菜单条中
        this.setJMenuBar(menuBar);
    }

    private void initImage() {
        //1.展示一个行列矩阵的图片色块依次铺满窗口(4*4)
        for (int i = 0; i < imageData.length; i++) {
            for (int j = 0; j < imageData[i].length; j++) {
                //2.拿到图片名称
                String imageName = imageData[i][j] + ".png";
                //2.创建一个JLabel对象,设置图片给他展示
                JLabel label = new JLabel();
                //3.设置图片到label对象中去
                label.setIcon(new ImageIcon(imagePath + imageName));
                //4.设置图片展示位置
                label.setBounds(20+j * 100, 60+i * 100, 100, 100);
                //5.把这个图片展示到窗口上去,this代表当前窗口主对象
                this.add(label);
            }
        }

        //设置窗口的背景图片(背景图片太小了所以没展示)
        JLabel background = new JLabel(new ImageIcon(imagePath + "background.png"));
        background.setBounds(0, 0, 450, 484);
        this.add(background);

    }

    private void initFrame() {
        //设置窗口的标题
        this.setTitle("石子迷阵 V 1.0 xuan");
        //设置窗口的宽高
        this.setSize(465, 575);
        //设置窗口关闭方式
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //设置窗口居中
        this.setLocationRelativeTo(null);
        //设置布局方式为绝对位置定位,一定要设置绝对布局,用于展示图片在坐标上的位置
        this.setLayout(null);
    }
}
package com.itheima;

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

三、控制上下左右移动

  • 给窗口绑定上下左右按键事件
  • 控制位置的交换

        ——定位当前空白色块的位置

        ——根据用户点击的方位确定交换哪个数据,到数组中交换

  • 重新绘制主界面的内容

        ——让主界面按照二维数组的最新内容刷新界面

//5.给当前窗口绑定上下左右按键事件。
        initKeyPressEvent();
 private void initKeyPressEvent() {
        //给当前窗口绑定上下左右按键事件。
        this.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //获取当前按钮的编号
                int keyCode = e.getKeyCode();
                //判断这个编号是否是上下左右的按键
                switch (keyCode) {
                    case KeyEvent.VK_UP:
                        //用户按了上建,让图片向上移动。
                        switchAndMove(Direction.UP);
                        break;
                    case KeyEvent.VK_DOWN:
                        //用户按了下建,让图片向下移动。
                        switchAndMove(Direction.DOWN);
                        break;
                    case KeyEvent.VK_LEFT:
                        //用户按了左建,让图片向左移动。
                        switchAndMove(Direction.LEFT);
                        break;
                    case KeyEvent.VK_RIGHT:
                        //用户按了右建,让图片向右移动。
                        switchAndMove(Direction.RIGHT);
                        break;
                }
            }
        });
    }
package com.itheima;
//使用枚举来定义方向,使项目更加专业
public enum Direction {
    UP,DOWN,LEFT,RIGHT;
}

  

四、判断是否通关

  • 用户每操作一步,需要立即判断是否已经通过,如果通过,需要显示胜利的标记。
//判断是否赢了。我们设置只要用户刷新界面就要判断一次用户是否胜利。
        //且将图层设置在所有界面的上面
        if (isWin()) {
            //展示胜利的图片
            JLabel label = new JLabel(new ImageIcon(imagePath + "win.png"));
            label.setBounds(124, 230, 266, 88);
            this.add(label);
        }
        //1.展示一个行列矩阵的图片色块依次铺满窗口(4*4)
        for (int i = 0; i < imageData.length; i++) {
            for (int j = 0; j < imageData[i].length; j++) {
                //2.拿到图片名称
                String imageName = imageData[i][j] + ".png";
                //2.创建一个JLabel对象,设置图片给他展示
                JLabel label = new JLabel();
                //3.设置图片到label对象中去
                label.setIcon(new ImageIcon(imagePath + imageName));
                //4.设置图片展示位置
                label.setBounds(20+j * 100, 60+i * 100, 100, 100);
                //5.把这个图片展示到窗口上去,this代表当前窗口主对象
                this.add(label);
            }
        }

        //设置窗口的背景图片(背景图片太小了所以没展示)
        JLabel background = new JLabel(new ImageIcon(imagePath + "background.png"));
        background.setBounds(0, 20, 450, 484);
        this.add(background);

        //刷新新图层,重新绘制
        this.repaint();
private boolean isWin() {
        //判断游戏二维数组和赢了之后的二维数组的内容是否一样,只要有一个位置处的数据不一样,说明没有赢了
        for (int i = 0; i < imageData.length; i++) {
            for (int j = 0; j < imageData[i].length; j++) {
                if (imageData[i][j] != winData[i][j]) {
                    return false;
                }
            }
        }
        //赢了
        return true;
    }

五、统计移动步骤、重启游戏

  • 没成功移动一步,都需要累加一次步数
  • 定义一个变量用于累加步数,并实时展示到界面上
private int count;//统计总共移动的步数。
 //先清空窗口上的全部图层
        this.getContentPane().removeAll();

        //刷新界面时,可以给界面显示步数。
        //给窗口添加一个展示文字的组件
        JLabel countTxt = new JLabel("当前移动" + count + "步");
        countTxt.setBounds(20, 20, 100, 20);
        //把文字展示成红色
        countTxt.setForeground(Color.RED);
        //加粗
        countTxt.setFont(new Font("楷体", Font.BOLD, 12));
        this.add(countTxt);

六、拓展问题

数字华容道的乱序操作,并不是可以随意打乱的,必须满足一定的算法去打乱顺序,这样才是有解的,才能让玩家恢复到有序。有没有简单的算法????

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

c萱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值