黑马Java拼图游戏需求文档和完整代码展示

需求文档

项目名称:拼图游戏

项目概述: 拼图游戏是一款基于Java基础语法开发的桌面游戏,通过拖动图片块来完成图片的拼图,游戏分为重新开始、重新登录、关闭游戏、更换图片等功能。

功能需求:

2.1 游戏界面:

  • 游戏界面大小为603x680像素
  • 界面标题为“拼图游戏单机版 V1.0
  • 界面居中显示 - 界面关闭时退出程序

2.2 菜单功能:

  • 功能菜单包括重新开始、重新登录、关闭游戏、更换图片功能 -
  • 关于我们菜单包括赞助和版本号功能

2.3 图片功能:

  • 可以更换不同类别的图片,包括美女、动物、运动等 - 每类图片包含多张图片可供选择

2.4 游戏操作:

  • 键盘移动空白块完成拼图 - 计步器统计步数 - 提供作弊码快速通关
用户界面:

游戏界面包含图片拼图区域、计步器、胜利图片显示区域

数据需求:

二维数组存储图片数据

计数器记录步数

二维数据判断游戏胜利状态

非功能需求:

游戏界面美观、易操作

图片加载速度快

界面响应快速

其他需求:

提供作弊码快速通关

提供赞助和版本号信息

提供重新开始、重新登录、关闭游戏等功能

附加需求:

可以根据用户需求定制更多图片类别和图片数量

部分代码展示(提供详细解释)(完整代码在最下面)

创建初始窗口代码

//创建界面,初始化界面(单独一个方法)
public void init(){
	//创建初始窗口
	//Jframe类,界面,窗体(class类继承了JFrame父类)
	//1.设置界面的宽和高
	this.setSize(603,680);
	//2.设置界面标题为“拼图游戏单机版 V1.0”
	this.setTitle("拼图游戏单机版 V1.0");
	//3.设置界面一直处于置顶状态
	this.setAlwaysOnTop(true);//ps:true代表是一直置顶,如果是false就不是一直处于置顶状态
	//4.界面居中显示
	this.setLocationRelativeTo(null);
	//5.设置关闭模式,只要关闭游戏窗口就直接关闭虚拟机,防止关闭游戏后虚拟机持续运行
	this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	/*ps:还需要添加一个功能,就是取消添加图片是居中放置,只有取消了以后添加图片才是可以自己设置XY值来添加组件,不然就一直是居中放置*/
	this.setLayout(null);

	//为了游戏的操作,我们还需要设置键盘监听
	this.addKeyListener(this);
}

初始菜单(包括重新开始、重新登录、关闭游戏、更换图片功能 ,赞助和版本号功能)

