菜鸟之路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();
        }
目录
相关文章
|
3月前
|
安全 Java API
Java Web 在线商城项目最新技术实操指南帮助开发者高效完成商城项目开发
本项目基于Spring Boot 3.2与Vue 3构建现代化在线商城,涵盖技术选型、核心功能实现、安全控制与容器化部署,助开发者掌握最新Java Web全栈开发实践。
381 1
|
4月前
|
前端开发 Java API
2025 年 Java 全栈从环境搭建到项目上线实操全流程指南:Java 全栈最新实操指南(2025 版)
本指南涵盖2025年Java全栈开发核心技术,从JDK 21环境搭建、Spring Boot 3.3实战、React前端集成到Docker容器化部署,结合最新特性与实操流程,助力构建高效企业级应用。
1293 1
|
2月前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
3月前
|
IDE 安全 Java
Lombok 在企业级 Java 项目中的隐性成本:便利背后的取舍之道
Lombok虽能简化Java代码,但其“魔法”特性易破坏封装、影响可维护性,隐藏调试难题,且与JPA等框架存在兼容风险。企业级项目应优先考虑IDE生成、Java Records或MapStruct等更透明、稳健的替代方案,平衡开发效率与系统长期稳定性。
181 1
|
3月前
|
消息中间件 人工智能 Java
抖音微信爆款小游戏大全:免费休闲/竞技/益智/PHP+Java全筏开源开发
本文基于2025年最新行业数据,深入解析抖音/微信爆款小游戏的开发逻辑,重点讲解PHP+Java双引擎架构实战,涵盖技术选型、架构设计、性能优化与开源生态,提供完整开源工具链,助力开发者从理论到落地打造高留存、高并发的小游戏产品。
|
3月前
|
存储 小程序 Java
热门小程序源码合集:微信抖音小程序源码支持PHP/Java/uni-app完整项目实践指南
小程序已成为企业获客与开发者创业的重要载体。本文详解PHP、Java、uni-app三大技术栈在电商、工具、服务类小程序中的源码应用,提供从开发到部署的全流程指南,并分享选型避坑与商业化落地策略,助力开发者高效构建稳定可扩展项目。
|
3月前
|
存储 Java 关系型数据库
Java 项目实战基于面向对象思想的汽车租赁系统开发实例 汽车租赁系统 Java 面向对象项目实战
本文介绍基于Java面向对象编程的汽车租赁系统技术方案与应用实例,涵盖系统功能需求分析、类设计、数据库设计及具体代码实现,帮助开发者掌握Java在实际项目中的应用。
133 0
|
4月前
|
JavaScript 安全 前端开发
Java开发:最新技术驱动的病人挂号系统实操指南与全流程操作技巧汇总
本文介绍基于Spring Boot 3.x、Vue 3等最新技术构建现代化病人挂号系统,涵盖技术选型、核心功能实现与部署方案,助力开发者快速搭建高效、安全的医疗挂号平台。
242 3
|
4月前
|
安全 Java 数据库
Java 项目实战病人挂号系统网站设计开发步骤及核心功能实现指南
本文介绍了基于Java的病人挂号系统网站的技术方案与应用实例,涵盖SSM与Spring Boot框架选型、数据库设计、功能模块划分及安全机制实现。系统支持患者在线注册、登录、挂号与预约,管理员可进行医院信息与排班管理。通过实际案例展示系统开发流程与核心代码实现,为Java Web医疗项目开发提供参考。
229 2