当前位置: 首页 > news >正文

Java-拼图小游戏跟学笔记

阶段项目-01-项目介绍和界面搭建_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV17F411T7Ao?p=144

代码

1.主界面分析(组件)

JFrame:最外层的窗体

JMenuBar:最上层的菜单

JLabel:管理文字和图片的容器

1.界面

--关闭模式--

  • DO_NOTHING_ON_CLOSE:当用户尝试关闭窗口时,程序什么都不做。

  • HIDE_ON_CLOSE:当用户尝试关闭窗口时,窗口会被隐藏起来,但不会被销毁。

  • DISPOSE_ON_CLOSE:当用户尝试关闭窗口时,窗口会被销毁,释放掉所有相关的资源。

  • EXIT_ON_CLOSE:当用户尝试关闭窗口时,整个程序会直接退出。

public interface WindowConstants
{
    /**
     * 什么都不做的默认窗口关闭操作。
     */
    public static final int DO_NOTHING_ON_CLOSE = 0;

    /**
     * 隐藏窗口的默认窗口关闭操作。
     */
    public static final int HIDE_ON_CLOSE = 1;

    /**
     * 销毁窗口的默认窗口关闭操作。
     * <p>
     * <b>注意</b>:当 Java 虚拟机(VM)中的最后一个可显示窗口被销毁时,虚拟机可能会终止。更多信息请参见
     * <a href="../../java/awt/doc-files/AWTThreadIssues.html">
     * AWT 线程问题</a>。
     * @see java.awt.Window#dispose()
     * @see JInternalFrame#dispose()
     */
    public static final int DISPOSE_ON_CLOSE = 2;

    /**
     * 退出应用程序的默认窗口关闭操作。尝试在支持此功能的窗口(如
     * <code>JFrame</code>)上设置此值时,可能会根据
     * <code>SecurityManager</code> 抛出 <code>SecurityException</code>。
     * 建议仅在应用程序中使用此选项。
     *
     * @since 1.4
     * @see JFrame#setDefaultCloseOperation
     */
    public static final int EXIT_ON_CLOSE = 3;

}

代码展示

package com.scarelf.ui;

import javax.swing.*;
import java.awt.*;

public class GameJFrame extends JFrame {

    public GameJFrame() {
        //设置界面的宽高
        this.setSize(603,680);
        //设置界面的标题
        this.setTitle("拼图单机版 v1.0");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //让界面显示出来,建议写在最后
        setVisible(true);
    }
}

2.菜单

//初始化菜单
        //创建整个的菜单对象
        JMenuBar jMenuBar = new JMenuBar();

        //创建菜单上面的两个选项对象
        JMenu functionJMenu = new JMenu("功能");
        JMenu aboutJMenu = new JMenu("关于制作人");
        JMenu rechargeJMenu = new JMenu("充值选项");

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

        JMenuItem accountItem = new JMenuItem("公众号");
        JMenuItem QQItem = new JMenuItem("制作人QQ");

        JMenuItem wepayItem = new JMenuItem("微信支付");

        //将每个选项下面的条目添加到选项当中
        functionJMenu.add(replayItem);
        functionJMenu.add(reLoginItem);
        functionJMenu.add(closeItem);

        aboutJMenu.add(accountItem);
        aboutJMenu.add(QQItem);

        rechargeJMenu.add(wepayItem);

        //将菜单里面的两个选项添加到菜单当中
        jMenuBar.add(functionJMenu);
        jMenuBar.add(aboutJMenu);
        jMenuBar.add(rechargeJMenu);

        //给整个界面设置菜单
        this.setJMenuBar(jMenuBar);

3.添加图片

  1. 取消默认的居中放置
  2. 创建一个图片ImageIcon的对象
  3. 创建一个JLabel的对象(管理容器)
  4. 指定图片位置
  5. 把管理容器添加到界面中

 前提

private void initImage() {
        int number = 1;
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                //创建一个JLabel的对象(管理容器)
                JLabel jLabel1 = new JLabel(path + num + ".jpg");
                //指定图片位置
                jLabel1.setBounds(105*j,105*i,105,105);
                //把管理容器添加到界面中
                //this.add(jLabel1);
                this.getContentPane().add(jLabel1);
            }
            number++;
        }
        
    }

4.打乱图片顺序

(1)测试类

package Test;

import java.util.Random;

public class 打乱 {
    public static void main(String[] args) {
        //需求:
        //把一个一维数组中的数据:0~15打乱顺序
        //让后再按照4个一组的方式添加到二维数组当中去

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

        Random r = new Random();
        for (int i = 0; i < tempArr.length; i++) {
            int index = r.nextInt(tempArr.length);
            int temp = tempArr[index];
            tempArr[index] = tempArr[i];
            tempArr[i] = temp;
        }

        int [][]data = new int [4][4];
        for (int i = 0; i < tempArr.length; i++) {
            data[i/4][i%4] = tempArr[i];
        }
    }
}

(2)修改

把data定义在成员变量当中,因为initData和initImage都会用到此数据

private void initImage() {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                int num = data[i][j];
                //创建一个JLabel的对象(管理容器)
                JLabel jLabel1 =new JLabel(path+ num + ".jpg");
                //指定图片位置
                jLabel1.setBounds(105*j,105*i,105,105);
                //把管理容器添加到界面中
                //this.add(jLabel1);
                this.getContentPane().add(jLabel1);
            }
        }
    }