public void initJMenuBar(){
	//JMenuBar就是标题下方的一个长条方框,方框里面的就是对象,对象里面的东西叫做条目
	//先创建一个大的JMenuBar对象
	JMenuBar jMenuBar = new JMenuBar();
	//再创建功能选项
	JMenu functionJMenu = new JMenu("功能");
    JMenu aboutJMenu = new JMenu("关于我们");
    JMenu changeImage = new JMenu("更换图片");//因为更换图片是再功能选项里面,所以我们需要将这个添加到功能对象中

	//创建JMenuItem对象
	//创建选项下面的条目对象,包含《功能》和《关于我们》还有《更换图片》
	//功能
    JMenuItem regainGameItem = new JMenuItem("重新开始");
    JMenuItem loginGameItem = new JMenuItem("重新登录");
    JMenuItem closeGameItem = new JMenuItem("关闭游戏");
    //关于我们
    JMenuItem accountItem = new JMenuItem("赞助");
    JMenuItem aboutGame = new JMenuItem("版本号");
    //更换图片
    JMenuItem girlP = new JMenuItem("换美女");
    JMenuItem animalP = new JMenuItem("换动物");
    JMenuItem sportP = new JMenuItem("换运动");
	
	//需要将创建的JMenuItem对象添加到JMenu对象中,这样可视化界面才会显现出这些条目
	//将JMenuItem条目归类到JMenu对象中
	//ps:将条目归类到对象中,将对象归类到菜单中,将菜单归类到JMenuBar中
    functionJMenu.add(changeImage);//更换图片
    functionJMenu.add(regainGameItem);//重新开始
    functionJMenu.add(loginGameItem);//重新登录
    functionJMenu.add(closeGameItem);//关闭游戏

	aboutJMenu.add(accountItem);//赞助
    aboutJMenu.add(aboutGame);//版本号
    
	changeImage.add(girlP);//换美女
    changeImage.add(animalP);//换动物
    changeImage.add(sportP);//换运动

	//将JMenu对象归类到Bar类
    jMenuBar.add(functionJMenu);
    jMenuBar.add(aboutJMenu);


 	//给条目绑定动作监听(鼠标点击)
        regainGameItem.addActionListener(this);//重新开始
        loginGameItem.addActionListener(this);//重新登录
        closeGameItem.addActionListener(this);//关闭游戏
        accountItem.addActionListener(this);//关于我们
        girlP.addActionListener(this);
        animalP.addActionListener(this);
        sportP.addActionListener(this);

//ps:现在已经将所有东西都归类到他的上一级,最后一步就是将可视化界面设置一下菜单
	this.setJMenuBar(jMenuBar);
}

打乱二维数组,将照片碎片按照打乱后的二维数组进行输出

public void swap(){
	Random rd = new Random();
	//图片碎片编号一共是1~15,0代表可移动空白块
    int[] arr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    for(int i =0;i<arr.length;i++){
    		//创建一个随机数
            int number = rd.nextInt(arr.length);
            int temp = arr[i];
            arr[i] = arr[number];
            arr[number] = temp;
        }
        //给二维数组添加数据
        for(int i =0;i<arr.length;i++){
            data[i/4][i%4] = arr[i];
            if(arr[i] == 0){
                x = i/4;
                y = i%4;
                //ps:一个小方法,可以将一维数组里的数据存储到二维数组中,只用一层for循环
            }
        }
    }

初始化图片(添加图片)

添加图片需要注意的小知识:先添加的图片显示在上层,后添加的图片显示在下层

 private void initImage(){
        //页面刷新
        this.getContentPane().removeAll();//ps:每次空白图片的更换都需要进行刷新界面的操作,不然界面无法更新

        //如果胜利则输出胜利的图标
        if(victory()){
            //创建一个对象胜利图片
            JLabel win = new JLabel(new ImageIcon("C:\\Users\\31412\\IdeaProjects\\mystatic\\src\\puzzleGame\\image\\win.png"));
            //设置图片的大小和位置
            win.setBounds(203,283,193,73);
            //将图片添加到界面中
            this.getContentPane().add(win);
        }

        //计数器
        JLabel stepCount = new JLabel("步数:" + count);//count已经创建好了但是不在这个方法中
        stepCount.setBounds(50,30,100,20);//设置计步器大小和位置
        this.getContentPane().add(stepCount);//将计步器添加到界面中

        //添加图片到界面上
        for (int i = 0; i < 4;i++) {
            for (int i1 = 0; i1 < 4;) {
                //创建一个图片类,将这个图片类添加到管理容器中
                JLabel jlabel = new JLabel(new ImageIcon(path + photoClass + "\\" + photoNumber +"\\"+ data[i][i1] +".jpg"));//ps:其中path,photoclass等都已经创建好了
                
                //添加边框
                jlabel.setBorder(new BevelBorder(BevelBorder.LOWERED));//1
                //指定图片位置
                jlabel.setBounds(105 * i1 + 83,105 * i + 134,105,105);//按照打乱好的二维数组进行输出图片
                i1++;
                //将这个容器添加到界面中
                this.getContentPane().add(jlabel);
                //如果图片编号为0,那么这个图片就是空白图片
            }
        }

        //添加背景图片(后添加,显示在下层)
        JLabel background = new JLabel(new ImageIcon("C:\\Users\\31412\\IdeaProjects\\mystatic\\src\\puzzleGame\\image\\background.png"));
        background.setBounds(40,40,508,560);
        //把背景图片添加到界面中
        this.getContentPane().add(background);

        //刷新界面强制界面重现绘制
        this.getContentPane().repaint();
    }

