用Java实现拼图小游戏

用JAVA实现拼图小游戏

目录

一、项目简介

          用JAVA的JFrame,JButton等工具实现拼图小游戏,包括拼图功能,更换图片功能,重新开始功能等等。

一、界面搭建和菜单搭建

          首先创建一个名为GameJframe的类,通过setSize()方法以及setTitle()等方法来初始化一个JFrame窗口,并设置标题为“拼图单机版”,通过setAlwaysOnTop()方法设置窗口置顶,并通过setLocationRelativeTo()方法设置窗口居中,而为使玩家可以通过关闭游戏窗口而关闭整个进程,我们则需设置默认关闭模式,当setDefaultCloseOperation()中参数为3即可。

//设置窗口宽、高
        this.setSize(603, 680);
        //设置窗口标题
        this.setTitle("拼图单机版");
        //设置窗口置顶
        this.setAlwaysOnTop(true);
        //设置窗口置中
        this.setLocationRelativeTo(null);
        //设置窗口关闭模式
                /*
        setDefaultCloseOperation()里的参数为0时,窗口不可关闭
        为1时,则为默认关闭模式
        为2时,则需关闭所有窗口才可完全关闭虚拟机
        为3时,则只需关闭一个窗口即可完全关闭虚拟机
        */
        this.setDefaultCloseOperation(3);

          为搭建菜单,需通过创建JMenuBarJMenu对象实现,通过其中的add()方法将需要的菜单选项添加到窗口中即可。

        //创建整个菜单对象
        JMenuBar jmb = new JMenuBar();

        //创建菜单下三个选项对象
        JMenu functionjm = new JMenu("菜单");
        JMenu aboutjm = new JMenu("关于我");

        JMenu changeimage = new JMenu("更换图片");

二、添加和打乱图片

        拼图游戏自然要有图片以供我们拼接,为此我们需准备好相应的图片资源,并复制粘贴至项目所在的文件夹中,通过创建JLabel对象和ImageIcon对象来管理图片,通过其中的成员方法setBounds()来设置图片大小以及setBorder()方法来设置图片格式,方法中参数为0时表示让图片凸出来,参数为1则表示让图片凹进去,为美观,我们选择将参数设为1,然后通过getContentpane()方法来添加进去。

//创建一个JLabel管理容器
                JLabel jl = new JLabel(new ImageIcon(path+temppath+temp+"\\"+count+".jpg"));
                //设置图片位置以及大小
                jl.setBounds(105*j+83,105*i+134,105,105);
                //给图片设置边框
                //参数为0时表示让图片凸出来
                //参数为1时表示让图片凹进去
                jl.setBorder(new BevelBorder(1));
                this.getContentPane().add(jl);

        在添加完图片后,为打乱图片,我们可以将图片分为16份,15份索引和一份空白图片,所以我们只需创建一个如下的4行4列的二维数组,将随机打乱后的位置索引存储进去,在添加图片时按照打乱后的索引进行添加即可。

111154
31059
8267
0121413

    //存储打乱后的索引
    private int[][] data = new int[4][4];
    int[] arr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    //数组随机索引
    int temp = 0;
    Random r = new Random();
    //打乱数组元素
    for (int i = 0; i < arr.length; i++) {
        int index = r.nextInt(arr.length);
        temp = arr[i];
        arr[i] = arr[index];
        arr[index] = temp;
    }
  	//给二位数组添加打乱后的元素
    for (int i = 0; i < arr.length; i++) {
        //若当前元素为空白元素,则令x和y为当前元素的位置
        if (arr[i] == 0){
            x = i / 4;
            y = i % 4;
        }
        data[i / 4][i % 4] = arr[i];
    }    

三、添加事件和美化图片

        在我们玩游戏时,需要对图片进行操作,这时候就需要用到监听这个接口了,比如在编写图片移动功能时,我们就要对键盘进行监听,当我们按到w键或者上箭头时,空白格子下方的图片就会向上移动一格,所以我们要实现KeyListener接口,并重写keyRelease()方法即可。

