天天看點

拼圖小遊戲拼圖小遊戲

拼圖小遊戲

采用主技術

GUI Java多線程  IO流
           

效果展示:

啟動界面:

拼圖小遊戲拼圖小遊戲

主界面:(遊戲界面内容功能見名知意)

拼圖小遊戲拼圖小遊戲

閱前須知

源碼分為兩部分
1、圖檔image
2、代碼實作
在導入之前需要修改IO檔案路徑
如需修改拼圖照片内容,需要将主圖像素大小調至450 x 600
然後拆分為6行5列作為拼圖區
注意圖檔命名格式一定要一緻
附上一個拆分圖檔網站:https://www.qtool.net/piccutting
創作不易,如果能幫到您,請點贊支援,感謝!
           

源碼部分

ResourceUtil

package jinhuan.pink;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class ResourceUtil {
    public static BufferedImage getImage(String imageName){
        BufferedImage bufferedImage = null;
        try {
//            這裡的路徑需要修改為自己的檔案路徑
            bufferedImage = ImageIO.read(new File("Xingle\\src\\image\\"+imageName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return  bufferedImage;
    }
}
           

MyTime

package jinhuan.pink;

/**
 * 自定義計時器
 * 實作時間的遞增
 * */
public class MyTime implements Runnable {
    static String myTime;
    static int  myMinute = 0;
    static int  mySecond = 0;
    static int  myHour = 0;
    @Override
    public void run() {
        while (true){
            try {
                Thread.currentThread().sleep(1000);
                mySecond++;
                if(mySecond >= 60){
                    mySecond = 0;
                    myMinute++;
                }
                if(myMinute >= 60){
                    myMinute++;
                }
                if(myHour >= 24){
                    myMinute++;
                }
                myTime = myHour+":"+myMinute+":"+mySecond;
                MainJFrame.buttonAreaJPanel.yourtime.setText("時間:"+myTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}
           

GameStart

package jinhuan.pink;
//主啟動類

public class GameStart {
    public static void main(String[] args) {
        new BeginJFrame();
    }
}
           

BeginJFrame

package jinhuan.pink;

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

/**
 * 遊戲的開始界面
 * */
public class BeginJFrame extends JFrame {
    private BeginJFrame beginJFrame = this;

   private BufferedImage titleIcon = ResourceUtil.getImage("icon.png");
   private BufferedImage startBu = ResourceUtil.getImage("startBu.png");
   private JButton start = new JButton(new ImageIcon(startBu));
   private Container contentPane = getContentPane();

    /**
     * 定義主視窗的元件
     */
    private JLabel title = new JLabel("拼圖小遊戲",JLabel.CENTER );
    private JLabel hhh = new JLabel("開始遊戲",JLabel.CENTER );

    /**
     * 定義主窗體的子面闆
     * */
    private JPanel mainJpanel = new JPanel(null);

    //    擷取本窗體的自帶面闆并将其屬化
    public BeginJFrame(){
        addComponent();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setResizable(false);
        setTitle("拼圖小遊戲");
        setSize(600,300);
        setIconImage(titleIcon);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    public void addComponent(){
        contentPane.setBackground(Color.getHSBColor(12,12,12));
        title.setFont(new Font("宋體",Font.BOLD,60));
        contentPane.add(title,BorderLayout.NORTH);

        /**
         * 給兩個按鈕設定屬性并添加監聽事件
         * */
        start.setBounds(200,100,200,76);
        hhh.setFont(new Font("幼圓",Font.BOLD,20));
        start.setFocusPainted(false);
        start.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new MainJFrame();
                beginJFrame.dispose();
            }
        });

        hhh.setBounds(200,50,200,76);
        mainJpanel.add(hhh);
        mainJpanel.add(start);
        mainJpanel.setBackground(Color.WHITE);
        contentPane.add(mainJpanel,BorderLayout.CENTER);
    }
}
           

MainJFrame

package jinhuan.pink;

import java.awt.*;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;

public class MainJFrame extends JFrame {
    /**
     * 建立整個面闆的屬性變量
     *     窗體的圖示:
     *          iconImage-->建立工具類,利用IO進行批量的讀入
     *      兩個子面闆:
     *          buttonAreaJPanel-->代表按鈕面闆
     *          imageAreaJPanel-->代表下部圖檔區域
     *
     * */
    BufferedImage iconImage = ResourceUtil.getImage("icon.png");// 代表整個遊戲的圖示
    static ButtonAreaJPanel buttonAreaJPanel = new ButtonAreaJPanel();//按鈕區域對象
    static ImageAreaJPanel imageAreaJPanel = new ImageAreaJPanel();// 建立圖檔區域對象

    /**
     * 提供無參的構造方法:
     *          添加事件監聽
     *          設定視窗屬性(可見設定在最後)
     * */
    public MainJFrame(){
        //調用監聽的方法
        this.setIconImage(iconImage);
        this.setTitle("拼圖小遊戲");
        this.setSize(1200, 720);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationRelativeTo(null);// 設定窗體居中
        this.setResizable(false);// 設定窗體的大小不可以改變
        this.add(buttonAreaJPanel, BorderLayout.NORTH);
        this.add(imageAreaJPanel, BorderLayout.CENTER);
        this.setVisible(true);
    }
}

           

ButtonAreaJPanel

package jinhuan.pink;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.TitledBorder;

public class ButtonAreaJPanel extends JPanel{

    /**
     * 為目前面闆添加兩個子面闆:
     *       1、左面闆--leftJPanel
     *       2、右面闆--rightJPanel
     * */

    JPanel leftJPanel = new JPanel();
    JPanel rightJPanel = new JPanel();
    
    /**
     * 構造方法來初始化面闆
     *      1、設定此面闆的屬性
     *      2、将左邊的面闆和右邊的面闆添加到按鈕區域面闆中
     * */
    public  ButtonAreaJPanel() {
        this.setLayout(new GridLayout(1, 2));
        addLeftJPanel();
        addRightJPanel();
    }
    /**
     * 1、設定左邊面闆的屬性
     * 2、定義左邊面闆的元件:
     *      a、imageName代表左邊的圖檔名稱
     *      b、step代表計步區域
     * */
    static JTextField imageName;
    static JTextField step;
    static JTextField yourtime;
    public void addLeftJPanel() {
        leftJPanel.setBorder(new TitledBorder("遊戲資料區"));
        leftJPanel.setLayout(new GridLayout(1,2));
        /**
         * 圖檔顯示的文本框
         * */
        imageName = new JTextField("圖檔名稱:"+pictures[0]);
        imageName.setBackground(Color.CYAN);
        imageName.setEditable(false);
        /**
         * 步數的文本顯示框
         * */
        step = new JTextField("步數:"+0);// 
        step.setBackground(Color.magenta);
        step.setEditable(false);
        /**
         * yourtime
         * */
        yourtime = new JTextField("花費時間:"+0);//
        yourtime.setBackground(Color.PINK);
        yourtime.setEditable(false);

//        添加至左面闆
        leftJPanel.add(imageName,BorderLayout.WEST);
        leftJPanel.add(yourtime,BorderLayout.CENTER);
        leftJPanel.add(step, BorderLayout.EAST);
//        将leftJPanel添加到ButtonAreaJPanel
        this.add(leftJPanel, BorderLayout.WEST);
    }

    /**
     * 定義右邊面闆的元件:
     *      1、單選按鈕:——>分組
     *              a、showNumber代表顯示序号
     *              b、hideNumber代表隐藏序号-->預設被選中
     *      2、下拉清單——>來選擇圖檔
     *      3、開始按鈕
     * */
    static String[] pictures = {"波妞和宗介_1","波妞和宗介_2","宗介"};//作為下拉清單的選項
    static String[] models = {"簡單","中等","困難"};
    static JRadioButton showNum;
    static JRadioButton hideNum;
    static JComboBox<String> changePic;
    static JComboBox<String> changeMod;
    static JButton start;
    static int modIndex;
    static int indexBegin;
    static long beginTime;

    MyTime myTime = new MyTime();
    Thread thread = new Thread(myTime);

    public void addRightJPanel() {
        rightJPanel.setBorder(new TitledBorder("功能區"));//設定 面闆的邊框的标題
        /**
         * 完成 兩個單選框的初始化
         * */
        showNum = new JRadioButton("顯示序号",false);
        showNum.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                ImageAreaJPanel.myPuzzle.showNum();
            }
        });
        
        hideNum = new JRadioButton("隐藏序号",true);
        hideNum.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ImageAreaJPanel.myPuzzle.hideNum();
            }
        });
//        将兩個按鈕綁定為一組
        ButtonGroup buttonGroup = new ButtonGroup();
        buttonGroup.add(showNum);
        buttonGroup.add(hideNum);

//        添加到右邊的面闆上
        rightJPanel.add(showNum);
        rightJPanel.add(hideNum);


//       對下拉清單進行設定
        changePic = new JComboBox<String>(pictures);//将圖檔名稱的數組進行傳入
        changeMod = new JComboBox<String>(models);//設定難度

        changePic.addItemListener(new ItemListener(){
            @Override
            public void itemStateChanged(ItemEvent e) {
                if(e.getStateChange() == ItemEvent.SELECTED) {
                    hideNum.setSelected(false);// 切換圖檔預設不顯示序号
                    int index = changePic.getSelectedIndex();//擷取選中的圖檔的索引 index  第一個選項 0
                    PreviewAreaJPanel.picId = index + 1;// 通過擷取的索引 确定圖檔的id ----> 修改圖檔的id
                    ImageAreaJPanel.myPreview.repaint(); //重新繪制
                    imageName.setText("圖檔名稱:"+changePic.getSelectedItem());//設定功能區顯示的圖檔名稱
                    PreviewAreaJPanel.stepCount = 0;//當遊戲切換圖檔之後,步數清空,重新指派為0
                    //将總共用了多少步數  指派給文本框
                    step.setText("目前步數:"+PreviewAreaJPanel.stepCount);
                    MainJFrame.buttonAreaJPanel.yourtime.setText("時間:"+MyTime.myTime);
//                    thread.interrupt();
                    ImageAreaJPanel.myPuzzle.reload();
                }
            }
        });
        changeMod.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                modIndex = changeMod.getSelectedIndex();
            }
        });
        changePic.setBackground(Color.WHITE);
        changeMod.setBackground(Color.WHITE);
        //将下拉清單添加到右邊的面闆上
        rightJPanel.add(new JLabel("選擇圖檔:"));
        rightJPanel.add(changePic);
        rightJPanel.add(new JLabel("選擇難度:"));
        rightJPanel.add(changeMod);
        /**
         * 完成開始按鈕的初始化
         *  并給開始按鈕添加監聽事件
         *  */

        start = new JButton("開始遊戲");
        start.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                beginTime = System.currentTimeMillis();
                PreviewAreaJPanel.stepCount = 0;
                PreviewAreaJPanel.wasteTime = "";
                MainJFrame.buttonAreaJPanel.step.setText("步數:"+PreviewAreaJPanel.stepCount);
                myTime.mySecond = 0;
                myTime.myMinute = 0;
                myTime.myHour = 0;
                if(indexBegin == 0){
                    thread.start();
                }
                indexBegin++;
                ImageAreaJPanel.myPuzzle.upset();
            }
        });
        start.setFocusPainted(false);//去除擷取焦點時的邊框線