5.事件

事件是可以被组件识别的操作

当你对组件干了某件事情之后,就会执行对应的代码

  • 事件源:按钮,图片,窗体
  • 事件:某些操作(鼠标点击,鼠标划入)
  • 绑定监听:当时间源上发生了某个事件,则执行某段代码

KeyListener              //键盘监听

MouseListener         //鼠标监听

ActionListener          //动作监听(鼠标的单击和空格)

(1)ActionListener

package Test;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class thingTest1 {
    public static void main(String[] args) {
        JFrame jFrame = new JFrame();
        jFrame.setSize(603,680);
        jFrame.setTitle("事件演示");
        jFrame.setAlwaysOnTop(true);
        jFrame.setLocationRelativeTo(null);
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        jFrame.setLayout(null);

        //创建一个按钮对象
        JButton jtb = new JButton("按钮1");
        //设置位置和宽高
        jtb.setBounds(0,0,100,50);
        //给按钮添加动作监听
        //jtb:组件对象,表示你要给那个组件添加事件
        //addActionListener:表示我要给组件添加哪一个事件监听(动作监听)
        //参数:表示事件被触发时候要执行的代码
        //jtb.addActionListener(new MyActionListener());

        //使用匿名内部类
        jtb.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("按钮1被点击了");
            }
        });
        //把按钮添加到界面当中
        jFrame.getContentPane().add(jtb);


        jFrame.setVisible(true);
    }
}
package Test;//下同

public class MyJFrameTest {
    public static void main(String[] args) {
       new MyJFrame();

    }

}
-----------------------------------------------------------------------------------------

package Test;

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

public class MyJFrame extends JFrame implements ActionListener {

    JButton jtb1 = new JButton("按钮1");
    JButton jtb2 = new JButton("按钮2");
    
    public MyJFrame() {
        this.setSize(603,680);
        this.setTitle("事件测试类 2");
        this.setAlwaysOnTop(true);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setLayout(null);


        jtb1.setBounds(0,0,100,50);
        jtb1.addActionListener(this);

        jtb2.setBounds(100,0,100,50);
        jtb2.addActionListener(this);

        //把按钮添加到界面当中
        this.getContentPane().add(jtb1);
        this.getContentPane().add(jtb2);

        this.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();

        if(source == jtb1){
            jtb1.setSize(200,200);
        }else if(source == jtb2){
            Random r = new Random();
            jtb2.setLocation(r.nextInt(500),r.nextInt(500));
        }
    }

}

(2)鼠标监听

package Test;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class MyJFrame2 extends JFrame implements MouseListener {

    JButton jtb1 = new JButton("按钮1");

    public MyJFrame2() {
        this.setSize(603,680);
        this.setTitle("事件测试类 2");
        this.setAlwaysOnTop(true);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setLayout(null);

        jtb1.setBounds(0,0,100,50);
        jtb1.addMouseListener(this);

        //把按钮添加到界面当中
        this.getContentPane().add(jtb1);

        this.setVisible(true);
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        System.out.println("点击");
    }

    @Override
    public void mousePressed(MouseEvent e) {
        System.out.println("按住不松");
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        System.out.println("松开");
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        System.out.println("划入");
    }

    @Override
    public void mouseExited(MouseEvent e) {
        System.out.println("划出");
    }

}

(3)键盘监听

package Test;

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

public class MyJFrame3 extends JFrame implements KeyListener {
    JButton jtb1 = new JButton("button");

    public MyJFrame3() {
        this.setSize(603,680);
        this.setTitle("MyJFrame3");
        this.setAlwaysOnTop(true);
        this.setLocationRelativeTo(null);

        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setLayout(null);

        jtb1.setBounds(0,0,100,50);
        jtb1.addKeyListener(this);

       this.getContentPane().add(jtb1);
        this.setVisible(true);
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {
        System.out.println("按下不松");
    }

    @Override
    public void keyReleased(KeyEvent e) {
        int code = e.getKeyCode();
        System.out.println(code);
    }
}

6.美化界面

1.将15张小图片移动到界面的中央偏下方

2.添加背景图片

        细节:代码中后添加的,塞在下面

3.添加图片的边框

jLabel.setBoreder(new BevelBorder(1));

4.优化路径

  • 从盘符开始的:绝对路径
  • 非盘符开始的:相对路径
private void initImage() {

        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                int num = data[i][j];
                //创建一个JLabel的对象(管理容器)
                JLabel jLabel1 =new JLabel(path + num + ".jpg");
                //指定图片位置
                jLabel1.setBounds(105*j + 83,105*i + 105,105,105);
                //给图片添加边框
                //0:表示让图片凸起来
                //1:表示让图片凹下去
                jLabel1.setBorder(new BevelBorder(BevelBorder.LOWERED));
                //把管理容器添加到界面中
                //this.add(jLabel1);
                this.getContentPane().add(jLabel1);
            }
        }

        //添加背景图
        JLabel background = new JLabel(new ImageIcon("image/background.png"));
        background.setBounds(40, 40, 800, 600);
        //把背景图添加到界面当中
        this.getContentPane().add(background);
    }

7.上下移动

1.本类实现KeyListener接口,并重写所有抽象方法