if (code == 37 || code == 65){
           System.out.println("向左移动");
           //实现空白图片右方的图片向左移动
           if (y == 3){
               return;
           }
           data[x][y] = data[x][y+1];
           data[x][y+1] = 0;
           y++;
           step++;
           //调用方法按照最新的数字加载图片
           initimage();
       }

        为美化图片,使玩家获得更好游戏体验,只需为图片添加一个背景即可。

        //添加背景图片
        JLabel jb = new JLabel(new ImageIcon("image\\background.png"));
        jb.setBounds(40,40,508,560);
        this.getContentPane().add(jb);

四、计步和菜单业务实现

        为了实现计步功能,只需定义一个成员变量来储存步数,当移动一次时,步数加一,当选择重新开始游戏或者更换图片时,步数清零即可。而菜单业务则与上文的移动功能类似,也需实现监听接口,当鼠标点击该功能按钮时,就要进行相应的操作。

Object obj = e.getSource();
        if (obj == restartjmi){
            System.out.println("重新游戏");
            //计步器清零
            step = 0;
            //初始化数据
            initdata();
            //初始化图片
            initimage();
        }
        else if(obj == closejmi){
            System.out.println("关闭游戏");
            //关闭虚拟机
            System.exit(0);
        }else if(obj == accountjmi){
            System.out.println("名片");

            JDialog jdi = new JDialog();
            JLabel jb = new JLabel(new ImageIcon("image\\mingpian.jpg"));
            //设置位置
            jb.setBounds(0,0,300,299);
            jdi.getContentPane().add(jb);
            //设置弹框大小
            jdi.setSize(344,344);
            //设置弹框置顶
            jdi.setAlwaysOnTop(true);
            //设置弹框居中
            jdi.setLocationRelativeTo(null);
            //设置弹框不关闭无法继续
            jdi.setModal(true);
            //设置弹框可视化
            jdi.setVisible(true);
        }else if (obj == girl) {
            System.out.println("更换美女图片");
            //计步器清零
            step = 0;
            //初始化数据
            initdata();
            //随机图片库
            temppath = "\\girl\\girl";
            changei();
        }else if (obj == animal) {
            System.out.println("更换动物图片");
            //计步器清零
            step = 0;
            //初始化数据
            initdata();
            //随机图片库
            temppath = "\\animal\\animal";
            changei();
        }else if (obj == sport) {
            System.out.println("更换运动图片");
            //计步器清零
            step = 0;
            //初始化数据
            initdata();
            //随机图片库
            temppath = "\\sport\\sport";
            changei();
        }