//        将開始按鈕添加到右邊的面闆中
        rightJPanel.add(start);
//        将整個右邊的面闆添加到按鈕區
        this.add(rightJPanel, BorderLayout.EAST);
    }

}
           

ImageAreaJPanel

package jinhuan.pink;

import java.awt.BorderLayout;
import java.awt.GridLayout;

import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

public class ImageAreaJPanel extends JPanel{
    /**
     * 下面闆的兩個子面闆
     *          一個是原圖區
     *          一個是拼圖區
     * */
    static PreviewAreaJPanel myPreview = new PreviewAreaJPanel();
    static PuzzleAreaJPanel myPuzzle = new PuzzleAreaJPanel();

    /**
     * 構造方法完成圖檔區域的初始化
     * */
    public  ImageAreaJPanel() {
        this.setLayout(new GridLayout(1, 2));
        myPreview.setBorder(new TitledBorder("圖檔預覽區"));
        myPuzzle.setBorder(new TitledBorder("拼圖區"));
        this.add(myPreview, BorderLayout.WEST);
        this.add(myPuzzle, BorderLayout.EAST);
    }
}
           

PreviewAreaJPanel

package jinhuan.pink;
//圖檔預覽區

import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

public class PreviewAreaJPanel extends JPanel{
    //定義兩個變量
    //圖檔的數字 ----> static 修飾的成員 可以直接通過類名.通路    靜态變量:類變量 随着類的加載而 初始化的   存在于 方法區的靜态區
    static int picId = 1;
    //總共用了多少步
    static int stepCount = 0;