2.给整个界面添加键盘监听事件

3.统计一下空白方块对应的数字0在二维数组中的位置

4.Bug修复

  • 当空白方块在最下方时,无法再次进行上移
  • 当空白方块在最上方时,无法再次进行下移
  • 当空白方块在最左方时,无法再次进行右移
  • 当空白方块在最右方时,无法再次进行左移

因为东西实在太多了所以就把改变的部分发出来,最后我再展示源码

...
public class GameJFrame extends JFrame implements KeyListener {

    ...
    int x = 0;
    int y = 0;

    public GameJFrame() {
        //设置界面
        initJFrame();

        //设置菜单
        initJMenuBar();

        //初始化数据(打乱)
        initData();

        //初始化图片
        initImage();
        //让界面显示出来,建议写在最后
        setVisible(true);
    }

    private void initData() {
        ...

        for (int i = 0; i < tempArr.length; i++) {
            if(tempArr[i] == 0){
                x = i / 4;
                y = i % 4;
            }else{
                data[i/4][i%4] = tempArr[i];
            }

        }
    }

    private void initImage() {
        //清空原本已经出现的所有图片
        this.getContentPane().removeAll();

       ...
        //刷新一下界面
        this.getContentPane().repaint();
    }

    private  void initJMenuBar(){
        ...
    }

    private void initJFrame(){
        ...
        //给整个界面添加键盘监听事件
        this.addKeyListener(this);

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {

    }

    @Override
    public void keyReleased(KeyEvent e) {
        //对上, 下, 左, 右进行判断
        //左: 37 上: 38 右: 39 下: 40
        int code = e.getKeyCode();
        if(code == 37){
            if(y == 3){
                return;
            }

            data[x][y]=data[x][y+1];
            data[x][y+1]=0;
            y++;
            initImage();
        }else if(code == 38){
            if(x == 3){
                return;
            }
            //逻辑:把空白方块下方的数字往上移动
            //x, y  表示空白方块
            //x+1, y  表示空白方块下方的数字

            //把空白方块下方的数字赋值给空白方块
            data[x][y]=data[x+1][y];
            data[x+1][y]=0;
            x++;
            //调用方法按照最新的数字加载图片
            initImage();
        }else if(code == 39){
            if(y == 0){
                return;
            }

            data[x][y]=data[x][y-1];
            data[x][y-1]=0;
            y--;
            initImage();
        }else if(code == 40){
            if(x == 0){
                return;
            }
            data[x][y]=data[x-1][y];
            data[x-1][y]=0;
            x--;
            initImage();
        }
    }
}

 8.查看完整图片

String path = "images";

//按下不松时会调用这个方法
    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if(code == 65){
            //把界面中所有的图片全部删除
            this.getContentPane().removeAll();
            //加载一张完整的图片
            JLabel all = new JLabel(new ImageIcon(path + "all.jpg"));
            all.setBounds(83, 134, 420, 420);
            this.getContentPane().add(all);
            //添加背景图
            JLabel background = new JLabel(new ImageIcon("image/background.png"));
            background.setBounds(40, 40, 800, 600);
            //把背景图添加到界面当中
            this.getContentPane().add(background);

            //刷新一下界面
            this.getContentPane().repaint();

        }
    }

9.作弊码

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

            };
            initImage();
        }

10.判断胜利

//判断data数组中的数据是否跟win数组中相同
    //如果全部相同,返回true,否则返回false
    public boolean victory(){
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data.length; j++) {
                if(data[i][j] != win[i][j]){
                    return false;
                }

            }
        }
        return true;
    }

 

 11.记步功能

 JLabel stepCount = new JLabel("步数" + step);
        stepCount.setBounds(50,30,100,20);
        this.getContentPane().add(stepCount);
...
x++;
step++;
initImage();
...

12.JMenuBar相关事件

