当前位置: 首页 > news >正文

Java项目—— 拼图小游戏(进阶版)

项目需求

在拼图小游戏基础版的基础上,完成下列要求:

一、实现更换拼图图片功能

1,给美女,动物,运动菜单按钮添加单击事件(动作监听)

2,当我们点击了美女之后,就会从13组美女图片中随机选择一组。

3,当我们点击了动物之后,就会从8组动物图片中随机选择一组。

4,当我们点击了运动之后,就会从10组运动图片中随机选择一组。

5,细节1:更换完毕之后,游戏界面中需要加载所有的小图片并且打乱顺序

6,细节2:更换完毕之后,查看全图的功能显示的是更换后图片的全图

二、完成登录界面

1,界面搭建。

2,用静态代码块准备一些初始的用户信息

3,点击登录按钮之后的逻辑:

  • 按下登录不松,切换登录按钮的深色背景图片

  • 松开登录按钮,逻辑较为复杂

    • 获取用户输入的用户名,密码,验证码。

    • 比较验证码    提示正确、错误

    • 判断用户名和密码是否为空,只要有一个为空就不行

      • 细节:如果用户没有输入用户名和密码,在代码中获取的不是null,而是长度为0的字符串

      • 为空时,提示用户名和密码为空

    • 用户名,密码比较正确,跳转游戏界面

    • 用户名,密码比较错误,提示错误

4,提示全部以弹窗的形式提出

5,点击注册按钮之后的逻辑

  • 暂时不需要写逻辑,后面学习完IO的时候再补

6,点击验证码字符串后

  • 更换一个新的验证码(写一个工具类提供验证码)


分析 

一、实现更换拼图图片功能

在这个界面中,我们需要哪些技术点:

整个的菜单就是JMenuBar

功能,关于我们:JMenu

更换图片:JMenu

重新游戏,重新登录,关闭游戏,美女,动物,运动:JMenuItem

特点:如果在菜单中,还需要嵌套二级的菜单,那么可以用JMenu完成。JMenu里面是可以再次添加其他的JMenu的。

写代码的时候如何实现:

第一步:创建JMenuBar对象
第二步:创建三个JMenu对象(功能,关于我们,更换图片)
第三步:创建六个JMenuItem对象(重新游戏,重新登录,关闭游戏,美女,动物,运动)
第四步:把美女,动物,运动放到更换图片当中
第五步:把更换图片,重新游戏,重新登录,关闭游戏放到功能当中
第六步:把功能,关于我们放到JMenuBar
第七步:把JMenuBar放到整个界面当中

二、完成登录界面

所需要的技术点

1.用户名文字其实是一张图片,还是用JLabel去管理ImageIcon

        用户名输入框:JTextField(明文显示的输入框)

2.密码文字其实是一张图片,还是用JLabel去管理ImageIcon

        密码输入框:JPasswordField(密文显示的输入框)

3.验证码文字其实是一张图片,还是用JLabel去管理ImageIcon

        验证码输入框:JTextField(明文显示的输入框)

4.验证码wyS7i:用JLabel去管理文字,需要自己写一个生成验证码的工具类。

5.登录与注册两个都是按钮,当点击按钮不松的时候,按钮变灰,其实就是换一个深色的背景图。


代码实现 

App类

public class App {public static void main(String[] args) {//创建登录界面,在登录界面中成功登录后创建游戏界面new LoginJFrame();}
}