    static String wasteTime = "";

    //預覽區的圖檔
    BufferedImage previewImage ;

    //繪制圖檔
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        previewImage = ResourceUtil.getImage(picId + ".jpg");
        g.drawImage(previewImage, 70, 20, 450, 600, null);
    }
}
           

PuzzleAreaJPanel

package jinhuan.pink;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;


public class PuzzleAreaJPanel extends JPanel implements MouseListener {
    static class PictureButton extends JButton {
        // 構造方法完成按鈕的初始化
        public PictureButton(Icon icon) {
            super(icon);
            this.setSize(90, 100);
            this.setHorizontalTextPosition(CENTER);
            this.setVerticalTextPosition(CENTER);
        }
        /**
         * 定義小方格按鈕的運動的方法
         * */
        public void movePictureButton(String dir) {
            switch (dir) {
                case "RIGHT":
                    this.setLocation(this.getBounds().x + 90, this.getBounds().y);
                    break;
                case "LEFT":
                    this.setLocation(this.getBounds().x - 90, this.getBounds().y);
                    break;
                case "UP":
                    this.setLocation(this.getBounds().x, this.getBounds().y - 100);
                    break;
                case "DOWN":
                    this.setLocation(this.getBounds().x , this.getBounds().y + 100);
                    break;
            }
        }
    }