完成代码展示

import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.event.*;
import java.util.Random;

public class GameJframe extends JFrame implements KeyListener, ActionListener {
    //JFrame 界面,窗体
    //子类继承父类,也表示窗体
    //规定:GameJFrame也表示游戏的界面,以后所有的界面代码逻辑都写在这里

    Random rd = new Random();

    //创建选项下面的条目对象,包含《功能》和《关于我们》还有《更换图片》
    JMenuItem regainGameItem = new JMenuItem("重新开始");
    JMenuItem loginGameItem = new JMenuItem("重新登录");
    JMenuItem closeGameItem = new JMenuItem("关闭游戏");
    //关于我们
    JMenuItem accountItem = new JMenuItem("赞助");
    JMenuItem aboutGame = new JMenuItem("版本号");
    //更换图片
    JMenuItem girlP = new JMenuItem("换美女");
    JMenuItem animalP = new JMenuItem("换动物");
    JMenuItem sportP = new JMenuItem("换运动");

    //创建二维数组来存储图片
    int[][] data = new int[4][4];

    //创建XY来确定空白图片的位置
    int x,y;

    //创建计数器,统计步数
    int count = 0;

    //创建一个二维数据存储数据来判断游戏是否结束
    int[][] win = {
            {1,2,3,4},
            {5,6,7,8,},
            {9,10,11,12},
            {13,14,15,0},
    };

    String photoNumber = "";
    String photoClass = changeClass();
    String path = "C:\\Users\\31412\\IdeaProjects\\mystatic\\src\\puzzleGame\\image\\";


    //界面主体
    public GameJframe(){
        //初始界面
        init();

        //初始菜单
        initJMenuBar();

        //打乱数组
        swap();

        //添加图片(初始化图片)
        changePicture();
        initImage();

        //显示界面
        this.setVisible(true);

    }

    //初始界面
    private void init() {
        //设置界面的宽高
        this.setSize(603,680);//像素
        //设置界面的标题
        this.setTitle("拼图游戏单机版 VIP1.0");
        //设置一直处于置顶状态
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //取消添加图片是居中放置,只有取下了才会按照XY轴的形式添加组件
        this.setLayout(null);
        //设置关闭模式,关闭程序时,虚拟机自动停止
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

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


    }

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

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

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

        //将JMenuItem对象归类到JMenu中
        functionJMenu.add(changeImage);//更换图片
        functionJMenu.add(regainGameItem);//重新开始
        functionJMenu.add(loginGameItem);//重新登录
        functionJMenu.add(closeGameItem);//关闭游戏


        aboutJMenu.add(accountItem);//赞助
        aboutJMenu.add(aboutGame);//版本号

        changeImage.add(girlP);
        changeImage.add(animalP);
        changeImage.add(sportP);

        //给条目绑定动作监听(鼠标点击)
        regainGameItem.addActionListener(this);//重新开始
        loginGameItem.addActionListener(this);//重新登录
        closeGameItem.addActionListener(this);//关闭游戏
        accountItem.addActionListener(this);//关于我们
        girlP.addActionListener(this);
        animalP.addActionListener(this);
        sportP.addActionListener(this);

        //将JMenu对象归类到Bar类
        jMenuBar.add(functionJMenu);
        jMenuBar.add(aboutJMenu);

