拼图游戏(JAVA)超详细!入股不亏

哎,最近被这个搞的头晕眼花的,烦死了!!!

不多解释了,代码注释很详细(毕竟写了好几天还熬了个大✌夜),不会欢迎私聊(虽然本人JAVA真的拉)

MainJFrame.java//主窗体(package zhangjinyang;大家自己换包名)

package zhangjinyang;

import javax.swing.*;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.filechooser.FileNameExtensionFilter;

public class MainJFrame extends JFrame implements Runnable{
    public static void main(String[]args)
    {
        new  MainJFrame();
    }
    //相当于初始化--------------------
    JMenuBar jmenubar;//菜单栏
    JMenu menu,menuclass,menuhelp;//菜单(菜单、等级、帮助)
    JMenuItem itembegin,itemend,itemchange,itemabout,itemrecord,itemclear;//菜单项(开始、退出、图片更换、关于游戏、游戏记录、清空记录)
    JRadioButtonMenuItem itemeasy,itemnormal,itemhard;//单选菜单项(简单、一般、困难)
    JLabel total_time,total_step;//标签(步数,时间)

    //相当于初始化--------------------
    JPanel jp;//主面板
    LeftJPanel lp;//左面板
    RightJPanel rp;//右面板
    URL url;//定位符,查找图片使用

    //起止时间
    long startTime,endTime;
    //创建线程对象,实现计时功能
    Thread th;

//    Label total_count;
    //设置主窗口样式----------------------------
    public MainJFrame()
    {

        //整体的设置---------------
        setTitle("拼图游戏");
        setSize(1440,780);
        setLocationRelativeTo(null);//null表示固定相对位置在屏幕中间
        setResizable(false);//可调整大小(false不可调整大小)
        setDefaultCloseOperation(EXIT_ON_CLOSE);//运行完之后,点关闭,自动停止程序运行
        setVisible(true);//设置窗口可见

        //添加界面菜单栏---------------
        menuinit();//菜单初始化
        //面板初始化----------------
        init();

        //先创建个运行线程------------------
        th=new Thread(this);

        //开始菜单监视器
        itembegin.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //启动线程
                //如果线程没启动,调用start方法
                if(!th.isAlive()) th.start();
                startTime=System.currentTimeMillis();//当前时间毫秒
                rp.times=0;//步数为0
                rp.randomOrder();//每次都要调动自动打乱命令
            }
        });
        //结束游戏
        itemend.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(1);
            }
        });
        //难易程度
        itemeasy.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                rp.hs=2;//传递2*2到右面板
                rp.ls=2;
                //初始化组件(init就是美小格进行计算和定位)
                rp.init(url);
            }
        });
        itemnormal.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                rp.hs=3;
                rp.ls=3;
                rp.init(url);
            }
        });
        itemhard.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                rp.hs=4;
                rp.ls=4;
                rp.init(url);
            }
        });
        //游戏记录显示
        itemrecord.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //info用来储存要存放的记录
                String info="";
                try {
                    File f=new File("F:\\游戏记录.dat");
                    if(f.exists())
                    {
                        //创建输入流
                        FileReader fr=new FileReader("F:\\游戏记录.dat");
                        //用来读取数据
                        char[] chs=new char[1024];
                        int len;
                        while ((len=fr.read(chs))!=-1)
                        {
                            //读取的结果放在info中
                            // char[]值,
                            //int偏移量,
                            //整数计数
                            info+=new String(chs,0,len);
                        }
                        fr.close();//读完关闭
                        //通过消息框显示结果(作业窗格)
                        JOptionPane.showMessageDialog(null,info);
                    }
                    else{
                        JOptionPane.showMessageDialog(null,"游戏记录为空!");
                    }
//                } catch (FileNotFoundException fileNotFoundException) {
//                    fileNotFoundException.printStackTrace();
                } catch (IOException e1) {
                    e1.printStackTrace();//主要的不是很理解我就知道和rightJPanel里面异常追捕对应,其实我觉得不对应也行
                }
            }
        });
        //关于游戏
        itemabout.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(null,"关于拼图游戏\r\n版本:v2.0\r\n作者:XiaoZhang\r\n欢迎进入游戏!");
            }
        });
        //清空记录
        itemclear.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                File f=new File("F:\\游戏记录.dat");
                if(f.exists())
                    f.delete();
            }
        });