    /**
     * 設定拼圖區域
     *      1、設定29個按鈕
     *         a、圖檔來添加到按鈕上
     *         b、for循環建立按鈕(記得減去一個按鈕)
     *      2、一個為空白按鈕
     * */
    static PictureButton[] picButtons;
    static Rectangle rectangle;
    static BufferedImage showImage;

    /**
     * 構造方法完成屬性的初始化
     * */
    public PuzzleAreaJPanel() {
        picButtons = new PictureButton[6 * 5];
        this.setLayout(null);
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 5; j++) {
                showImage = ResourceUtil.getImage(PreviewAreaJPanel.picId + "_" + (5 * i + j + 1) + ".jpg");
                picButtons[5 * i + j] = new PictureButton(new ImageIcon(showImage));
                picButtons[5 * i + j].setLocation(70 + j * 90, 20 + i * 100);
                this.add(picButtons[5 * i + j]);
            }
        }
//        删除最後一個小方格
        this.remove(picButtons[picButtons.length - 1]);
//        設定最後的空白格的坐标來将其初始化
        rectangle = new Rectangle(70 + 360, 20 + 500, 90, 100);
    }


    /**
     * 顯示序号的方法
     * */
    public void showNum() {
        // 循環為每個按鈕添加文本
        for (int i = 0; i < picButtons.length - 1; i++) {
            picButtons[i].setText("" + (i + 1));
        }
    }

    /**
     * 隐藏序号的方法
     * */
    public void hideNum() {
        // 循環為每個按鈕添加文本
        for (int i = 0; i < picButtons.length - 1; i++) {
            picButtons[i].setText("");
        }
    }
    /**
     * 完成拼圖區的圖檔重新加載
     *              擷取目前picId  重新設定
     * */
    public void reload() {
        for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 5; j++) {
                showImage = ResourceUtil.getImage(PreviewAreaJPanel.picId + "_" + (i * 5 + j + 1) + ".jpg");
                // 重新設定小方格的圖檔
                picButtons[i * 5 + j].setIcon(new ImageIcon(showImage));
                picButtons[5 * i + j].setLocation(70 + j * 90, 20 + i * 100);
                // 小方格的文本内容 清空
                picButtons[i * 5 + j].setText("");
            }
        }
    }
    /**
     * 完成 空白格 和 小方格 進行位置的交換
     *              a b 空白格的坐标位置
     * */
    public void movePictureButton(int rx, int ry, String dir) {
        for (int i = 0; i < picButtons.length - 1; i++) {
            if (picButtons[i].getBounds().x == rx && picButtons[i].getBounds().y == ry) {
                picButtons[i].movePictureButton(dir);
                rectangle.setLocation(rx, ry);
                break;
            }
        }
    }

    /**
     * 完成圖示的打亂
     * */
    boolean isListener = false;

    public void upset() {// 打亂小方格
        // 判斷目前的小方格有沒有被監聽
        if (!isListener) {
            // 為每一個小方格添加監聽
            for (int i = 0; i < picButtons.length - 1; i++) {
                picButtons[i].addMouseListener(this);
            }
            isListener = true;
        }

            //以第一個小方格的位置來判定,隻要第一個小方格的位置沒有發生改變就一直打亂小方格的位置
//        for(int i=0;i<MainJFrame.buttonAreaJPanel.modIndex;i++) {
        while (picButtons[0].getBounds().x <= 70 + MainJFrame.buttonAreaJPanel.modIndex * 90 || picButtons[0].getBounds().y <= 20 + MainJFrame.buttonAreaJPanel.modIndex * 100 ) {
            //擷取空白格的坐标
            int rx = rectangle.getBounds().x;
                    int ry = rectangle.getBounds().y;
                    //定義一個 0 - 3 之間的随機整數,用來表示空白格上下左右移動的方向
                    int random = (int) (Math.random() * 4);
                    switch (random) {
                        case 0:
                    //當随機數為0 的時候 空白格水準向左移動一格
                    rx -= 90;
                    //和空白個重合的小方格向右水準移動一格
                    movePictureButton(rx,ry,"RIGHT");
                    break;
                case 1:
                    //随機數為1時,空白格水準向右移動一格
                    rx += 90;
                    //和空白格重合的小方格向左水準移動一格
                    movePictureButton(rx,ry,"LEFT");
                    break;
                case 2:
                    //随機數為2的時候 空白格垂直向下移動一格
                    ry += 100;
                    //和空白格重合的小方格垂直向上移動一格
                    movePictureButton(rx,ry,"UP");
                    break;
                case 3:
                    //當随機數為3時,空白格垂直向下移動一格
                    ry -= 100;
                    movePictureButton(rx,ry,"DOWN");
                    break;
            }
        }
    }

    public void moveSwitch(int random,int rx,int ry) {
        switch (random) {
            case 0://随機數為0 --> 空白格 向左移動一格
                //改變空白格的坐标
                rx -= 90;
                //和空白格重合的小方格進行向右移動一格
                movePictureButton(rx, ry, "RIGHT");
                break;
            case 1: // ---> 空白格向右移動一格
                //改變空格格的坐标
                rx+=90;
                //和空白格重合的小方格進行向左移動一格
                movePictureButton(rx, ry, "LEFT");
                break;
            case 2:// ---> 向下
                //改變空格格的坐标
                ry+=100;
                //和空白格重合的小方格進行向上移動一格
                movePictureButton(rx, ry, "UP");
                break;
            case 3://向上
                //改變空格格的坐标
                ry-=100;
                //和空白格重合的小方格進行向左移動一格
                movePictureButton(rx, ry, "DOWN");
                break;
        }
    }
    @Override
    public void mouseClicked(MouseEvent e) {
        // TODO Auto-generated method stub

    }
    @Override
    public void mousePressed(MouseEvent e) {
        //當滑鼠按下時候 發生一些操作

        // 1 擷取被點選的對象  ---> 小方格
        PictureButton p = (PictureButton) e.getSource();
        // 2 擷取目前被點選的小方格的 坐标
        int px = p.getBounds().x;
        int py = p.getBounds().y;

        //3 .擷取目前空方格的坐标
        int rx = rectangle.getBounds().x;
        int ry = rectangle.getBounds().y;

        //4 判斷 目前被點選的小方格 周圍有沒有空白格
        if (px == rx && py - ry == 100) {//上邊有空白格
            //小方格 移動到上邊
            p.movePictureButton("UP");
        }else if (px == rx && py - ry == -100) {//下邊有空白格
            //小方格移動到下邊
            p.movePictureButton("DOWN");
        }else if (py == ry && px - rx == 90) {//左邊有空白格
            //小方格 左移
            p.movePictureButton("LEFT");
        }else if (py == ry && px - rx == -90) {//右邊有空白格
            // 小方格 右邊移動
            p.movePictureButton("RIGHT");
        }else {
            return;
        }

        // 5 當小方格移動之後   空白格跟着移動
        rectangle.setLocation(px, py);// 将空白格的坐标設定為原來小方格的坐标

        // 6 重繪
        this.repaint();

        // 7 當移動了一次  步數進行 + 1
        PreviewAreaJPanel.stepCount++;
        // 8更新 文本框中的步數的内容
        ButtonAreaJPanel.step.setText("步數:"+PreviewAreaJPanel.stepCount);


        // 9 當遊戲完成的時候  彈出一格框框  顯示 用了多少步
        if (win()) {
            //彈出框 顯示資訊
            MainJFrame.buttonAreaJPanel.thread.stop();
            long endTime = System.currentTimeMillis();
            long cha = (endTime - MainJFrame.buttonAreaJPanel.beginTime)/1000;
            JOptionPane.showMessageDialog(this, "勝利! 共用了:"+PreviewAreaJPanel.stepCount+"步,"+ cha+"秒");
            // 複原遊戲  取消 每個小方格的監聽
            for (int i = 0; i < picButtons.length-1; i++) {
                picButtons[i].removeMouseListener(this);
            }
            isListener = false;
        }
    }

    /**
     * 判斷是否遊戲成功
     * */
    public boolean win() {
        //周遊所有的方格  判斷每個方格是不是在它應該在的位置
        for (int i = 0; i < picButtons.length-1; i++) {
            //擷取方格的位置
            int x = picButtons[i].getBounds().x;
            int y = picButtons[i].getBounds().y;
            //隻要有一個方格不在自己的位置上就傳回false
            if ((y-20)/100*5 + (x-20)/90 != i) {
                return false;
            }
        }
        return true;
    }
    @Override
    public void mouseReleased(MouseEvent e) {
        // TODO Auto-generated method stub

    }
    @Override
    public void mouseEntered(MouseEvent e) {
        // TODO Auto-generated method stub
    }
    @Override
    public void mouseExited(MouseEvent e) {
        // TODO Auto-generated method stub
    }
}
           

原檔案以及源碼下載下傳連結:

連結:https://pan.baidu.com/s/19oe0AavtxNyCQfs8rbpK9A

提取碼:3598

感謝支援!謝謝!