if(obj == replayItem){
            //再次打乱二维数组中的数据
            initData();
            //计步器清零
            step = 0;
            //重新加载图片
            initImage();

        }else if(obj == reLoginItem){
            //关闭当前界面
            this.setVisible(false);
            //打开登录界面
            new LoginJFrame();
        }else if(obj == closeItem){
            //直接关闭虚拟机即可
            System.exit(0);
        }else if(obj == accountItem){
            //创建一个弹框对象
            JDialog jDialog = new JDialog();
            //创建一个管理图片的容器对象JLabel
            JLabel jLabel = new JLabel(new ImageIcon( "image\\img_1.png"));
            //设置位置和宽高
            jLabel.setBounds(0,0,getWidth(),getHeight());
            //把图片添加到弹框当中
            jDialog.getContentPane().add(jLabel);
            //给弹框设置大小
            jDialog.setSize(500,500);
            //让弹框置顶
            jDialog.setAlwaysOnTop(true);
            //让弹框居中
            jDialog.setLocationRelativeTo(null);
            //弹框不关闭则无法操作下面的界面
            jDialog.setModal(true);
            //让弹框显示出来
            jDialog.setVisible(true);
...

因为下面的一部分都是网课上面留的作业,因为本人实力有限,怕误导大家,所以我写得解释就比较少了,虽然最终代码可以运行,但是自己心里也不是十拿九稳

13.更换图片

需要知道在更换图片中更换图片是JMenu,而其下面的分类是JMenuItem

...
JMenuItem animal = new JMenuItem("动物");
    JMenuItem girl = new JMenuItem("女性");
    JMenuItem sport = new JMenuItem("运动");
...
//创建更换图片
JMenu changeImage = new JMenu("更换图片");
...
changeImage.add(animal);
changeImage.add(girl);
changeImage.add(sport);
...
else if(obj == animal){
            //选择随机图片
            Random r = new Random();
            int index =r.nextInt(8) + 1;
            path = "image\\animal\\animal"+ index + "\\";
            //再次打乱二维数组中的数据
            initData();
            //计步器清零
            step = 0;
            //重新加载图片
            initImage();
        }else if(obj == girl){
            //选择随机图片
            Random r = new Random();
            int index =r.nextInt(13)+1;
            path = "image\\girl\\girl" + index + "\\";
            //再次打乱二维数组中的数据
            initData();
            //计步器清零
            step = 0;
            //重新加载图片
            initImage();
        }else if (obj == sport){
            //选择随机图片
            Random r = new Random();
            int index =r.nextInt(10)+1;
            path = "image\\sport\\sport" + index + "\\";
            //再次打乱二维数组中的数据
            initData();
            //计步器清零
            step = 0;
            //重新加载图片
            initImage();
        }

14.登录界面

(1)提前设置账号密码

//创建一个集合存储正确的用户名和密码
    static ArrayList<User> allUsers = new ArrayList<>();
    static {
        allUsers.add(new User("ccc","123456"));
        allUsers.add(new User("bbb","123456"));
        allUsers.add(new User("aaa","123456"));
    }
...
...
private static class User {
        static String username;
        static String  password;

        public User() {
        }

        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }

(2)明文显示的输入框和密文显示的输入框

JTextField username = new JTextField();
JPasswordField password = new JPasswordField();

(3)设置弹窗方法

private void showJDialog(String contnet) {
        JDialog dialog = new JDialog();
        dialog.setSize(200, 150);
        dialog.setAlwaysOnTop(true);
        dialog.setLocationRelativeTo(null);
        dialog.setModal(true);

        JLabel label = new JLabel(contnet);
        label.setBounds(0, 0, 200, 150);
        dialog.getContentPane().add(label);
        dialog.setVisible(true);
    }

(4)对按钮的操作美化等

 @Override
    public void mousePressed(MouseEvent e) {
        Object source =e.getSource();
        if(source ==login) {
            login.setIcon(new ImageIcon("image\\login\\登录按下.png"));
        } else if(source ==register){
            register.setIcon(new ImageIcon("image\\login\\注册按下.png"));
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        Object source =e.getSource();
        if(source ==login) {
            login.setIcon(new ImageIcon("image\\login\\登录按钮.png"));
        } else if(source ==register){
            register.setIcon(new ImageIcon("image\\login\\注册按钮.png"));
        }
    }

(5)对有事件交互的变量定义在成员变量的地方

JButton register = new JButton();
    JButton login = new JButton();
    String codeStr = CodeUtil.getCode();
    JLabel rightCode = new JLabel(codeStr);

    JTextField username = new JTextField();
    JPasswordField password = new JPasswordField();
    JTextField code = new JTextField();

其中对验证码的要求是定义一个工具类,而且需要点击就会改变

package CodeUtil;

import java.util.ArrayList;
import java.util.Random;

public class CodeUtil {
    public static String getCode(){
        //1.创建一个集合
        ArrayList<Character> list = new ArrayList<>();
        //2,添加字母a - z, A - Z
        for (int i = 0; i < 26; i++) {
            list.add((char) ('a' + i));
            list.add((char) ('A' + i));
        }
        //3.生成四个随机字母
        String result ="";
        Random r = new Random();
        for (int i = 0; i < 4; i++) {
            int index0 = r.nextInt(list.size());
            result += list.get(index0);
        }
        //4.在后面添加数字
        int number = r.nextInt(10);
        result = result + number;
        //5.把字符串变成字符数组
        char[] chars = result.toCharArray();
        //6.打乱顺序
        int index = r.nextInt(chars.length);
        char temp = chars[4];
        chars[4] = chars[index];
        chars[index] = temp;
        //7.把字符数组变回字符串
        String code = new String(chars);
        return code;
    }
}

(6)对账号和密码进行判断

@Override
    public void mouseClicked(MouseEvent e) {
            Object source =e.getSource();
            if(source ==rightCode){
                String code = CodeUtil.getCode();
                rightCode.setText(code);
            }else if(source ==login){
                //获取两个文本输入框中的内容
                String usernameInput = this.username.getText();
                String passwordInput = this.password.getText();
                //获取用户输入的验证码
                String codeInput = code.getText();
               User userInfo = new User(usernameInput,passwordInput);
               if(codeInput.length() == 0){
                   showJDialog("验证码不能为空");
               }else if(usernameInput.length() == 0 ||passwordInput.length() == 0){
                   showJDialog("用户名或者密码为空");
               }else if(codeInput.equals(rightCode.getText())){
                   showJDialog("验证码输入错误");
               }else if(contains(userInfo)){
                   this.setVisible(false);
                   new GameJFrame();
               }else {
                   showJDialog("用户名或密码错误");
               }
            }else if(source ==register){
                this.setVisible(false);
                new Registerjframe();
            }
    }

    public boolean contains(User userInput){
        for (int i = 0; i < allUsers.size(); i++) {
           User rightUser = allUsers.get(i);
           if(userInput.getUsername().equals(rightUser.getUsername()) &&
                   userInput.getPassword().equals(rightUser.getPassword())){
               return true;
           }
        }
        return false;
    }

因为注册需要其他知识点所以在这个还没有写出来,下面展示所有代码

源码

package com.scarelf.ui;

import javax.swing.*;
import javax.swing.border.BevelBorder;
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 GameJFrame extends JFrame implements KeyListener, ActionListener {

    //创建一个二维数组:用来管理数据
    //加载图片的时候,会根据二维数组中的数据进行加载
    int [][]data = new int [4][4];
    //记录空白方块在二维数组中的位置
    int x = 0;
    int y = 0;
    String path = "image\\animal\\animal3\\";

    //定义一个二维数组,存储正确的数据
    int [][] win = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12},
        {13, 14, 15, 0}
    };

    //定义变量用来统计步数
    int step = 0;

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

    JMenuItem accountItem = new JMenuItem("二维码");
    JMenuItem QQItem = new JMenuItem("制作人QQ");

    JMenuItem wePayItem = new JMenuItem("微信支付");


    JMenuItem animal = new JMenuItem("动物");
    JMenuItem girl = new JMenuItem("女性");
    JMenuItem sport = new JMenuItem("运动");

    public GameJFrame() {
        //设置界面
        initJFrame();

        //设置菜单
        initJMenuBar();

        //初始化数据(打乱)
        initData();

        //初始化图片
        initImage();
        //让界面显示出来,建议写在最后
        setVisible(true);
    }

    private void initData() {
        int [] tempArr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

        Random r = new Random();
        for (int i = 0; i < tempArr.length; i++) {
            int index = r.nextInt(tempArr.length);
            int temp = tempArr[index];
            tempArr[index] = tempArr[i];
            tempArr[i] = temp;
        }


        for (int i = 0; i < tempArr.length; i++) {
            if(tempArr[i] == 0){
                x = i / 4;
                y = i % 4;
            }
            data[i/4][i%4] = tempArr[i];
        }
    }

    private void initImage() {
        //清空原本已经出现的所有图片
        this.getContentPane().removeAll();

        if(victory()){
            //显示胜利图标
           JLabel winJLabel = new JLabel(new ImageIcon("image\\win.png"));
           winJLabel.setBounds(203,283,197,73);
           this.getContentPane().add(winJLabel);
        }

        JLabel stepCount = new JLabel("步数" + step);
        stepCount.setBounds(50,30,100,20);
        this.getContentPane().add(stepCount);


        //先加载的图片在上方,后加载的图片塞在下面
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                int num = data[i][j];
                //创建一个JLabel的对象(管理容器)
                JLabel jLabel1 =new JLabel( new ImageIcon(path + num + ".jpg"));
                //指定图片位置
                jLabel1.setBounds(105*j + 83,105*i + 134,105,105);
                //给图片添加边框
                //0:表示让图片凸起来
                //1:表示让图片凹下去
                jLabel1.setBorder(new BevelBorder(BevelBorder.LOWERED));
                //把管理容器添加到界面中
                //this.add(jLabel1);
                this.getContentPane().add(jLabel1);
            }
        }

        //添加背景图
        JLabel background = new JLabel(new ImageIcon( "image/background.png"));
        background.setBounds(40, 40, 508, 560);
        //把背景图添加到界面当中
        this.getContentPane().add(background);

        //刷新一下界面
        this.getContentPane().repaint();
    }

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

        //创建菜单上面的两个选项对象
        JMenu functionJMenu = new JMenu("功能");
        JMenu aboutJMenu = new JMenu("关于我");
        JMenu rechargeJMenu = new JMenu("充值选项");

        //创建更换图片
        JMenu changeImage = new JMenu("更换图片");

        //给条目绑定事件
        replayItem.addActionListener(this);
        reLoginItem.addActionListener(this);
        closeItem.addActionListener(this);

        animal.addActionListener(this);
        girl.addActionListener(this);
        sport.addActionListener(this);

        accountItem.addActionListener(this);
        QQItem.addActionListener(this);

        wePayItem.addActionListener(this);

        //将每个选项下面的条目添加到选项当中
        functionJMenu.add(changeImage);
        functionJMenu.add(replayItem);
        functionJMenu.add(reLoginItem);
        functionJMenu.add(closeItem);

        changeImage.add(animal);
        changeImage.add(girl);
        changeImage.add(sport);

        aboutJMenu.add(accountItem);
        aboutJMenu.add(QQItem);

        rechargeJMenu.add(wePayItem);

        //将菜单里面的两个选项添加到菜单当中
        jMenuBar.add(functionJMenu);
        jMenuBar.add(aboutJMenu);
        jMenuBar.add(rechargeJMenu);

        //给整个界面设置菜单
        this.setJMenuBar(jMenuBar);
    }

    private void initJFrame(){
        //设置界面的宽高
        this.setSize(603,680);
        //设置界面的标题
        this.setTitle("拼图单机版 v1.0");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //取消默认的的居中放置,只有取消了才会按照XY轴的形式添加组件
        setLayout(null);
        //给整个界面添加键盘监听事件
        this.addKeyListener(this);

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    //按下不松时会调用这个方法
    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if(code == 65){
            //把界面中所有的图片全部删除
            this.getContentPane().removeAll();
            //加载一张完整的图片
            JLabel all = new JLabel(new ImageIcon(path + "all.jpg"));
            all.setBounds(83, 134, 420, 420);
            this.getContentPane().add(all);
            //添加背景图
            JLabel background = new JLabel(new ImageIcon( "image/background.png"));
            background.setBounds(40, 40, 508, 560);
            //把背景图添加到界面当中
            this.getContentPane().add(background);

            //刷新一下界面
            this.getContentPane().repaint();

        }
    }

    //松开按键所对应的方法
    @Override
    public void keyReleased(KeyEvent e) {
        //判断游戏是否胜利,如果胜利,此方法需要直接结束,不能再执行下面的移动代码了
        if(victory()){
            //结束方法
            return;
        }


        //对上, 下, 左, 右进行判断
        //左: 37 上: 38 右: 39 下: 40
        int code = e.getKeyCode();
        if(code == 37){
            if(y == 3){
                return;
            }

            data[x][y]=data[x][y+1];
            data[x][y+1]=0;
            y++;
            step++;
            initImage();
        }else if(code == 38){
            if(x == 3){
                return;
            }
            //逻辑:把空白方块下方的数字往上移动
            //x, y  表示空白方块
            //x+1, y  表示空白方块下方的数字

            //把空白方块下方的数字赋值给空白方块
            data[x][y]=data[x+1][y];
            data[x+1][y]=0;
            x++;
            step++;
            //调用方法按照最新的数字加载图片
            initImage();
        }else if(code == 39){
            if(y == 0){
                return;
            }

            data[x][y]=data[x][y-1];
            data[x][y-1]=0;
            y--;
            step++;
            initImage();
        }else if(code == 40){
            if(x == 0){
                return;
            }
            data[x][y]=data[x-1][y];
            data[x-1][y]=0;
            x--;
            step++;
            initImage();
        }else if(code == 65){
            initImage();
        }else if(code == 87){
            data =new int [][]{
                    {1, 2, 3, 4},
                    {5, 6, 7, 8},
                    {9, 10, 11, 12},
                    {13, 14, 15, 0}

            };
            initImage();
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        //获取当前被点击的条目对象
        Object obj = e.getSource();
        if(obj == replayItem){
            //再次打乱二维数组中的数据
            initData();
            //计步器清零
            step = 0;
            //重新加载图片
            initImage();

        }else if(obj == reLoginItem){
            //关闭当前界面
            this.setVisible(false);
            //打开登录界面
            new LoginJFrame();
        }else if(obj == closeItem){
            //直接关闭虚拟机即可
            System.exit(0);
        }else if(obj == accountItem){
            //创建一个弹框对象
            JDialog jDialog = new JDialog();
            //创建一个管理图片的容器对象JLabel
            JLabel jLabel = new JLabel(new ImageIcon( "image\\img_1.png"));
            //设置位置和宽高
            jLabel.setBounds(0,0,getWidth(),getHeight());
            //把图片添加到弹框当中
            jDialog.getContentPane().add(jLabel);
            //给弹框设置大小
            jDialog.setSize(500,500);
            //让弹框置顶
            jDialog.setAlwaysOnTop(true);
            //让弹框居中
            jDialog.setLocationRelativeTo(null);
            //弹框不关闭则无法操作下面的界面
            jDialog.setModal(true);
            //让弹框显示出来
            jDialog.setVisible(true);

        }else if(obj == QQItem){
            //创建一个弹框对象
            JDialog jDialog = new JDialog();
            //创建一个管理图片的容器对象JLabel
            JLabel jLabel = new JLabel("2190144173");
            //设置位置和宽高
            jLabel.setBounds(200,0,getWidth(),getHeight());
            //把图片添加到弹框当中
            jDialog.getContentPane().add(jLabel);
            //给弹框设置大小
            jDialog.setSize(300,75);
            //让弹框置顶
            jDialog.setAlwaysOnTop(true);
            //让弹框居中
            jDialog.setLocationRelativeTo(null);
            //弹框不关闭则无法操作下面的界面
            jDialog.setModal(true);
            //让弹框显示出来
            jDialog.setVisible(true);

        }else if(obj == wePayItem){
            //创建一个弹框对象
            JDialog jDialog = new JDialog();
            //创建一个管理图片的容器对象JLabel
            JLabel jLabel = new JLabel(new ImageIcon("image\\img.png"));
            //设置位置和宽高
            jLabel.setBounds(0,0,getWidth(),getHeight());
            //把图片添加到弹框当中
            jDialog.getContentPane().add(jLabel);
            //给弹框设置大小
            jDialog.setSize(500,500);
            //让弹框置顶
            jDialog.setAlwaysOnTop(true);
            //让弹框居中
            jDialog.setLocationRelativeTo(null);
            //弹框不关闭则无法操作下面的界面
            jDialog.setModal(true);
            //让弹框显示出来
            jDialog.setVisible(true);
        }else if(obj == animal){
            //选择随机图片
            Random r = new Random();
            int index =r.nextInt(8) + 1;
            path = "image\\animal\\animal"+ index + "\\";
            //再次打乱二维数组中的数据
            initData();
            //计步器清零
            step = 0;
            //重新加载图片
            initImage();
        }else if(obj == girl){
            //选择随机图片
            Random r = new Random();
            int index =r.nextInt(13)+1;
            path = "image\\girl\\girl" + index + "\\";
            //再次打乱二维数组中的数据
            initData();
            //计步器清零
            step = 0;
            //重新加载图片
            initImage();
        }else if (obj == sport){
            //选择随机图片
            Random r = new Random();
            int index =r.nextInt(10)+1;
            path = "image\\sport\\sport" + index + "\\";
            //再次打乱二维数组中的数据
            initData();
            //计步器清零
            step = 0;
            //重新加载图片
            initImage();
        }
    }

    //判断data数组中的数据是否跟win数组中相同
    //如果全部相同,返回true,否则返回false
    public boolean victory(){
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data.length; j++) {
                if(data[i][j] != win[i][j]){
                    return false;
                }

            }
        }
        return true;
    }

}
package com.scarelf.ui;