        //最后一步,给整个界面设置菜单也最容易漏掉的一步
        this.setJMenuBar(jMenuBar);
    }

    //更换图片类别
    public String changeClass(){
        String[] arr = {"girl","animal","sport"};
        int n = rd.nextInt(3);
        return arr[n];
    }

    //选择美女图片编号
    public String girlPicture(){
        int n = rd.nextInt(13) + 1;
        return "girl"+n;
    }

    //选择动物图片编号
    public String animalPicture(){
        int n = rd.nextInt(8) + 1;
        return "animal"+n;
    }
    //选择运动图片编号
    public String sportPicture(){
        int n = rd.nextInt(10) + 1;
        return "sport"+n;
    }

    public void changePicture(){
        //显示图片类别和图片编号
        switch (photoClass) {
            case "girl":
                photoNumber = girlPicture();
                break;
            case "animal":
                photoNumber = animalPicture();
                break;
            case "sport":
                photoNumber = sportPicture();
                break;
        }
    }

    //初始化图片(添加图片)
    //细节:先添加的图片是在上层的,后添加的图片是在下层的
    private void initImage(){
        //页面刷新
        this.getContentPane().removeAll();

        //胜利则输出图标
        if(victory()){
            //输出胜利图片
            JLabel win = new JLabel(new ImageIcon("C:\\Users\\31412\\IdeaProjects\\mystatic\\src\\puzzleGame\\image\\win.png"));
            win.setBounds(203,283,193,73);
            this.getContentPane().add(win);
        }

        //计数器来表示有多少步
        JLabel stepCount = new JLabel("步数:" + count);
        stepCount.setBounds(50,30,100,20);
        this.getContentPane().add(stepCount);

        //添加图片到界面上
        for (int i = 0; i < 4;i++) {
            for (int i1 = 0; i1 < 4;) {
                //创建一个图片类,将这个图片类添加到管理容器中
                JLabel jlabel = new JLabel(new ImageIcon(path + photoClass + "\\" + photoNumber +"\\"+ data[i][i1] +".jpg"));
                //添加边框
                jlabel.setBorder(new BevelBorder(BevelBorder.LOWERED));//1
                //指定图片位置
                jlabel.setBounds(105 * i1 + 83,105 * i + 134,105,105);
                i1++;
                //将这个容器添加到界面中
                this.getContentPane().add(jlabel);
                //如果图片编号为0,那么这个图片就是空白图片
            }
        }

        //添加背景图片(后添加,显示在下层)
        JLabel background = new JLabel(new ImageIcon("C:\\Users\\31412\\IdeaProjects\\mystatic\\src\\puzzleGame\\image\\background.png"));
        background.setBounds(40,40,508,560);
        //把背景图片添加到界面中
        this.getContentPane().add(background);

        //刷新界面强制界面重现绘制
        this.getContentPane().repaint();
    }

    //打乱图片顺序
    public void swap(){
        int[] arr = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        for(int i =0;i<arr.length;i++){
            int number = rd.nextInt(arr.length);
            int temp = arr[i];
            arr[i] = arr[number];
            arr[number] = temp;
        }
        //给二维数组添加数据
        for(int i =0;i<arr.length;i++){
            data[i/4][i%4] = arr[i];
            if(arr[i] == 0){
                x = i/4;
                y = i%4;
            }
        }
    }

    //判断游戏是否胜利
    public boolean victory(){
        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;
                }
            }
        }
        return true;
    }


    //键盘监听(没用上)
    @Override
    public void keyTyped(KeyEvent e) {

        //如果胜利就直接结束
        if(victory()){
            return;
        }

    }

    //键盘监听, 显示全部图片
    @Override
    public void keyPressed(KeyEvent e) {

        //如果胜利就直接结束
        if(victory()){
            return;
        }

        int code = e.getKeyCode();
        if(code == 65){
            //删除全部图片
            this.getContentPane().removeAll();
            //添加全部图片
            String allPhoto = "C:\\Users\\31412\\IdeaProjects\\mystatic\\src\\puzzleGame/image/";
            JLabel all = new JLabel(new ImageIcon(allPhoto + photoClass+"/"+photoNumber+"/all.jpg"));
            all.setBounds(83,134,420,420);
            this.getContentPane().add(all);
            //添加背景图
            JLabel background = new JLabel(new ImageIcon("C:\\Users\\31412\\IdeaProjects\\mystatic\\src\\puzzleGame\\image\\background.png"));
            background.setBounds(40,40,508,560);
            //把背景图片添加到界面中
            this.getContentPane().add(background);
            //刷新
            this.repaint();
        }
    }

    //键盘监听,操作白块
    @Override
    public void keyReleased(KeyEvent e) {

        //如果胜利就直接结束
        if(victory()){
            return;
        }

        int code = e.getKeyCode();
        //左方向键,空白方块向左移动
        if(code == 37){
            System.out.println("向左移动");
            data[x][y] = data[x][y-1];
            data[x][y-1] = 0;
            y--;
            count++;
            initImage();
        }
        //上方向键,空白方块向上移动
        else if(code == 38){
            System.out.println("向上移动");
            //逻辑:
            //空白方块向上移动
            //XY表示空白方块
            //x-1,y表示空白方块上方的数字
            data[x][y] = data[x-1][y];
            data[x-1][y] = 0;
            x--;
            count++;
            initImage();
        }
        //右方向键,空白方块向右移动
        else if(code == 39){
            System.out.println("向右移动");
            data[x][y] = data[x][y+1];
            data[x][y+1] = 0;
            y++;
            count++;
            initImage();
        }
        //下方向键,空白方块向下移动
        else if(code == 40){
            System.out.println("向下移动");
            data[x][y] = data[x+1][y];
            data[x+1][y] = 0;
            x++;
            count++;
            initImage();
        }
        else if(code == 65){
            initImage();
        }
        //作弊码,按一下可以通关
        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 == regainGameItem){
             System.out.println("重新游戏");
             //再次打乱二维数组
             swap();
             //计步器清零
             count = 0;
             //加载图片
             initImage();
         }else if(obj == loginGameItem){
             System.out.println("重新登录");
             //关闭界面
             this.setVisible(false);
             //打开登录界面
             new LoginJframe();
         }else if(obj == closeGameItem){
             System.out.println("关闭游戏");
             //关闭虚拟机
             System.exit(0);
         }else if(obj == accountItem){
             System.out.println("赞助");
             //创建收款码对象
             JLabel money = new JLabel(new ImageIcon("C:\\Users\\31412\\IdeaProjects\\mystatic\\src\\puzzleGame\\image\\微信图片_20240202174310.jpg"));
             //设置位置和宽高
             money.setBounds(0,0,423,389);
             //创建弹窗对象
             JDialog m = new JDialog();
             //将对象添加到弹框中
             m.add(money);
             //设置弹框大小
             m.setSize(500,450);
             //设置弹框置顶
             m.setAlwaysOnTop(true);
             //设置弹框居中
             m.setLocationRelativeTo(null);
             //设置弹框不关闭就不能进行下一步操作
             m.setModal(true);
             //显示弹框
             m.setVisible(true);
         }

         if(obj == girlP){
             System.out.println("换美女");
             //计步器清零
             count = 0;
             //打乱新的图片
             swap();
             //从13张女生图片选一张
             photoClass = "girl";
             photoNumber = girlPicture();
             //添加新的图片
             initImage();
         }else if(obj == animalP){
             System.out.println("换动物");
             //计步器清零
             count = 0;
             //打乱新的图片
             swap();
             //从8张动物的照片换一张
             photoClass = "animal";
             photoNumber = animalPicture();

             initImage();
         }else if(obj == sportP){
             System.out.println("换运动");
             //计步器清零
             count = 0;
             //打乱新的图片
             swap();
             //从10张运动的照片换一张
             photoClass = "sport";
             photoNumber = sportPicture();

             initImage();
         }
    }
}

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
import java.awt.*; import java.applet.*; import java.awt.event.*; public class PPuzzle extends Applet{ Image imgPuzzle,buff; Point fifteen=new Point(3,3); int[][] map={{0,4,8,12},{1,5,9,13},{2,6,10,14},{3,7,11,15}}; int sx,sy; Canvas screen; Graphics gs,gb; boolean running=false; Button bStart= new Button("新游戏"); Button bSee=new Button("显示正确图像"); public void init(){ prepareImage(); sx=imgPuzzle.getWidth(this)/4; sy=imgPuzzle.getHeight(this)/4; setBackground(Color.blue); initScreen(); initButtons(); add(screen); add(bStart); add(bSee); } void prepareImage(){ imgPuzzle=getImage(getCodeBase(),"images/3.jpg");// MediaTracker mt=new MediaTracker(this); mt.addImage(imgPuzzle, 0); try{ mt.waitForAll(); }catch(Exception e){} //创建buffer并获取graphics对象 buff=createImage(imgPuzzle.getWidth(this),imgPuzzle.getHeight(this)); gb=buff.getGraphics(); } void initMap(){ java.util.Random rnd=new java.util.Random(); int temp,x1,x2,y1,y2; for(int i=0;i<100;i++){ x1=rnd.nextInt(4); x2=rnd.nextInt(4); y1=rnd.nextInt(4); y2=rnd.nextInt(4); temp=map[x1][y1]; map[x1][y1]=map[x2][y2]; map[x2][y2]=temp; } outer:for(int j=0;j<4;j++) for(int i=0;i<4;i++) if(map[i][j]==15){ fifteen.setLocation(i,j); break outer; } } void initScreen(){ screen=new Canvas(){ public void paint(Graphics g){ if(gs==null) gs=getGraphics(); if(running) drawScreen(); else g.drawImage(imgPuzzle,0,0,this); } }; screen.setSize(imgPuzzle.getWidth(this), imgPuzzle.getHeight(this)); screen.addMouseListener(new MouseAdapter(){ public void mousePressed(MouseEvent me){ if(!running)return; int x=me.getX()/sx,y=me.getY()/sy; int fx=(int)fifteen.getX(),fy=(int)fifteen.getY(); if (Math.abs(fx-x)+Math.abs(fy-y)>=2)return; map[fx][fy]=map[x][y]; map[x][y]=15; fifteen.setLocation(x,y); drawScreen(); } }); } void initButtons(){ //新游戏 按钮事件的处理 bStart.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ae){ initMap(); drawScreen(); running=true; bSee.setLabel("显示正确图像"); } }); //显示正确图像 按钮事件处理 bSee.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent ae){ //bsee 按钮标题为”继续游戏“ if(bSee.getLabel().equals("继续游戏")){ drawScreen(); bSee.setLabel("继续游戏"); } else{ //bsee的标题显示为”显示正确图像“ gs.drawImage(imgPuzzle,0,0,screen); bSee.setLabel("继续游戏"); } } }); } void drawScreen(){ gb.clearRect(0, 0, sx*4, sy*4); //将指定位置的图像块绘制到Buffer中 for(int j=0;j<4;j++) for(int i=0;i<4;i++) if(map[i][j]!=15) drawSegment(map[i][j],i,j); //向Screen绘制buffer中的图像 gs.drawImage(buff,0,0,screen); } void drawSegment(int seg,int x,int y){ int dx=seg%4*sx,dy=seg/4*sy; //可能有错误 gb.drawImage(imgPuzzle, x*sx,y*sy ,x*sx+sx-1 ,y*sy+sy-1 , dx , dy,dx+sx-1,dy+sy-1 ,screen ); } }
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值