//图片进行更换
        itemchange.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //显示一个打开对话框,选择一个图片文件,将文件转换成url对象,调用左右面板的相应方法
                JFileChooser jfc=new JFileChooser();//文件选择器
                //设置文件筛选器  文件名扩展筛选器
                jfc.setFileFilter(new FileNameExtensionFilter("图片格式(jpg|png|gif|jpeg)", "jpg","png","gif","jpeg"));
                //弹出打开对话框
                int sd=jfc.showOpenDialog(MainJFrame.this);
                if(sd==jfc.APPROVE_OPTION)//如果用户选择了打开按钮
                {
                    //获取用户选择的文件(获取绝对路径)
                    String file=jfc.getSelectedFile().getAbsolutePath();
                    try {
                        url=new URL("file:\\"+file);//获取新图片但是为啥这样表示,等我再研究研究
                        //更新两个面板
                        lp.init(url);
                        rp.init(url);
                    } catch (MalformedURLException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        });
    }
//设置整个窗口-----------------------------------
    public void init() {

        //相当于赋初值-------------------
        jp=new JPanel();
        lp=new LeftJPanel();
        rp=new RightJPanel();
        url=this.getClass().getResource("1000.jpg");
        //分割主面板(网格布局分割为一行两列,一边放lp,一边放rp)
        jp.setLayout(new GridLayout(1,2));
        jp.add(lp);
        jp.add(rp);
        lp.init(url);
        rp.init(url);

        //再将主面板放到主窗体,把拼图拼好挂墙上,一个意思
        this.add(jp);//如果我没猜错this一般代指最高层就是窗口

    }
