菜鸟之路day02-04拼图小游戏开发一一JAVA基础综合项目

简介: 本项目基于黑马程序员教程,涵盖面向对象进阶、继承、多态等知识,历时约24小时完成。项目去除了登录和注册模块,专注于单机游戏体验。使用Git进行版本管理,代码托管于Gitee。项目包含窗体搭建、事件监听、图片加载与打乱、交互逻辑实现、菜单功能及美化界面等内容。通过此项目,巩固了Java基础并提升了实际开发能力。仓库地址:[https://gitee.com/zhang-tenglan/puzzlegame.git](https://gitee.com/zhang-tenglan/puzzlegame.git)

菜鸟之路day02-04拼图小游戏开发一一JAVA基础综合项目

作者:blue

时间:2025.1.20-1.22

[TOC]

0.概述

1.项目来源:黑马程序员:BV17F411T7Ao,感谢阿玮老师,讲的实在是太详细了

2.菜鸟之路day02-day04:

​ 第一天我学习了面向对象的进阶知识,继承,多态,接口,内部类,等知识

​ 第二天我开始做项目,项目完成了85%

​ 第三天上午完善了项目,总耗时估计在24h左右,包括学习知识,代码编写,版本管理,文档编写

3.在项目中,我删除了登录和注册模块,因为我认为在一个单机游戏中,这两个模块有些许突兀(不是懒,听我狡辩!)

4.由于我在菜鸟之路day01时学习了Git,所以在这个项目中,我运用了git来管理这个项目,并将源码上传到了Gitee,读者可根据我的11次提交循序渐进的学习此项目

5.在本文中我仅展示部分核心代码,读者想获取完整代码,应该去我的仓库里clone,仓库是public的

6.图片均为视频提供,里面的美女我一个都不认识(真的!!!!)

7.本项目仅为java基础练习项目,此类项目并不是java语言的特长,用前端知识也确实能写出比这个项目更好的拼图游戏,但是我们毕竟是在练习java这个后端语言嘛,所以项目有它存在的意义,理解万岁。

仓库地址:https://gitee.com/zhang-tenglan/puzzlegame.git

在第11次提交时,我才删掉了注册和登录界面,所以若读者对这两个界面有兴趣,可以git第10次提交

image-20250122104803581.png

此为我项目的结构图:

image-20250122103819089.png

1.界面搭建

1.1创建窗体

创建ui包,在包内新建三个JavaBean类,三个类均继承JFrame(窗体类)这个父类,分别代表游戏的三个界面。

定义空参构造方法:1.设置窗口宽高 2.将窗口显示设置为true,表示可视

package com.bluening.ui;

import javax.swing.*;
import java.awt.*;

//游戏主界面
public class GameJFrame extends JFrame{
   

    //空参构造,做初始化
    public GameJFrame() {
   
        setSize(603,680);
        setVisible(true);
    }
}

1.2窗体基础设置

还是以GameJFrame这个类为例

package com.bluening.ui;

import javax.swing.*;
import java.awt.*;

//游戏主界面
public class GameJFrame extends JFrame{
   

    //空参构造,做初始化
    public GameJFrame() {
   
        //设置界面宽高
        this.setSize(603,680);
        //设置界面的标题
        this.setTitle("拼图游戏单机版");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //让窗体显示
        this.setVisible(true);
    }
}

1.3创建主界面菜单

主界面与菜单结构,先建立各自对象,然后再建立对象间的联系

image-20250121090752588.png

private void initJMenuBar() {
   
        JMenuBar jMenuBar = new JMenuBar();

        JMenu functionJMenu = new JMenu("功能");
        JMenu aboutJMenu = new JMenu("关于我");


        JMenuItem replayItem = new JMenuItem("重新游戏");
        JMenuItem reLoginItem = new JMenuItem("重新登录");
        JMenuItem closeItem = new JMenuItem("关闭游戏");

        JMenuItem myBlogItem = new JMenuItem("我的博客");

        //给菜单添加条目
        functionJMenu.add(replayItem);
        functionJMenu.add(reLoginItem);
        functionJMenu.add(closeItem);

        aboutJMenu.add(myBlogItem);

        //给菜单栏添加JMenu
        jMenuBar.add(functionJMenu);
        jMenuBar.add(aboutJMenu);

        //给窗体添加菜单栏
        this.setJMenuBar(jMenuBar);
    }

1.4添加图片素材,并将图片素材加载到GameJFrame中

结构:

image-20250121102953472.png

private void initImage() {
   
        int number = 1;
        for (int i=0;i<4;i++){
   
            for (int j=0;j<4;j++){
   
                //创建ImageIcon对象
                ImageIcon icon = new ImageIcon("image/animal/animal3/"+number+".jpg");

                //创建JLabel对象(JLabel一个管理容器)
                JLabel jLabel = new JLabel(icon);

                //指定图片位置
                jLabel.setBounds(105*j,105*i,105,105);

                //把JLabel添加到界面当中
                getContentPane().add(jLabel);

                //加完一张添加下一个图片
                number++;
            }
        }
    }

1.5打乱图片

创建了随机生成二维数组的方法,利用随机二维数组,打乱图片

private void initData() {
   
        int[] tempArr = {
   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
        //打乱
        Random rd = new Random();
        for(int i=0;i<tempArr.length;i++){
   
            int index = rd.nextInt(tempArr.length);
            int temp = tempArr[index];
            tempArr[index] = tempArr[i];
            tempArr[i] = temp;
        }

        for (int i = 0; i < tempArr.length; i++) {
   
            data[i/4][i%4] = tempArr[i];
        }
    }

2.如何实现交互

2.1事件

​ ①事件源:按钮 图片 窗体

​ ②事件:某些操作 如:鼠标单击,鼠标划入

​ ③绑定监听:当事件源上发生了某件事,则执行某段代码

​ KeyListener:键盘监听

​ MouseListener:鼠标监听

​ ActionListener:动作监听

2.4实现事件监听的两种方式

2.4.1匿名内部类
package Test;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

/*
    在这个代码中,我将以匿名内部类的方式实现事件监听
*/
public class ActionListenerTest {
   
    public static void main(String[] args) {
   
        //创建一个窗体对象
        JFrame jFrame = new JFrame();
        //设置界面宽高
        jFrame.setSize(603, 680);
        //设置界面的标题
        jFrame.setTitle("拼图游戏单机版");
        //设置界面置顶
        jFrame.setAlwaysOnTop(true);
        //设置界面居中
        jFrame.setLocationRelativeTo(null);
        //设置关闭模式
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //取消默认的居中放置
        jFrame.setLayout(null);

        //设置按钮
        JButton jb1 = new JButton("点我吧");
        jb1.setBounds(0,0,105,105);

        jb1.addActionListener(
                //匿名内部类
                new ActionListener() {
   
                    @Override
                    public void actionPerformed(ActionEvent e) {
   
                        Random r = new Random();
                        jb1.setLocation(r.nextInt(500),r.nextInt(500));
                    }
                }
        );

        jFrame.getContentPane().add(jb1);

        //让窗体显示
        jFrame.setVisible(true);
    }
}
2.4.2本类作为事件监听接口的实现类
package Test;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

//本类用来测试事件监听
//我们重写接口ActionListener中的actionPerformed,自己就是addActionListener的实现类
public class MyJFrame extends JFrame implements ActionListener {
   

    //设置一个按钮
    JButton jb1 = new JButton("点我啊");
    JButton jb2 = new JButton("我是另一个按钮");

    public MyJFrame(){
   
        //设置界面宽高
        this.setSize(603,680);
        //设置界面的标题
        this.setTitle("拼图游戏单机版");
        //设置界面置顶
        this.setAlwaysOnTop(true);
        //设置界面居中
        this.setLocationRelativeTo(null);
        //设置关闭模式
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        //取消默认的居中放置
        this.setLayout(null);

        jb1.setBounds(0,0,105,105);
        jb1.addActionListener(this);//自己就是addActionListener的实现类

        jb2.setBounds(200,200,105,105);
        jb2.addActionListener(this);

        //将按钮加入窗体中
        this.getContentPane().add(jb1);
        this.getContentPane().add(jb2);

        //让窗体显示
        this.setVisible(true);
    }

    //重写接口中的方法
    @Override
    public void actionPerformed(ActionEvent e) {
   
        //判断当前按钮是谁

        //获取被点击的按钮对象
        Object jb = e.getSource();
        if(jb==jb1){
   
            jb1.setSize(200,200);
        } else if (jb==jb2) {
   
            Random rd = new Random();
            jb2.setLocation(rd.nextInt(500),rd.nextInt(500));
        }
    }
}

3.美化界面

针对GameJFrame类中的initImage方法做一个界面美化

private void initImage() {
   

        //先加载的图片在上面,后加载的图片在下面
        for (int i=0;i<4;i++){
   
            for (int j=0;j<4;j++){
   

                //获取图片编号
                int number = data[i][j];

                //创建ImageIcon对象
                ImageIcon icon = new ImageIcon("image/animal/animal3/"+number+".jpg");

                //创建JLabel对象(JLabel一个管理容器)
                JLabel jLabel = new JLabel(icon);

                //指定图片位置
                jLabel.setBounds(105*j+83,105*i+134,105,105);

                //给图片添加边框
                jLabel.setBorder(new BevelBorder(BevelBorder.LOWERED));

                //把JLabel添加到界面当中
                this.getContentPane().add(jLabel);

            }
        }

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

4.实现图片移动业务逻辑

4.1图片根据方向键移动

步骤:

​ 1.本类实现KeyListener接口,并重写所有抽象方法

​ 2.给整个界面添加键盘监听事件

​ 3.统计一下空白方块对应的数字0在二维数组中的位置

​ 4.在KeyReleased方法当中实现移动的逻辑

@Override
    public void keyReleased(KeyEvent e) {
   
        //实现键盘方向键控制移动,其实就是交换[0][0]位置,及其周边位置的图片
        int code = e.getKeyCode();
        if(code==37){
   //左
            if(y+1<4){
   
                data[x][y]=data[x][y+1];
                data[x][y+1]=0;
                y++;
                initImage();
            }
        }
        else if(code==38){
   //上
            if(x+1<4){
   
                data[x][y]=data[x+1][y];
                data[x+1][y]=0;
                x++;
                initImage();
            }
        }
        else if(code==39){
   //右
            if(y-1>=0){
   
                data[x][y]=data[x][y-1];
                data[x][y-1]=0;
                y--;
                initImage();
            }
        }
        else if(code==40){
   //下
            if(x-1>=0){
   
                data[x][y]=data[x-1][y];
                data[x-1][y]=0;
                x--;
                initImage();
            }
        }
    }

4.2查看全图功能

在代码中,我设置按住ctrl键不松,就可以查看原图

@Override
    //这里我们实现的逻辑是按住ctrl不松,查看完整的图片
    public void keyPressed(KeyEvent e) {
   
        if(victory()){
   
            return;
        }

        int code = e.getKeyCode();
        if(code==17){
   
            //清空图片
            this.getContentPane().removeAll();
            //创建对象
            JLabel jLabel = new JLabel(new ImageIcon(path+"all.jpg"));
            jLabel.setBounds(83,134,420,420);
            this.getContentPane().add(jLabel);
            //添加背景图片
            JLabel Background = new JLabel(new ImageIcon("image/background.png"));
            Background.setBounds(40,40,508,560);
            this.getContentPane().add(Background);

            //刷新
            this.getContentPane().repaint();
        }
    }

4.3作弊码

我设置了按m,一键通关,原理是改变data数组,然后重新初始化图片

//作弊码,一件通关
        else if(code==77){
   
            data = new int[][]{
   
                    {
   1,2,3,4},
                    {
   5,6,7,8},
                    {
   9,10,11,12},
                    {
   13,14,15,0}
            };
            initImage();
        }

4.4判断胜利

利用一个按顺序的win数组和data数组比对,如果完全一样的话,则打印出胜利,并禁止移动

//判断胜利
    public boolean victory(){
   
        for(int i=0;i<data[0].length;i++){
   
            for(int j=0;j<data.length;j++){
   
                if(win[i][j]!=data[i][j]){
   
                    return false;
                }
            }
        }
        return true;
    }

4.4计数器

设置step变量,每按一步自增一次,让其显示出来

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

5.菜单业务实现

为条目设置动作监听,类继承ActionListener接口,重写其中方法,针对不同条目执行对应代码

@Override
    public void actionPerformed(ActionEvent e) {
   
        Object item = e.getSource();
        if(item==replayItem){
   //重新游戏
            initData();
            step=0;
            initImage();
        } else if (item==reLoginItem) {
   //重新登录
            this.setVisible(false);
            new LoginJFrame();
        } else if (item==closeItem) {
   //关闭
            System.exit(0);//直接关闭虚拟机
        }else if(item==myBlogItem) {
   //博客
            //创建一个弹框对象
            JDialog jDialog = new JDialog();

            JLabel jLabel = new JLabel(new ImageIcon("image/about.png"));
            //设置宽高
            jLabel.setBounds(0,0,380,539);
            //把图片添加到弹框中
            jDialog.getContentPane().add(jLabel);
            //给弹框设置大小
            jDialog.setSize(420,580);
            //让弹框置顶
            jDialog.setAlwaysOnTop(true);
            //让弹框居中
            jDialog.setLocationRelativeTo(null);
            //弹框不关闭无法操作下面界面
            jDialog.setModal(true);
            //让弹框显示出来
            jDialog.setVisible(true);
        }
    }

6.完成图片切换功能

设置更换条目,添加事件监听,随机生成,改变路径,重新加载图片

else if (item==girl) {
   //更换美女图片
            //生成随机路径
            Random rd = new Random();
            int num = rd.nextInt(8)+1;
            path = "image/girl/girl"+num+"/";
            initData();
            step = 0;
            initImage();
        }
目录
相关文章
|
2天前
|
JavaScript NoSQL Java
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
136 96
接替此文【下篇-服务端+后台管理】优雅草蜻蜓z系统JAVA版暗影版为例-【蜻蜓z系列通用】-2025年全新项目整合搭建方式-这是独立吃透代码以后首次改变-独立PC版本vue版搭建教程-优雅草卓伊凡
|
4天前
|
前端开发 JavaScript Java
【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
42 13
【03】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架搭建-服务端-后台管理-整体搭建-优雅草卓伊凡商业项目实战
|
5天前
|
人工智能 JavaScript 关系型数据库
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
48 14
【02】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-ui设计图figmaUI设计准备-figma汉化插件-mysql数据库设计-优雅草卓伊凡商业项目实战
|
3天前
|
SQL JavaScript 安全
【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
31 11
【04】Java+若依+vue.js技术栈实现钱包积分管理系统项目-若依框架二次开发准备工作-以及建立初步后端目录菜单列-优雅草卓伊凡商业项目实战
|
7天前
|
人工智能 JavaScript 安全
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
49 13
【01】Java+若依+vue.js技术栈实现钱包积分管理系统项目-商业级电玩城积分系统商业项目实战-需求改为思维导图-设计数据库-确定基础架构和设计-优雅草卓伊凡商业项目实战
|
2天前
|
网络协议 Java Shell
java spring 项目若依框架启动失败,启动不了服务提示端口8080占用escription: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to listen on another port-优雅草卓伊凡解决方案
java spring 项目若依框架启动失败,启动不了服务提示端口8080占用escription: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to listen on another port-优雅草卓伊凡解决方案
22 7
|
24天前
|
算法 搜索推荐 Java
【潜意识Java】深度解析黑马项目《苍穹外卖》与蓝桥杯算法的结合问题
本文探讨了如何将算法学习与实际项目相结合,以提升编程竞赛中的解题能力。通过《苍穹外卖》项目,介绍了订单配送路径规划(基于动态规划解决旅行商问题)和商品推荐系统(基于贪心算法)。这些实例不仅展示了算法在实际业务中的应用,还帮助读者更好地准备蓝桥杯等编程竞赛。结合具体代码实现和解析,文章详细说明了如何运用算法优化项目功能,提高解决问题的能力。
55 6
|
24天前
|
Java 应用服务中间件 API
【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析
本文介绍了 Spring Boot 的核心概念和使用场景,并通过一个实战项目演示了如何构建一个简单的 RESTful API。
38 5
|
24天前
|
Java 数据库连接 数据库
【潜意识Java】深度分析黑马项目《苍穹外卖》在Java学习中的重要性
《苍穹外卖》项目对Java学习至关重要。它涵盖了用户管理、商品查询、订单处理等模块,涉及Spring Boot、MyBatis、Redis等技术栈。
65 4
|
24天前
|
前端开发 Java 数据库连接
【潜意识Java】深度解读JavaWeb开发在Java学习中的重要性
深度解读JavaWeb开发在Java学习中的重要性
28 4

热门文章

最新文章