import CodeUtil.CodeUtil;
import javax.swing.*;
import java.awt.event.*;
import java.security.PrivateKey;
import java.util.ArrayList;

public class LoginJFrame extends JFrame implements KeyListener, MouseListener {
    //创建一个集合存储正确的用户名和密码
    static ArrayList<User> allUsers = new ArrayList<>();
    static {
        allUsers.add(new User("lihaihang","123456"));
        allUsers.add(new User("gongxiaofan","123456"));
        allUsers.add(new User("wujunfeng","123456"));
    }

    JButton register = new JButton();
    JButton login = new JButton();
    String codeStr = CodeUtil.getCode();
    JLabel rightCode = new JLabel(codeStr);

    JTextField username = new JTextField();
    JPasswordField password = new JPasswordField();
    JTextField code = new JTextField();

    public LoginJFrame() {

        initJFrame();

        //在这个界面中添加内容
        initView();

        //让当前界面显示出来
        this.setVisible(true);
    }

    private void initView() {

        //1.添加用户名文字
        JLabel usernameText = new JLabel(new ImageIcon("image\\login\\用户名.png"));
        usernameText.setBounds(116, 135, 47, 17);
        this.getContentPane().add(usernameText);
        //2.添加用户名输入框
        username.setBounds(195, 134, 200, 30);
        this.getContentPane().add(username);
        //3.添加密码文字
        JLabel passwordText = new JLabel(new ImageIcon("image\\login\\密码.png"));
        passwordText.setBounds(130, 195, 32, 16);
        this.getContentPane().add(passwordText);
        //4.密码输入框
        password.setBounds(195, 195, 200, 30);
        this.getContentPane().add(password);

        //验证码提示
        JLabel codeText = new JLabel(new ImageIcon("image\\login\\验证码.png"));
        codeText.setBounds(133, 256, 50, 30);
        this.getContentPane().add(codeText);
        //验证码输入框
        code.setBounds(195, 256, 100, 30);
        this.getContentPane().add(code);



        //位置和宽高
        rightCode.setBounds(300, 256, 50, 30);
        this.getContentPane().add(rightCode);
        //添加监视功能
        rightCode.addMouseListener(this);

        // 5.添加登录按钮

        login.setBounds(123, 310, 128, 47);
        login.setIcon(new ImageIcon("image\\login\\登录按钮.png"));
        login.setBorderPainted(false);
        login.setContentAreaFilled(false);
        this.getContentPane().add(login);
        login.addMouseListener(this);
        //添加注册按钮

        register.setBounds(256, 310, 128, 47);
        register.setIcon(new ImageIcon("image\\login\\注册按钮.png"));
        register.setBorderPainted(false);
        register.setContentAreaFilled(false);
        this.getContentPane().add(register);
        register.addMouseListener(this);
        //7.添加背景图片

        JLabel backgroundImage = new JLabel(new ImageIcon("image\\login\\background.png"));
        backgroundImage.setBounds(0, 0, 470, 390);
        this.getContentPane().add(backgroundImage);
    }