//设置整个菜单样式----------------------------
    public void menuinit() {

        //相当于赋初值-------------------
        jmenubar = new JMenuBar();
        menu=new JMenu("菜单");
        menuclass=new JMenu("等级");
        menuhelp=new JMenu("帮助");
        itembegin=new JMenuItem("开始游戏");
        itemend=new JMenuItem("结束游戏");
        itemchange=new JMenuItem("更换图片");
        itemabout=new JMenuItem("关于游戏");
        itemrecord=new JMenuItem("游戏记录");
        itemclear=new JMenuItem("清空记录");
        itemeasy=new JRadioButtonMenuItem("简单");
        itemnormal=new JRadioButtonMenuItem("一般");
        itemhard=new JRadioButtonMenuItem("困难");
        total_step=new JLabel("步数:");
        total_time=new JLabel("用时:");

        //设置选项的以下小装饰
        itemeasy.setSelected(true);//最开始默认先择最简单的
        total_time.setForeground(Color.GRAY);//设置标签颜色
        total_step.setForeground(Color.gray);


        //把单选难度进行按钮组,实现一对多-------------
        ButtonGroup group=new ButtonGroup();
        group.add(itemeasy);
        group.add(itemnormal);
        group.add(itemhard);

        //把按钮都添加到菜单的菜单里-------------
        menu.add(itembegin);
        menu.add(itemend);
        menu.add(itemchange);

        //把难度系数添加到菜单的难度等级里面------------
        //这里就会有同学疑惑了,慢慢就把这三个放到一个按钮组里面了
        ///呢直接把按钮组放进来不就可以吗?为什么一个一个加
        //其实Java里面规定的记住就行,嘿嘿
        menuclass.add(itemeasy);
        menuclass.add(itemnormal);
        menuclass.add(itemhard);

        //把记录等事项添加进菜单的帮助按钮-----------
        menuhelp.add(itemabout);
        menuhelp.add(itemrecord);
        menuhelp.add(itemclear);

        //这就相当于把组件都拼好了,然后拼一起一个意思(按顺序拼)
        jmenubar.add(menu);
        jmenubar.add(menuclass);
        jmenubar.add(menuhelp);
        jmenubar.add(new JLabel("                                "));
        jmenubar.add(total_step);
        jmenubar.add(new JLabel("                                "));
        jmenubar.add(total_time);

        //这一步就更好说了,把拼图拼好挂墙上
        this.setJMenuBar(jmenubar);

        th=new Thread(this);
    }

    @Override
    public void run() {//是Runnable的继承
        while(true) {
            endTime=System.currentTimeMillis();//当前时间毫秒
            total_time.setText("用时:"+(endTime-startTime)/1000+"秒");//显示文本

            total_step.setText("步数:第"+rp.times+"步");
            try {
                Thread.sleep(500);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

 RightJPanel.java

package zhangjinyang;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.awt.Image;
import java.io.FileWriter;
import java.util.Random;
import java.io.IOException;//缓冲读取数据
//java.io.IOException

public class RightJPanel extends JPanel implements ActionListener
{
    int width=700;
    int height=700;//面板的大小

    JButton[] jbs;//定义按钮数组

    int hs=2,ls=2;//设置分割的行列数

    int widthbut,heightbut;//按钮的宽度和高度,指定是小图图片缩放的尺寸

    int widthtp,heighttp; //图片原始高度宽度

    int widthxt,heightxt;//小图的原始宽度高度

    int times;//实现步数计算的变量
    JButton kb;//空白按钮
    public RightJPanel()
    {
        setLayout(null);//面板布局为空
        setSize(width,height);//面板的大小
    }
    //设计右面板
    public void init(URL url)
    {
        this.removeAll();//面板组件初始化前,先清除所有已有的组件
        //创建按钮组
        jbs=new JButton[hs*ls];

        //为每一个按钮实现初始化
        //计算按钮的宽度和高度
        widthbut=width/ls;
        heightbut=height/hs;

        BufferedImage buf=null;//缓冲图片区为空
        try {
            buf = ImageIO.read(url);//缓冲读取图片

            //获取原图的宽度、高度
            widthtp=buf.getWidth();
            heighttp=buf.getHeight();
            //获取小图的宽度和高度(分割后的)
            widthxt=widthtp/ls;
            heightxt=heighttp/hs;

            //给每个子图,也就是按钮确定位置
            for(int i=0;i<jbs.length;i++)
            {
                jbs[i]=new JButton();//每个小子图都新建按钮
                jbs[i].setSize(widthbut,heightbut);
                //这点很聪明,因为i相当于线性排序,现在为确定每i个小方格的位置现在是二维的
                //横向取余,纵向取整
                jbs[i].setLocation((i%ls)*widthbut,(i/ls)*heightbut);

                //获取每个小图(获取子映像,现在的图是原图映射到每个小方格的里面)
                BufferedImage subimage=buf.getSubimage(i%ls*widthxt,i/ls*heightxt,widthxt,heightxt);
                //小图的缩放(把刚刚获取的子图片缩小)
                Image image = subimage.getScaledInstance(widthbut, heightbut, 1);
                //将小图图片放置到按钮上
                jbs[i].setIcon(new ImageIcon(image));
                //添加按钮到右面板
                this.add(jbs[i]);
                //设置图片补课被修改(就是刚开始是图片按钮是不显示的需要按开始按钮)
                jbs[i].setEnabled(false);//设置已启用被关闭
                jbs[i].addActionListener((ActionListener) this);
            }
            jbs[hs*ls-1].setIcon(null);
            kb=jbs[hs*ls-1];
        } catch (IOException e) {//IO异常
            e.printStackTrace();
        }
    }


    //打乱按钮顺序
    public void randomOrder()
    {
        Random rand=new Random();//创建随机对象
        //多次打乱-------------
        for(int i=0;i<hs*ls;i++)
        {
            int index1=rand.nextInt(hs*ls);//bound就是范围
            int index2=rand.nextInt(hs*ls);
            int x1=jbs[index1].getX();
            int y1=jbs[index1].getY();
            int x2=jbs[index2].getX();
            int y2=jbs[index2].getY();
            jbs[index1].setLocation(x2,y2);
            jbs[index2].setLocation(x1,y1);
            //本来我还在想为啥为啥要设两个随机数,其实还是不太明白,可能要满足(x1,y1)与(x2,y2)重合
            jbs[i].setEnabled(true);//将图片显现出来
        }
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        //获取用户单击的按钮 ,通过ActionEvent e的方法gerSource获取事件源
        JButton jb=(JButton)(e.getSource());
        //获取单击按钮和空白按钮的位置
        int x1=jb.getX();
        int y1=jb.getY();
        int x2=kb.getX();
        int y2=kb.getY();

        //判断是否可以被移动
        //Math.abs(x1-x2)/widthbut+Math.abs(y1-y2)==1
        //给大家说一下我的理解,如果没记错Math.abs是取绝对值
        //当两个按钮相邻要么同一行要么同一列,而且是相邻所以要么行号差一,要么列号差一
        if(Math.abs(x1-x2)/widthbut+Math.abs(y1-y2)/heightbut==1)
        {
            jb.setLocation(x2,y2);
            kb.setLocation(x1,y1);//换换位置
            times++;//步数加一
        }
        //每走一步就要判断拼图是否拼成功-------------
        //成功之后怎么做
        if(isWin()){
            JOptionPane.showMessageDialog(null, "恭喜你,拼图成功");//判断父组件,这个我也不是很懂说什么帧啥的

            //停止按键的使用
            for(int i=0;i<jbs.length;i++){
                jbs[i].setEnabled(false);
            }

            //记录信息
            String name = JOptionPane.showInputDialog("请输入你的姓名:");
            //小tips”\t“是回车符,”\n“是换行
            String info=hs+"*"+ls+"拼图记录:"+name+"的步数"+times+"\r\n";
            JOptionPane.showMessageDialog(null,info);
            try
            {
                FileWriter fw=new FileWriter("F:\\游戏记录.dat",true);
                fw.write(info);//把每次记录都记录下来
                fw.close();
            }
            catch (IOException e1)
            {
                e1.printStackTrace();
            }
        }
    }

    public boolean isWin() {
       //获取每个按钮的坐标
        for(int i=0;i<jbs.length;i++){
            //jbs[i].setLocation((i%ls)*widthbut, i/ls*heightbut);由之前坐标设置给出下面的x,y
            int x=jbs[i].getX()/widthbut;
            int y=jbs[i].getY()/heightbut;
            if(i%ls!=x||i/ls!=y)
                return false;
        }
        return true;
    }
}

 LeftJPanel.java

package zhangjinyang;
import java.net.URL;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
//左面板类
public class LeftJPanel extends JPanel{
    JLabel jl;//左面板
    int width=700;
    int height=700;

    //相当于左窗口的设置-------------------
    public LeftJPanel()
    {
        setSize(width,height);
        jl=new JLabel();
        jl.setSize(width,height);//窗口和面板也可以设不一样的

        //把面板放左窗口里面---------
        this.add(jl);
    }
    public void init(URL url)
    {
        ImageIcon icon=new ImageIcon(url);//图像图标初始化
        //没猜错的话因该是把图片缩放到窗口大小
        jl.setIcon(new ImageIcon(icon.getImage().getScaledInstance(width,height,1)));
        //刷新界面(验证所有的东西都放入了)
        validate();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值