• Java实现拼图小游戏


    1、了解拼图游戏基本功能:

    拼图游戏内容由若干小图像块组成的,通过鼠标点击图像块上下左右移动,完成图像的拼凑。

    2、拼图游戏交互界面设计与开发:

    通过创建窗体类、菜单、中间面板和左右面板完成设计拼图的交互界面 ,实现拼图游戏的基本功能。

    3、图片的加载与分割:

    使用Image类实现图片的缩放,ImageIO类实现图片的读写加载,通过接口类Icon,BufferedImage类获取BufferedImage类的对象实现图片分割。

    4、图片随机打乱和交换:

    产生随机数 Random rand=new Random();

               rand.nextInt(hs*ls)------[0,8]

    具体操作:生成两个随机数表示数组下标,互换两个数组元素的位置,按钮的方法getX和getY可以获取按钮的坐标,利用按钮的单击事件的处理ActionListener可以使其图片交换。

    5、判赢:

    当用户移动按钮后进行判断,代码写在监听器的actionPerformed方法中,判断拼图是否成功,主要取决于每一个按钮通过索引下标获取的位置值,与当前按钮的位置值是否相同。

    6、计时和计数功能的实现:

    计时功能的实现主要是线程的设计,线程的定义方法:第一:继承Thread类,第二:实现Runnable接口,创建带实现接口的子类对象的Thread对象,MainJFrame实现Runnable接口,重写run方法;而计数则在主窗体中通过rp.times实现对变量的使用来计数。

    7、游戏记录的保存:

    当用户拼图成功后,记录当前信息到文件中,FileWriter追加写信息,FileReader完成读取数据。
    import java.awt.Image;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import java.io.FileInputStream;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.net.URL;
    import java.util.Random;
     
    import javax.imageio.ImageIO;
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
     
    import jdk.jfr.events.FileWriteEvent;
    //右面板实现ActionListener接口,右面板也就成为了监听器
    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);
                //init();
     
        }
        //创建按钮,并放置到右面板
        public void init(URL url) {
            //面板组件初始化前,先清除所有已有的组件
            this.removeAll();
            //创建按钮数组
            jbs=new JButton[hs*ls];
            //为每一个按钮实现初始化
            //计算按钮的宽度和高度
            //面板是700*700,拆分成3*3的9个区域
            //每一块区域的宽度  700/3
            //每一块区域的高度 700/3
            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[i]=new JButton();
                jbs[i].setSize(widthbut,heightbut);
                //jbs[i].setText(i+"");
                //添加按钮前要确定坐标位置
                //横坐标 i=0   0    i=1   233    i=2   466
                //i=3   0   i=4  233
                //纵坐标 i=3
                jbs[i].setLocation((i%ls)*widthbut, i/ls*heightbut);
                //jbs[i].setIcon(null);
                //小图的获取
                 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));
                //添加按钮到右面板
                add(jbs[i]);
                //设置按钮不可用
                jbs[i].setEnabled(false);
                //设置按钮的监听,当按钮被单击,会到右面板中找actionPerformed方法执行
                jbs[i].addActionListener(this);
            }
            jbs[hs*ls-1].setIcon(null);
            kb=jbs[hs*ls-1];
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
     
     
        }
     
        //打乱按钮在面板中显示的顺序
        public void randomOrder(){
            //创建随机数对象
            Random rand=new Random();
            //打乱多次
            for(int i=0;i         //随机索引
            int index1=rand.nextInt(hs*ls);
            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);
            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)/heightbut==1
            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[i].setEnabled(false);
                }
                //提示用户输入名称
                //使用输入对话框
                String name = JOptionPane.showInputDialog("请输入你的姓名:");
                String info = hs+"*"+ls+"拼图记录:"+name+"的步数是:"+times+"\r\n";
                JOptionPane.showMessageDialog(null, hs+"*"+ls+"拼图记录:"+name+"的步数是:"+times+"\r\n");
                try {
                    FileWriter fw = new FileWriter("D:\\游戏记录.dat",true);
                    fw.write(info);
                    fw.close();
                }catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
     
        }
     
        //判断是否拼图成功
        public boolean isWin() {
            
            //获取每一个按钮的坐标
            for(int i=0;i             //jbs[i].setLocation((i%ls)*widthbut, i/ls*heightbut);由之前坐标设置给出下面的x,y
                int x=jbs[i].getX()/widthbut;
                int y=jbs[i].getY()/heightbut;
                //判断,通过下标值,也可以获取按钮的坐标   横坐标  i%ls    纵坐标 i/ls
                if (i%ls!=x || i/ls!=y  ){
                    return false;
                }
            }
            return true;
        }
    }

     右面版

    import java.awt.Image;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import java.io.FileInputStream;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.net.URL;
    import java.util.Random;
     
    import javax.imageio.ImageIO;
    import javax.swing.ImageIcon;
    import javax.swing.JButton;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
     
    import jdk.jfr.events.FileWriteEvent;
    //右面板实现ActionListener接口,右面板也就成为了监听器
    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);
                //init();
     
        }
        //创建按钮,并放置到右面板
        public void init(URL url) {
            //面板组件初始化前,先清除所有已有的组件
            this.removeAll();
            //创建按钮数组
            jbs=new JButton[hs*ls];
            //为每一个按钮实现初始化
            //计算按钮的宽度和高度
            //面板是700*700,拆分成3*3的9个区域
            //每一块区域的宽度  700/3
            //每一块区域的高度 700/3
            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[i]=new JButton();
                jbs[i].setSize(widthbut,heightbut);
                //jbs[i].setText(i+"");
                //添加按钮前要确定坐标位置
                //横坐标 i=0   0    i=1   233    i=2   466
                //i=3   0   i=4  233
                //纵坐标 i=3
                jbs[i].setLocation((i%ls)*widthbut, i/ls*heightbut);
                //jbs[i].setIcon(null);
                //小图的获取
                 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));
                //添加按钮到右面板
                add(jbs[i]);
                //设置按钮不可用
                jbs[i].setEnabled(false);
                //设置按钮的监听,当按钮被单击,会到右面板中找actionPerformed方法执行
                jbs[i].addActionListener(this);
            }
            jbs[hs*ls-1].setIcon(null);
            kb=jbs[hs*ls-1];
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
     
     
        }
     
        //打乱按钮在面板中显示的顺序
        public void randomOrder(){
            //创建随机数对象
            Random rand=new Random();
            //打乱多次
            for(int i=0;i         //随机索引
            int index1=rand.nextInt(hs*ls);
            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);
            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)/heightbut==1
            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[i].setEnabled(false);
                }
                //提示用户输入名称
                //使用输入对话框
                String name = JOptionPane.showInputDialog("请输入你的姓名:");
                String info = hs+"*"+ls+"拼图记录:"+name+"的步数是:"+times+"\r\n";
                JOptionPane.showMessageDialog(null, hs+"*"+ls+"拼图记录:"+name+"的步数是:"+times+"\r\n");
                try {
                    FileWriter fw = new FileWriter("D:\\游戏记录.dat",true);
                    fw.write(info);
                    fw.close();
                }catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
     
        }
     
        //判断是否拼图成功
        public boolean isWin() {
            
            //获取每一个按钮的坐标
            for(int i=0;i             //jbs[i].setLocation((i%ls)*widthbut, i/ls*heightbut);由之前坐标设置给出下面的x,y
                int x=jbs[i].getX()/widthbut;
                int y=jbs[i].getY()/heightbut;
                //判断,通过下标值,也可以获取按钮的坐标   横坐标  i%ls    纵坐标 i/ls
                if (i%ls!=x || i/ls!=y  ){
                    return false;
                }
            }
            return true;
        }
    }

    游戏功能 

    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.ButtonGroup;
    import javax.swing.JFileChooser;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JMenu;
    import javax.swing.JMenuBar;
    import javax.swing.JMenuItem;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JRadioButtonMenuItem;
    import javax.swing.filechooser.FileNameExtensionFilter;
     
    public class MainJFrame extends JFrame implements Runnable{
     
        //菜单
        //菜单栏
        JMenuBar jmenubar;
        //菜单  菜单、等级、帮助
        JMenu menu,menuclass,menuhelp;
        //菜单项  开始、退出、图片更换、关于游戏、游戏记录、清空记录
        JMenuItem itembegin,itemend,itemchange,itemabout,itemrecord,itemclear;
        //单选菜单项  简单、一般、困难
        JRadioButtonMenuItem itemeasy,itemnormal,itemhard;
        //中间面板
        JPanel jp;
        //左面板
        LeftJPanel lp;
        //右面板
        RightJPanel rp;
        //访问的图片
        URL url;
        //显示计时标签
        JLabel total_time;
        //起止时间
        long startTime,endTime;
        //创建线程对象,实现计时功能
        Thread th;
        //显示步数的标签
        JLabel total_count;
        //构造方法
        public MainJFrame(){
            //标题设置
            setTitle("拼图游戏");
            //窗体大小
            setSize(1440, 780);
            //窗体位置在容器/屏幕的正中间
            setLocationRelativeTo(null);
            //窗体大小不可变
            setResizable(false);
            //实现界面菜单初始化
            //创建一个线程对象
            th=new Thread(this);
            //界面菜单初始化
            menuinit();
            //各面板的初始化
            init();
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setVisible(true);
            //开始菜单
            itembegin.addActionListener(new ActionListener() {
     
                @Override
                public void actionPerformed(ActionEvent e) {
                    //启动线程
                    //如果线程没有启动,则调用start方法启动
                    if(!th.isAlive()) th.start();
                    startTime=System.currentTimeMillis();
                    rp.times=0;
                    rp.randomOrder();
                }
            });
            //结束游戏
            itemend.addActionListener(new ActionListener() {
     
                @Override
                public void actionPerformed(ActionEvent e) {
                    System.exit(1);
                }
            });
            //选择难易度itemeasy,itemnormal,itemhard
            itemeasy.addActionListener(new ActionListener() {
     
                @Override
                public void actionPerformed(ActionEvent e) {
                    //第一,传递2*2到右面板
                    rp.hs=2;
                    rp.ls=2;
                    //第二,调用右面板组件初始化的方法
                    rp.init(url);
                }
            });
            itemnormal.addActionListener(new ActionListener() {
     
                @Override
                public void actionPerformed(ActionEvent e) {
                    //第一,传递3*3到右面板
                    rp.hs=3;
                    rp.ls=3;
                    //第二,调用右面板组件初始化的方法
                    rp.init(url);
                }
            });
            itemhard.addActionListener(new ActionListener() {
     
                @Override
                public void actionPerformed(ActionEvent e) {
                    //第一,传递4*4到右面板
                    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("D:\\游戏记录.dat");
                        if(f.exists()) {
                        //创建指向***的文件字符输入流对象
                        FileReader fr = new FileReader("D:\\游戏记录.dat");
                        //读取数据
                        char[] chs = new char[1024];
                        int len;
                        while((len=fr.read(chs))!=-1) {
                            //读取的结果放在info中
                            info+=new String(chs,0,len);
                        }
                        
                        fr.close();
                        //通过消息框显示结果
                        JOptionPane.showMessageDialog(null, info);
                        }else {
                            JOptionPane.showMessageDialog(null, "游戏记录为空!");
                        }
                    }catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            });
            //关于游戏
            itemabout.addActionListener(new ActionListener() {
                
                @Override
                public void actionPerformed(ActionEvent e) {
                    JOptionPane.showMessageDialog(null, "关于拼图游戏\r\n版本:v2.0\r\n作者:LWL\r\n欢迎进入游戏!");
                }
            });
            //清空记录
            itemclear.addActionListener(new ActionListener() {
     
                @Override
                public void actionPerformed(ActionEvent e) {
                    File f = new File("D:\\游戏记录.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) {
                            // TODO Auto-generated catch block
                            e1.printStackTrace();
                        }
                    }
                }
            });
        }
     
        public void init() {
            jp=new JPanel();
            //设置中间面板的布局方式
            jp.setLayout(new GridLayout(1,2));
            //提供左右面板的图片
             url=this.getClass().getResource("小狗.jpg");
            //创建左面板
            lp=new LeftJPanel();
            //对标签初始化
            lp.init(url);
            //将左面板添加到中间面板
            jp.add(lp);
            //创建右面板
            rp=new RightJPanel();
            //右面板的按钮初始化
            rp.init(url);
            //将右面板添加到中间面板
            jp.add(rp);
            //将中间面板添加到窗体
            add(jp);
        }
     
        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("困难");
            //为单选菜单分组,实现多选一
            ButtonGroup bg=new ButtonGroup();
            bg.add(itemeasy);
            bg.add(itemnormal);
            bg.add(itemhard);
            //添加菜单
            menu.add(itembegin);
            menu.add(itemend);
            menu.add(itemchange);
     
            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);
     
            //菜单栏添加到窗体
            this.setJMenuBar(jmenubar);
            itemeasy.setSelected(true);
            //创建一个线程对象
            th=new Thread(this);
            total_time=new JLabel("用时:");
            total_time.setForeground(Color.red);
            jmenubar.add(new JLabel("                    "));
            jmenubar.add(total_time);
            total_count=new JLabel("步数:");
            total_count.setForeground(Color.red);
            jmenubar.add(new JLabel("                    "));
            jmenubar.add(total_count);
        }
     
        public static void main(String[] args) {
            new MainJFrame();
        }
        //实现计时并定时显示的run()方法
        @Override
        public void run() {
            while(true) {
                endTime=System.currentTimeMillis();
                total_time.setText("用时:"+(endTime-startTime)/1000+"秒");
                total_count.setText("步数:第"+rp.times+"步");
                try {
                    Thread.sleep(500);
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

  • 相关阅读:
    网站优化搜索引擎与关键词
    matlab入门基础笔记
    python常用代码总结2
    浅学JAVA泛型一:泛型的基础知识
    SpringCloud源码分析 (Eureka-Server-入口分析和处理Client状态请求) (五)
    3D视觉——2.人体姿态估计(Pose Estimation)入门——OpenPose含安装、编译、使用(单帧、实时视频)
    805. 数组的均值分割 : 折半搜索 + 二进制枚举运用题
    电脑重装系统后DirectX12旗舰版禁用了怎么解决?
    Kotlin VS Java区别较量?看了对比我更喜欢Kotlin
    统一异常的处理方法
  • 原文地址:https://blog.csdn.net/bokoxin/article/details/134517116