    private void initJFrame () {
        setSize(488, 430);
        //设置界面的标题
        this.setTitle("拼图 登录");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //取消内部默认布局
        this.setLayout(null);
    }

    public void initImage(){

        JLabel userImage = new JLabel(new ImageIcon("./image/user.jpg"));
        userImage.setBounds(0, 0, 470, 390);

    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    @Override
    public void keyPressed(KeyEvent e) {

    }

    @Override
    public void keyReleased(KeyEvent e) {

    }

    @Override
    public void mouseClicked(MouseEvent e) {
            Object source =e.getSource();
            if(source ==rightCode){
                String code = CodeUtil.getCode();
                rightCode.setText(code);
            }else if(source ==login){
                //获取两个文本输入框中的内容
                String usernameInput = this.username.getText();
                String passwordInput = this.password.getText();
                //获取用户输入的验证码
                String codeInput = code.getText();
               User userInfo = new User(usernameInput,passwordInput);
               if(codeInput.length() == 0){
                   showJDialog("验证码不能为空");
               }else if(usernameInput.length() == 0 ||passwordInput.length() == 0){
                   showJDialog("用户名或者密码为空");
               }else if(codeInput.equals(rightCode.getText())){
                   showJDialog("验证码输入错误");
               }else if(contains(userInfo)){
                   this.setVisible(false);
                   new GameJFrame();
               }else {
                   showJDialog("用户名或密码错误");
               }
            }else if(source ==register){
                this.setVisible(false);
                new Registerjframe();
            }
    }

    public boolean contains(User userInput){
        for (int i = 0; i < allUsers.size(); i++) {
           User rightUser = allUsers.get(i);
           if(userInput.getUsername().equals(rightUser.getUsername()) &&
                   userInput.getPassword().equals(rightUser.getPassword())){
               return true;
           }
        }
        return false;
    }

    private void showJDialog(String contnet) {
        JDialog dialog = new JDialog();
        dialog.setSize(200, 150);
        dialog.setAlwaysOnTop(true);
        dialog.setLocationRelativeTo(null);
        dialog.setModal(true);

        JLabel label = new JLabel(contnet);
        label.setBounds(0, 0, 200, 150);
        dialog.getContentPane().add(label);
        dialog.setVisible(true);
    }

    @Override
    public void mousePressed(MouseEvent e) {
        Object source =e.getSource();
        if(source ==login) {
            login.setIcon(new ImageIcon("image\\login\\登录按下.png"));
        } else if(source ==register){
            register.setIcon(new ImageIcon("image\\login\\注册按下.png"));
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        Object source =e.getSource();
        if(source ==login) {
            login.setIcon(new ImageIcon("image\\login\\登录按钮.png"));
        } else if(source ==register){
            register.setIcon(new ImageIcon("image\\login\\注册按钮.png"));
        }
    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }

    private static class User {
        static String username;
        static String  password;

        public User() {
        }

        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }
}
package com.scarelf.ui;

import javax.swing.*;

public class Registerjframe extends JFrame {

    public Registerjframe() {
        setSize(488, 500);
        //设置界面的标题
        this.setTitle("拼图 注册");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //让界面显示出来,建议写在最后
        setVisible(true);
    }
}
package CodeUtil;

import java.util.ArrayList;
import java.util.Random;

public class CodeUtil {
    public static String getCode(){
        //1.创建一个集合
        ArrayList<Character> list = new ArrayList<>();
        //2,添加字母a - z, A - Z
        for (int i = 0; i < 26; i++) {
            list.add((char) ('a' + i));
            list.add((char) ('A' + i));
        }
        //3.生成四个随机字母
        String result ="";
        Random r = new Random();
        for (int i = 0; i < 4; i++) {
            int index0 = r.nextInt(list.size());
            result += list.get(index0);
        }
        //4.在后面添加数字
        int number = r.nextInt(10);
        result = result + number;
        //5.把字符串变成字符数组
        char[] chars = result.toCharArray();
        //6.打乱顺序
        int index = r.nextInt(chars.length);
        char temp = chars[4];
        chars[4] = chars[index];
        chars[index] = temp;
        //7.把字符数组变回字符串
        String code = new String(chars);
        return code;
    }
}
import com.scarelf.ui.GameJFrame;
import com.scarelf.ui.LoginJFrame;
import com.scarelf.ui.Registerjframe;

public class Main {
    public static void main(String[] args) {

        //new GameJFrame();

        new LoginJFrame();

        //new registerJFrame();
    }
}

打包

之后学习打包exe安装包,因为涉及软件什么的太多知识点,所以直接放原视频了有需要的可以自己查看,在此不再提及

阶段项目-11-游戏打包成exe安装包_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV17F411T7Ao?p=154

  1. 将代码打包成jar包。
  2. 整合资源文件
  3. 将jar包打包成exe
  4. 将jdk、资源文件、jar包转换后的exe三者再次打包成最终的exe。

相关文章:

  • 前端各种for 循环
  • 算法:二维单调队列-P2216 [HAOI2007] 理想的正方形题解
  • 作文笔记16 点面结合
  • Trae AI 使用 APIkey 配置 Anthropic Claude BaseURL , gpt-4o,deepseek等大模型代理指南
  • c#使用forms实现屏幕截图
  • 在MFC中使用Qt(六):深入了解QMfcApp
  • flutter框架中文文档,android智能手机编程答案
  • 第十一章 VGA显示图片(还不会)
  • pod之间访问不通怎么排查?
  • 音视频开发---常用工具
  • JAVASE(十二)常用类(一)Object类
  • 【STM32】GPIO输入(按键)
  • 如何实现高性能的在线 PDF 预览
  • 【新人系列】Golang 入门(十):错误处理详解 - 上
  • 广东新政激发产业活力,凡拓数创以全场景AI3D方案领跑机器人赛道
  • JAVA并发编程高级-线程安全集合-CopyOnWriteArrayList
  • 配置防火墙和SELinux(1)
  • 第二次作业
  • SpringAI 集成本地Ollama大模型
  • 2025年智慧能源与控制工程国际学术会议(SECE 2025)
  • 哔哩哔哩网页版在线观看网址/搜索引擎营销优化策略有哪些
  • 商标设计网站有哪些/市场推广方法
  • 高端建设网站公司/谷歌广告投放教程
  • php网站后台开发/百度平台app下载
  • 网站后台页面是什么/百度竞价代运营
  • 上海整站优化公司/怎么把产品快速宣传并推广