五、最终代码实现以及结果展示

 完整代码:

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 {
    //存储打乱后的索引
    private int[][] data = new int[4][4];
    //创建选项下的条目对象
    JMenuItem restartjmi = new JMenuItem("重新开始");
    //JMenuItem relogjmi = new JMenuItem("重新登录");
    JMenuItem closejmi = new JMenuItem("关闭游戏");
    JMenuItem girl = new JMenuItem("美女");
    JMenuItem animal = new JMenuItem("动物");
    JMenuItem sport = new JMenuItem("运动");
    JMenuItem accountjmi = new JMenuItem("名片");
    //记录空白图片在二维数组中的位置
    private int x = 0;
    private int y = 0;
    //定义路径
    String path = "image";
    String temppath = "\\girl\\girl";

    int temp = 1;

    //String path = "image";
    //定义一个胜利数组
    private int[][] win = new int[][]{
            {1,2,3,4},
            {5,6,7,8},
            {9,10,11,12},
            {13,14,15,0}
    };
    //定义变量来统计步数
    private int step = 0;

    //判断data数组中的值是否跟win数组中的值完全相同
    //相同则胜利,返回true。不同则继续,返回false
    public boolean victory(){
        //判断data数组元素与win数组元素是否全部相同
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                if (data[i][j] != win[i][j]){
                    return false;
                }
            }
        }
        //遍历结束,全部相同返回true
        return true;
    }

    public GameJFrame() {
        //初始化窗口
        initjf();

        //初始化菜单
        initjmbar();

        //初始化数据
        initdata();

        //初始化图片
        initimage();







        //设置窗口可视化
        this.setVisible(true);
    }

    private void initdata() {
        int[] arr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        //数组随机索引
        int temp = 0;
        Random r = new Random();
        //打乱数组元素
        for (int i = 0; i < arr.length; i++) {
            int index = r.nextInt(arr.length);
            temp = arr[i];
            arr[i] = arr[index];
            arr[index] = temp;
        }
        //给二维数组添加打乱后的索引
//        int index = 0;
//        for (int i = 0; i < 4; i++) {
//            for (int j = 0; j < 4; j++) {
//                data[i][j] = arr[index];
//                index++;
//            }
//        }
        //给二位数组添加打乱后的元素
        for (int i = 0; i < arr.length; i++) {
            //若当前元素为空白元素,则令x和y为当前元素的位置
            if (arr[i] == 0){
                x = i / 4;
                y = i % 4;
            }
            data[i / 4][i % 4] = arr[i];
        }
    }

    private void initimage(){
        //删除所有图片
        this.getContentPane().removeAll();

        //调用victory方法判断是否胜利
        if (victory()) {
            JLabel win = new JLabel(new ImageIcon("image\\win.png"));
            //JLabel win = new JLabel(new ImageIcon("image\\win.png"));
            win.setBounds(203,283,197,73);
            this.getContentPane().add(win);
        }

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



        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                int count = data[i][j];
                //创建一个JLabel管理容器
                JLabel jl = new JLabel(new ImageIcon(path+temppath+temp+"\\"+count+".jpg"));
                //设置图片位置以及大小
                jl.setBounds(105*j+83,105*i+134,105,105);
                //给图片设置边框
                //参数为0时表示让图片凸出来
                //参数为1时表示让图片凹进去
                jl.setBorder(new BevelBorder(1));
                this.getContentPane().add(jl);
            }
        }

        //添加背景图片
        JLabel jb = new JLabel(new ImageIcon("image\\background.png"));
        jb.setBounds(40,40,508,560);
        this.getContentPane().add(jb);

        //刷新加载图片
        this.getContentPane().repaint();
    }

    private void changei(){

        Random r = new Random();

        if ((path+temppath).equals("image\\girl\\girl")){
            temp = r.nextInt(13)+1;
            initimage();
        }else if((path+temppath).equals("image\\animal\\animal")){
            temp = r.nextInt(8)+1;
            initimage();
        }else if((path+temppath).equals("image\\sport\\sport")){
            temp = r.nextInt(10)+1;
            initimage();
        }

    }

    private void initjmbar() {

        //创建整个菜单对象
        JMenuBar jmb = new JMenuBar();

        //创建菜单下三个选项对象
        JMenu functionjm = new JMenu("菜单");
        JMenu aboutjm = new JMenu("关于我");

        JMenu changeimage = new JMenu("更换图片");

        //添加条目对象到选项对象中
        functionjm.add(changeimage);
        functionjm.add(restartjmi);
        //functionjm.add(relogjmi);
        functionjm.add(closejmi);
        aboutjm.add(accountjmi);

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

        //给条目绑定事件
        restartjmi.addActionListener(this);
        //relogjmi.addActionListener(this);
        closejmi.addActionListener(this);
        accountjmi.addActionListener(this);
        girl.addActionListener(this);
        animal.addActionListener(this);
        sport.addActionListener(this);

        //将选项对象添加到菜单对象中
        jmb.add(functionjm);
        jmb.add(aboutjm);

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

    private void initjf(){
        //设置窗口宽、高
        this.setSize(603, 680);

        //设置窗口标题
        this.setTitle("拼图单机版");

        //设置窗口置顶
        this.setAlwaysOnTop(true);

        //设置窗口置中
        this.setLocationRelativeTo(null);

        //设置窗口关闭模式
                /*
        setDefaultCloseOperation()里的参数为0时,窗口不可关闭
        为1时,则为默认关闭模式
        为2时,则需关闭所有窗口才可完全关闭虚拟机
        为3时,则只需关闭一个窗口即可完全关闭虚拟机
        */
        this.setDefaultCloseOperation(3);

        //添加键盘监听指针
        this.addKeyListener(this);

        //只有取消居中,才可以将图片放到指定位置
        this.setLayout(null);
    }

    @Override
    public void keyTyped(KeyEvent e) {

    }

    //按下A键不松开时会调用此方法实现图片还原功能
    @Override
    public void keyPressed(KeyEvent e) {
        int code = e.getKeyCode();
        if (code == 73){
            //将界面中的图片全部删除
            this.getContentPane().removeAll();
            //加载一张完整图片
            JLabel jb = new JLabel(new ImageIcon(path+temppath+temp+"\\"+"all.jpg"));
            jb.setBounds(83,134,420,420);
            this.getContentPane().add(jb);
            //加载背景图片
            JLabel jb1 = new JLabel(new ImageIcon("image\\background.png"));
            jb1.setBounds(40,40,508,560);
            this.getContentPane().add(jb1);
            //刷新界面
            this.getContentPane().repaint();
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
       int code = e.getKeyCode();
       //判断游戏是否胜利,胜利则直接结束,不用执行下面的代码
        if (victory()) {
            return;
        }
       if (code == 37 || code == 65){
           System.out.println("向左移动");
           //实现空白图片右方的图片向左移动
           if (y == 3){
               return;
           }
           data[x][y] = data[x][y+1];
           data[x][y+1] = 0;
           y++;
           step++;
           //调用方法按照最新的数字加载图片
           initimage();
       }else if(code == 38 || code == 87){
           System.out.println("向上移动");
           //实现空白图片下方的图片向上移动
           if (x == 3){
               return;
           }
           data[x][y] = data[x+1][y];
           data[x+1][y] = 0;
           x++;
           step++;
           //调用方法按照最新的数字加载图片
           initimage();
       }else if(code == 39 || code == 68)
       {
           System.out.println("向右移动");
           //实现空白图片左方的图片向右移动
           if (y == 0){
               return;
           }
           data[x][y] = data[x][y-1];
           data[x][y-1] = 0;
           y--;
           step++;
           //调用方法按照最新的数字加载图片
           initimage();
       }else if(code == 40 || code == 83){
           System.out.println("向下移动");
           //实现空白图片上方的图片向下移动
           if (x == 0){
               return;
           }
           data[x][y] = data[x-1][y];
           data[x-1][y] = 0;
           x--;
           step++;
           //调用方法按照最新的数字加载图片
           initimage();
       }else if(code == 73){
           //当松开I键时,初始化界面
           initimage();
       }else if(code == 66){
           //当按下键为B时,作弊
           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 == restartjmi){
            System.out.println("重新游戏");
            //计步器清零
            step = 0;
            //初始化数据
            initdata();
            //初始化图片
            initimage();
        }
//        else if(obj == relogjmi){
//            System.out.println("重新登录");
//            //关闭当前游戏界面
//            this.setVisible(false);
//            //打开登陆界面
//            new LoginJFrame();
//        }
        else if(obj == closejmi){
            System.out.println("关闭游戏");
            //关闭虚拟机
            System.exit(0);
        }else if(obj == accountjmi){
            System.out.println("名片");

            JDialog jdi = new JDialog();
            JLabel jb = new JLabel(new ImageIcon("image\\mingpian.jpg"));
            //设置位置
            jb.setBounds(0,0,300,299);
            jdi.getContentPane().add(jb);
            //设置弹框大小
            jdi.setSize(344,344);
            //设置弹框置顶
            jdi.setAlwaysOnTop(true);
            //设置弹框居中
            jdi.setLocationRelativeTo(null);
            //设置弹框不关闭无法继续
            jdi.setModal(true);
            //设置弹框可视化
            jdi.setVisible(true);
        }else if (obj == girl) {
            System.out.println("更换美女图片");
            //计步器清零
            step = 0;
            //初始化数据
            initdata();
            //随机图片库
            temppath = "\\girl\\girl";
            changei();
        }else if (obj == animal) {
            System.out.println("更换动物图片");
            //计步器清零
            step = 0;
            //初始化数据
            initdata();
            //随机图片库
            temppath = "\\animal\\animal";
            changei();
        }else if (obj == sport) {
            System.out.println("更换运动图片");
            //计步器清零
            step = 0;
            //初始化数据
            initdata();
            //随机图片库
            temppath = "\\sport\\sport";
            changei();
        }
    }
}

成品展示:

 

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值