 登录界面类

import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;public class LoginJFrame extends JFrame implements MouseListener {//不止一个方法使用的变量定义在成员变量位置JButton login;JButton register;JTextField username;JTextField password;JTextField code;String codeStr;JLabel showCode;JDialog jDialog;static ArrayList<User> list = new ArrayList();//用静态代码块准备一些初始的用户信息,目前不写注册功能,用初始信息登录static {User u1 = new User("zhangsan", "123456");User u2 = new User("lisi", "12345678");list.add(u1);list.add(u2);}//空参构造初始化登录public LoginJFrame() {//调用方法初始化登录界面initFrame();//调用方法加载登录界面图式loadImages();//添加事件监听,鼠标监听事件MouseListenerlogin.addMouseListener(this);register.addMouseListener(this);showCode.addMouseListener(this);//设置界面可视,建议放在最后this.setVisible(true);}//定义方法加载登录界面图式private void loadImages() {//1. 添加用户名文字JLabel usernameText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\用户名.png"));usernameText.setBounds(116, 135, 47, 17);this.getContentPane().add(usernameText);//2.添加用户名输入框username = new JTextField();username.setBounds(195, 134, 200, 30);this.getContentPane().add(username);//3.添加密码文字JLabel passwordText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\密码.png"));passwordText.setBounds(130, 195, 32, 16);this.getContentPane().add(passwordText);//4.密码输入框password = new JTextField();password.setBounds(195, 195, 200, 30);this.getContentPane().add(password);//验证码提示JLabel codeText = new JLabel(new ImageIcon("puzzlegame\\image\\login\\验证码.png"));codeText.setBounds(133, 256, 50, 30);this.getContentPane().add(codeText);//验证码的输入框code = new JTextField();code.setBounds(195, 256, 100, 30);this.getContentPane().add(code);//调用工具类生成验证码codeStr = CodeUtil.getCode();//显示生成的验证码showCode = new JLabel();//设置内容showCode.setText(codeStr);//位置和宽高showCode.setBounds(300, 256, 50, 30);//添加到界面this.getContentPane().add(showCode);//5.添加登录按钮login = new JButton();login.setBounds(123, 310, 128, 47);//设置按钮背景图login.setIcon(new ImageIcon("puzzlegame\\image\\login\\登录按钮.png"));//去除按钮的默认边框login.setBorderPainted(false);//去除按钮的默认背景login.setContentAreaFilled(false);this.getContentPane().add(login);//6.添加注册按钮register = new JButton();register.setBounds(256, 310, 128, 47);//设置按钮背景图register.setIcon(new ImageIcon("puzzlegame\\image\\login\\注册按钮.png"));//去除按钮的默认边框register.setBorderPainted(false);//去除按钮的默认背景register.setContentAreaFilled(false);this.getContentPane().add(register);//7.添加界面背景图片JLabel background = new JLabel(new ImageIcon("puzzlegame\\image\\login\\background.png"));background.setBounds(0, 0, 470, 390);this.getContentPane().add(background);}//定义方法初始化登录界面private void initFrame() {this.setSize(488, 430);this.setTitle("拼图游戏登录");this.setAlwaysOnTop(true);this.setLocationRelativeTo(null);this.setDefaultCloseOperation(3);this.setLayout(null);}//定义方法判断用户名密码是否正确private boolean checkUser(ArrayList<User> list, User u) {int index = checkUserName(list, u);if (index == -1) {//System.out.println("用户名和密码错误");return false;}//到这步,证明用户名存在,判断对应的密码是否相同if (list.get(index).getPassWord().equals(u.getPassWord())) {//相同返回truereturn true;}//不同返回falsereturn false;}//定义方法查询用户名是否在集合中存在,存在返回索引,不存在返回-1private int checkUserName(ArrayList<User> list, User u) {for (int i = 0; i < list.size(); i++) {if (list.get(i).getUserName().equals(u.getUserName())) {return i;}}return -1;}//定义方法展示弹窗private void showDialog(String s) {jDialog = new JDialog();//设置弹框的宽和高:100,100jDialog.setSize(100, 100);//设置弹框居中jDialog.setLocationRelativeTo(null);//设置弹框置顶jDialog.setAlwaysOnTop(true);//设置关闭后进行其他操作jDialog.setModal(true);//创建一个JLabel去编写文本内容JLabel textJlabel = new JLabel(s);textJlabel.setBounds(20, 50, 120, 60);//把文本JLabel添加到弹框当中jDialog.getContentPane().add(textJlabel);//把弹框展示出来jDialog.setVisible(true);}//鼠标监听事件MouseListener//鼠标单击调用该方法@Overridepublic void mouseClicked(MouseEvent e) {Object source = e.getSource();if (source == login) {//如果是登录按钮,获取输入框中的用户名,密码,验证码String myUserName = username.getText();String myPassWord = password.getText();String myCode = code.getText();//判断是否为空,如果为空,提示:用户名或密码为空if (myUserName.equals("") || myPassWord.equals("")) {//展示弹框:用户名或密码为空//调用方法展示弹框,参数为需要展示的文字showDialog("用户名或密码为空");//换一个验证码codeStr = CodeUtil.getCode();showCode.setText(codeStr);return;}//判断验证码是否正确if (!(myCode.equalsIgnoreCase(codeStr))) {//展示弹框:验证码错误showDialog("验证码错误");System.out.println("验证码错误");//换一个验证码codeStr = CodeUtil.getCode();showCode.setText(codeStr);return;}//判断用户名和密码是否为正确,如果正确隐藏登录界面,进入游戏界面。//调用方法判断User myUser = new User(myUserName, myPassWord);boolean flag = checkUser(list, myUser);if (!flag) {//展示弹框:用户名或密码错误showDialog("用户名或密码错误");System.out.println("用户名或密码错误");//换一个验证码codeStr = CodeUtil.getCode();showCode.setText(codeStr);return;}//到这步,证明用户名和密码正确//隐藏登录界面,进入游戏界面this.setVisible(false);new GameJFrame();} else if (source == showCode) {//重新生成验证码codeStr = CodeUtil.getCode();showCode.setText(codeStr);}}//鼠标按下调用该方法@Overridepublic void mousePressed(MouseEvent e) {Object source = e.getSource();if (source == login) {//登录按钮//按下不松的时候利用setIcon方法,修改登录按钮的背景色login.setIcon(new ImageIcon("PuzzleGame\\image\\login\\登录按下.png"));} else if (source == register) {//注册按钮//按下不松的时候利用setIcon方法,修改注册按钮的背景色register.setIcon(new ImageIcon("PuzzleGame\\image\\login\\注册按下.png"));}}//鼠标释放调用该方法@Overridepublic void mouseReleased(MouseEvent e) {Object source = e.getSource();//登录按钮//释放的时候利用setIcon方法,恢复登录按钮的背景色if (source == login) {login.setIcon(new ImageIcon("PuzzleGame\\image\\login\\登录按钮.png"));} else if (source == register) {//注册按钮//释放的时候利用setIcon方法,恢复注册按钮的背景色register.setIcon(new ImageIcon("PuzzleGame\\image\\login\\注册按钮.png"));}}//鼠标划入调用该方法@Overridepublic void mouseEntered(MouseEvent e) {}//鼠标划出调用该方法@Overridepublic void mouseExited(MouseEvent e) {}}

游戏界面类

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 {//多个方法需要用到的变量,记录在成员变量的位置//定义二维数组记录打乱后的0~15,每一个数字对应一张拼图int data[][] = new int[4][4];//定义胜利时的数据数组int[][] winArr = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},{13, 14, 15, 0}};//定义坐标记录0的位置int x = 0;int y = 0;//定义计数器记录移动步数int stepCount = 0;//创建菜单选项里下面的条目JMenuItem restartItem = new JMenuItem("重新开始");JMenuItem reLoginItem = new JMenuItem("重新登录");JMenuItem exitItem = new JMenuItem("退出游戏");JMenuItem animalItem = new JMenuItem("动物");JMenuItem girllItem = new JMenuItem("美女");JMenuItem sportItem = new JMenuItem("运动");JMenuItem AccountItem = new JMenuItem("公众号");//定义图片路径,方便后面修改String path = "PuzzleGame\\image\\animal\\animal1\\";Random r = new Random();//空参构造初始化游戏public GameJFrame() {//调用方法初始化界面initFrame();//给界面添加事件监听,键盘监听KeyListenerthis.addKeyListener(this);//调用方法添加菜单initMenu();//给菜单里的条目添加事件监听,动作监听ActionListenerrestartItem.addActionListener(this);reLoginItem.addActionListener(this);exitItem.addActionListener(this);AccountItem.addActionListener(this);animalItem.addActionListener(this);girllItem.addActionListener(this);sportItem.addActionListener(this);//调用方法初始化数据initData();//调用方法根据初始化后的数据加载图片loadImages();//设置界面可视,建议放在最后this.setVisible(true);}//定义方法判断游戏是否胜利private boolean victoty() {for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {if (data[i][j] != winArr[i][j]) {//data中的数据有一个与胜利数组中的数据不同,就说明没有胜利return false;}}}return true;}//定义方法根据初始化后的数据加载图片private void loadImages() {//清空所有图片this.getContentPane().removeAll();//如果胜利,加载胜利图标if (victoty()) {JLabel vicJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\win.png"));vicJLabel.setBounds(203, 283, 197, 73);this.getContentPane().add(vicJLabel);}//加载计数器JLabel countJLabel = new JLabel("步数:" + stepCount);countJLabel.setBounds(50, 30, 100, 20);this.getContentPane().add(countJLabel);//利用循环加载拼图图片for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {//获得data数组里的数据int number = data[i][j];//根据数据创建图片对象ImageIcon icon = new ImageIcon(path + number + ".jpg");//创建管理容器,将图片交给管理容器JLabel jLabel = new JLabel(icon);//设置管理容器位置,大小jLabel.setBounds(105 * j + 83, 105 * i + 134, 105, 105);//设置边框jLabel.setBorder(new BevelBorder(0));//将管理容器添加到界面中this.getContentPane().add(jLabel);}}//添加背景图片JLabel bgJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\background.png"));bgJLabel.setBounds(40, 40, 508, 560);this.getContentPane().add(bgJLabel);//刷新一下this.getContentPane().repaint();}//定义方法初始化数据private void initData() {int[] tempArr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};Random r = new Random();//打乱数据,根据打乱后的数据就能实现打乱拼图for (int i = 0; i < tempArr.length; i++) {int index = r.nextInt(tempArr.length);int temp = tempArr[i];tempArr[i] = tempArr[index];tempArr[index] = temp;}//将打乱后的数据记录在二维数组data中for (int i = 0; i < tempArr.length; i++) {//如果是0,记录0的位置if (tempArr[i] == 0) {x = i / 4;y = i % 4;}data[i / 4][i % 4] = tempArr[i];}}//定义方法添加菜单private void initMenu() {//创建菜单JMenuBar jMenuBar = new JMenuBar();//创建菜单的选项JMenu functionJmenu = new JMenu("功能");JMenu aboutJmenu = new JMenu("关于我们");//嵌套二级菜单,JMenu里面是可以再次添加其他的JMenuJMenu updateJmenu = new JMenu("更换图片");updateJmenu.add(animalItem);updateJmenu.add(girllItem);updateJmenu.add(sportItem);functionJmenu.add(updateJmenu);//将条目添加到选项中functionJmenu.add(restartItem);functionJmenu.add(reLoginItem);functionJmenu.add(exitItem);aboutJmenu.add(AccountItem);//将选项添加到菜单中jMenuBar.add(functionJmenu);jMenuBar.add(aboutJmenu);//将菜单添加到界面中this.setJMenuBar(jMenuBar);}//定义方法初始化界面private void initFrame() {//设置大小this.setSize(603, 680);//设置标题this.setTitle("拼图游戏");//设置居中this.setLocationRelativeTo(null);//设置置顶this.setAlwaysOnTop(true);//设置关闭模式this.setDefaultCloseOperation(3);//设置解除默认居中放置,只有解除了,才能根据xy轴的方式添加主件this.setLayout(null);}//动作监听ActionListener,鼠标单击或按空格调用该方法@Overridepublic void actionPerformed(ActionEvent e) {Object source = e.getSource();if (source == restartItem) {//重新开始//重新初始化数据initData();//计数器归0stepCount = 0;//重新根据初始化后的数据加载图片loadImages();} else if (source == reLoginItem) {//重新登录//关闭本类(游戏类)this.setVisible(false);//创建登录界面new LoginJFrame();} else if (source == exitItem) {//退出游戏System.exit(0);} else if (source == AccountItem) {//显示公众号//创建弹窗JDialog accJDialog = new JDialog();//加载弹窗中的图片JLabel aboutJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\about.png"));aboutJLabel.setBounds(0, 0, 258, 258);//将图片添加到弹窗中accJDialog.getContentPane().add(aboutJLabel);//设置弹窗的大小accJDialog.setSize(344, 344);//设置弹窗置顶accJDialog.setAlwaysOnTop(true);//设置弹窗居中放置accJDialog.setLocationRelativeTo(null);//设置关闭后进行其他操作accJDialog.setModal(true);//设置弹窗可视accJDialog.setVisible(true);} else if (source == animalItem) {//随机更换动物图片int rAnimalNum = r.nextInt(8) + 1;path = "PuzzleGame\\image\\animal\\animal" + rAnimalNum + "\\";//重新初始化数据initData();//计数器归0stepCount = 0;//重新根据初始化后的数据加载图片loadImages();} else if (source == girllItem) {//随机更换美女图片int rGirlNum = r.nextInt(13) + 1;path = "PuzzleGame\\image\\girl\\girl" + rGirlNum + "\\";//重新初始化数据initData();//计数器归0stepCount = 0;//重新根据初始化后的数据加载图片loadImages();} else if (source == sportItem) {//随机更换运动图片int rSportlNum = r.nextInt(10) + 1;path = "PuzzleGame\\image\\sport\\sport" + rSportlNum + "\\";//重新初始化数据initData();//计数器归0stepCount = 0;//重新根据初始化后的数据加载图片loadImages();}}//键盘监听KeyListener//该方法基本不使用@Overridepublic void keyTyped(KeyEvent e) {}//长按键盘时调用该方法@Overridepublic void keyPressed(KeyEvent e) {//判断是否胜利if (victoty()) {//如果胜利,禁止进行显示全图操作,直接结束方法return;}//长按w显示全图int keyCode = e.getKeyCode();if (keyCode == 87) {//清空所有图片this.getContentPane().removeAll();//加载计数器JLabel countJLabel = new JLabel("步数:" + stepCount);countJLabel.setBounds(50, 30, 100, 20);this.getContentPane().add(countJLabel);//加载全图JLabel picJLabel = new JLabel(new ImageIcon(path + "all.jpg"));picJLabel.setBounds(83, 134, 420, 420);this.getContentPane().add(picJLabel);//添加背景图片JLabel bgJLabel = new JLabel(new ImageIcon("PuzzleGame\\image\\background.png"));bgJLabel.setBounds(40, 40, 508, 560);this.getContentPane().add(bgJLabel);//刷新一下this.getContentPane().repaint();}}//按下并松开键盘时调用该方法@Overridepublic void keyReleased(KeyEvent e) {//判断是否胜利if (victoty()) {//如果胜利,禁止进行移动操作,直接结束方法return;}int keyCode = e.getKeyCode();if (keyCode == 37) {//判断是否到了最左边if (y == 0) {//如果到了最左边,不能进行向左,直接结束方法return;}//没到最左边,进行下面的操作System.out.println("向左");//更改data数组里的数据data[x][y] = data[x][y - 1];data[x][y - 1] = 0;//更改0的坐标y--;//步数加1stepCount++;//按照此数据重新加载图片loadImages();} else if (keyCode == 38) {//判断是否到了最上边if (x == 0) {//如果到了最上边,不能进行向上,直接结束方法return;}//没到最上边,进行下面的操作System.out.println("向上");//更改data数组里的数据data[x][y] = data[x - 1][y];data[x - 1][y] = 0;//更改0的坐标x--;//步数加1stepCount++;//按照此数据重新加载图片loadImages();} else if (keyCode == 39) {//判断是否到了最右边if (y == 3) {//如果到了最右边,不能进行向右,直接结束方法return;}//没到最右边,进行下面的操作System.out.println("向右");//更改data数组里的数据data[x][y] = data[x][y + 1];data[x][y + 1] = 0;//更改0的坐标y++;//步数加1stepCount++;//按照此数据重新加载图片loadImages();} else if (keyCode == 40) {//判断是否到了最下边if (x == 3) {//如果到了最下边,不能进行向下,直接结束方法return;}//没到最下边,进行下面的操作System.out.println("向下");//更改data数组里的数据data[x][y] = data[x + 1][y];data[x + 1][y] = 0;//更改0的坐标x++;//步数加1stepCount++;//按照此数据重新加载图片loadImages();} else if (keyCode == 87) {//松开w恢复原状loadImages();} else if (keyCode == 65) {//一键通过for (int i = 0; i < data.length; i++) {for (int j = 0; j < data[i].length; j++) {data[i][j] = winArr[i][j];}}loadImages();}}}

生成验证码的工具类

 

import java.util.Random;public class CodeUtil {private CodeUtil(){}public static String getCode(){//定义StringBuilder方便拼接字符串StringBuilder sb = new StringBuilder();//记录a~z,A~Zchar[] ch = new char[52];for (int i = 0; i < ch.length; i++) {if (i < 26) {ch[i] = (char) ('a' + i);} else {ch[i] = (char) ('A' + i - 26);}}Random r = new Random();//随机抽取4个字母for (int i = 0; i < 4; i++) {int index = r.nextInt(ch.length);char randomCh = ch[index];//拼接sb.append(randomCh);}//随机抽取1个字母int randomNum = r.nextInt(10);//拼接sb.append(randomNum);//数字可以位于随机位置,因此最后一位需要与随机位置交换char[] chars = sb.toString().toCharArray();int index = r.nextInt(chars.length);char temp = chars[chars.length-1];chars[chars.length-1] = chars[index];chars[index] = temp;return new String(chars);}}

用户类(封装用户名,密码)

public class User {private String userName;private String passWord;public User() {}public User(String userName, String passWord) {this.userName = userName;this.passWord = passWord;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassWord() {return passWord;}public void setPassWord(String passWord) {this.passWord = passWord;}
}

相关文章:

  • PowerBi中的Measure(度量值)如何理解和应用?
  • 数字化转型浪潮下,B端产品如何助力企业乘风破浪?
  • Android studio—socketIO库的emit与return的使用
  • JVM对象创建全过程
  • .net core 项目快速接入Coze智能体-开箱即用-第2节
  • langgraph框架之初识
  • AI 编程工具—如何在 Cursor 中集成使用 MCP工具
  • Banana Pi BPI-RV2 RISC-V 路由器开发板发售, 全球首款RISC-V路由器
  • STM32单片机入门学习——第41节: [12-1] Unix时间戳
  • SpringAI入门:对话机器人
  • docker 镜像
  • MySQL中高级语法
  • 解决 Spring Boot 多数据源环境下事务管理器冲突问题(非Neo4j请求标记了 @Transactional 尝试启动Neo4j的事务管理器)
  • polkitd服务无法启动导致docker无法启动问题解决
  • 海关总署广东:广东外贸一季度进出口2.14万亿元 同期增长4.2%
  • 2.2/Q2,Charls最新文章解读
  • 【Python爬虫基础篇】--2.模块解析
  • 07_Docker 资源限制
  • Jenkins的使用及Pipeline语法讲解
  • Android Studio 常见报错
  • 两名中国公民在墨尔本被海浪卷走,我领馆发文提醒
  • 工人日报社评:下放职称评审权,推动“以产聚才、以才兴产”
  • 龙光集团:21笔境内债重组方案已有2笔获投票通过