目录
前言
涉及知识点
准备工具
Java开发环境
图片资源
最终效果 ——需求分析
登录界面
功能描述
需求分析
功能需求
游戏主界面
功能描述
需求分析
功能需求
游戏菜单
游戏胜利界面
框架搭建
总结
编码
编码顺序
搭建App实现程序的入口
完成User用户类和CodeUtil工具类的搭建
创建User用户类
创建CodeUtil工具类
搭建登录界面
搭建游戏主界面
关于String变量
总结
顶置有项目源代码以及图片资源,可以自行下载
前言
在学习了Java的基础编程知识之后,制作一个简单的拼图小游戏是一个很好的实战项目,它不仅能帮助我们巩固所学的内容,还能进一步提升编程逻辑和界面设计能力。本文将带领大家一步步用Java创建一个功能完整的拼图小游戏。
涉及知识点
通过这个项目,我们将复习和应用以下编程基础知识:
- Java的面向对象编程:如何通过类和对象设计拼图的各个组件。
- 事件处理机制:如何响应用户的拖拽操作并实时更新拼图界面。
- 图形用户界面(GUI)编程:使用Java的Swing或JavaFX库创建用户友好的图形界面。
- 基本算法:如何打乱拼图并判断拼图是否完成。
其中详细的知识点如下表:
运算符 | 判断 |
循环 | 数组 |
字符串 | 集合 |
封装 | 继承 |
多态 | 接口 |
抽象类 | 内部类 |
虽然这个小游戏没有复杂的用户注册功能,但其核心逻辑和界面设计已经能充分展示Java在桌面应用开发中的强大能力。通过这篇博文,你不仅可以熟练掌握Java编程,还能收获成就感,看到一个亲手完成的小项目成形。
准备工具
Java开发环境
- JDK (Java Development Kit):确保你已经安装了最新的Java开发工具包(JDK),建议使用JDK 8或更高版本,因为它包含了编译和运行Java应用程序所需的所有工具。本文采用JDK17
- IDE (集成开发环境):选择一个适合的Java开发环境,比如:
- IntelliJ IDEA:功能强大,支持广泛的插件和代码自动补全。(推荐使用)
- Eclipse:老牌Java IDE,社区支持丰富,适合初学者。
- NetBeans:Oracle官方支持的IDE,内置很多Java工具,适合快速上手。
图片资源
- 你需要制作一些图片,将其切割成若干块作为拼图的碎片。可以使用任意图像编辑工具,如 Photoshop 或 在线切割工具,将图片切割为相同大小的几部分。
- 如果想要自己制作,准备好相应尺寸的照片,这里推荐一个图片剪切网站图片分割-九宫格切图 - 在线工具 (wqtool.com)
- 如果不想自己制作图片,本文上方的资源image文件夹内为大家准备好了所需的图片资源(图片来源:黑马程序员)
最终效果 ——需求分析
登录界面
功能描述
- 这是一个简单的拼图小游戏的登录界面,用户需要输入用户名、密码以及验证码来进行登录。界面上包含登录和注册(本文不做实现)按钮,分别提供用户登录和
新用户注册的功能。- 登录界面设计简洁,UI风格可爱,符合小游戏的整体风格。
需求分析
功能需求
- 用户输入
- 用户名:允许用户输入字母、数字等常见字符,用于标识登录用户。(不做输入限制)
- 密码:用于保护用户的账号安全,采用密文显示输入,防止他人窥视。
- 验证码:随机生成一个四个字母和一个数字的验证码显示在界面右侧,用户需要正确输入显示的字符才能继续。
- 按钮功能
- 登录按钮:
- 验证用户输入的用户名、密码是否正确。
- 校验验证码输入是否与显示的验证码匹配。
- 若匹配成功,进入游戏主界面。
- 若用户名或密码错误,提示错误信息,用户需重新输入。
- 注册按钮:(暂时不作实现)
- 验证码刷新
- 验证码生成需要是随机的,并在每次页面加载或用户点击验证码时重新生成。
- 如果验证码输入错误,提示错误信息,用户需重新输入。
游戏主界面
功能描述
- 该界面是拼图游戏的主游戏界面。游戏通过将图片切割成多个方块并随机打乱,玩家通过点击或拖动方块使图片复原。
- 游戏显示了一个4x4的拼图,其中一个空白区域允许方块移动。
- 顶部有一个功能菜单栏,包括“功能”和“关于作者”两个选项,便于玩家了解游戏信息。
- 左上角显示了玩家当前的操作步数,方便记录和优化游戏。
需求分析
功能需求
拼图逻辑
- 随机打乱:游戏开始时,图片应自动随机打乱成小块,保持一个空白块位置。打乱后的图片依然可被复原(不应是无解状态)。
- 拼图复原:玩家通过按下上下左右键与空白位置相邻的方块来移动该方块,最终目标是将所有方块移动到正确的位置,还原完整图片。
用户交互
- 移动方块:按下上下左右键移动空白位置周围的方块,方块应当移动到空白处。每次移动仅能操作空白区域周围的一个方块。
- 步数记录:游戏界面左上角记录玩家的操作步数,每次有效的方块移动应当增加步数计数。
功能菜单
- 功能菜单:提供不同的游戏设置或功能选项,如重新开始游戏、更改图片、重新登录、退出游戏。
- 关于作者:点击后可以显示关于游戏作者或团队的信息。
游戏结束检测
- 检测玩家是否成功完成拼图。一旦所有方块排列成完整的图片,游戏应提示玩家成功。
- 快捷键
- 长按A键:显示完整图片,松开改键后回到游戏界面。
- 按下W键:一键完成游戏。
游戏菜单
功能如图
游戏胜利界面
框架搭建
为了实现上述功能,我们先创建一个新的项目
进入新建好的项目,搭建如下项目框架
将image文件夹直接复制粘贴到puzzlegame模块下
框架搭建好了后,思路是不是清晰了很多呢?
总结
- 我们在GameJFrame中实现游戏的主界面搭建
- LoginJFrame中搭建登录界面及其功能
- RegisterJFrame实现注册界面及其功能搭建,本文不作实现
- 最后把这些类的内容集成到App中实现游戏程序的运行(封装思想)
下面我们就要来到最最最激动人心的环节了!准备好你颤抖的双手
编码
编码顺序
- 首先搭建App实现程序的入口
- 完成User用户类和CodeUtil工具类的搭建,方便后续登录界面搭建的使用
- 搭建登录界面
- 搭建游戏主界面
搭建App实现程序的入口
创建LoginJFrame对象,进入登录界面
实现代码:
import com.joe.ui.LoginJFrame;
public class App {
public static void main(String[] args) {
//创建登录界面
LoginJFrame loginJFrame = new LoginJFrame();
}
}
是不是超级简单呢!那下面我们将逐渐加大难度~
完成User用户类和CodeUtil工具类的搭建
创建User用户类
类中定义了两个私有属性
username
(用户名)和password
(密码)
实现代码:
package com.joe.ui;
public class User {
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
/**
* 获取
* @return username
*/
public String getUsername() {
return username;
}
/**
* 设置
* @param username
*/
public void setUsername(String username) {
this.username = username;
}
/**
* 获取
* @return password
*/
public String getPassword() {
return password;
}
/**
* 设置
* @param password
*/
public void setPassword(String password) {
this.password = password;
}
}
创建CodeUtil工具类
在这个类中我们将随机生成一个5位的验证码,包含4个字母(包含大小写)以及一个数字,排列位置随机(如:WDq6a)
- 该方法的实现涉及静态方法、循环、集合、StringBuilder容器、生成随机数、变量数据交换、String字符串构造方法的内容,非常适合锻炼之前学习过的知识点
实现代码:
package com.joe.ui;
import java.util.ArrayList;
import java.util.Random;
public class CodeUtil {
public static String getCode() {
//创建一个集合容器存放字母
ArrayList<Character> list = new ArrayList<>();
//将小写英文字母存放进集合中
for (int i = 0; i < 26; i++) {
list.add((char)('a' + i));
}
//将大写英文字母存放进集合中
for (int i = 0; i < 26; i++) {
list.add((char)('A' + i));
}
//新建一个随机类
Random r = new Random();
//创建一个容器拼接字符串
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 4; i++) {
//调用随机类方法生成随机索引
int index = r.nextInt(list.size());
//拼接到容器
sb.append(list.get(index));
}
//最后生成一个数字
int num = r.nextInt(10);
//char n = (char)(num+48);
sb.append(num);//拼接会把数字转换成字符串
//把字符串变成数组,将数字打乱顺序
char[] c = sb.toString().toCharArray();
int newIndex = r.nextInt(c.length);
char temp = c[newIndex];
c[newIndex] = c[c.length-1];
c[c.length-1] = temp;
return new String(c);//参考String的构造方法
}
}
下面我们将继续搭建游戏登录界面,难度开始有提升了,但是不要放弃哦!
搭建登录界面
由于没有注册功能,在此类中,我们添加两个静态代码块,实现用户数据的初始化,在这里你可以手动提供你自己与好朋友的账号
该界面及其功能的实现,涉及了封装、接口、多态等知识点
实现代码:
package com.joe.ui;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
public class LoginJFrame extends JFrame implements MouseListener {
//初始用户
static ArrayList<User> allUsers = new ArrayList<>();
static {
allUsers.add(new User("乔没乔见","123"));
allUsers.add(new User("sunshi","123"));
allUsers.add(new User("yulu","123"));
allUsers.add(new User("leyu","123"));
allUsers.add(new User("jixin","123"));
allUsers.add(new User("yongzhao","123"));
}
//创建登录按钮
JButton login = new JButton();
//创建注册按钮
JButton register = new JButton();
//创建用户名输入栏
JTextField username = new JTextField();
//创建密码输入栏
JPasswordField password = new JPasswordField();
//创建验证码输入栏
JTextField code = new JTextField();
//正确的验证码容器
JLabel rightCode = new JLabel();
//核心:构造方法(无参)
public LoginJFrame() {
//初始化界面
initJFrame();
//在这个界面中添加内容
initView();
//让当前界面显示出来
this.setVisible(true);
}
//在这个界面中添加内容
public void initView() {
//1. 添加用户名文字
JLabel usernameText = new JLabel(new ImageIcon("D:\\PersonalFile\\javaProject\\puzzlegame\\image\\login\\用户名.png"));
usernameText.setBounds(116, 135, 47, 17);
this.getContentPane().add(usernameText);
//添加用户名输入框
username.setBounds(195, 134, 200, 30);
this.getContentPane().add(username);
//2.添加密码文字
JLabel passwordText = new JLabel(new ImageIcon("D:\\PersonalFile\\javaProject\\puzzlegame\\image\\login\\密码.png"));
passwordText.setBounds(130, 195, 32, 16);
this.getContentPane().add(passwordText);
//密码输入框
password.setBounds(195, 195, 200, 30);
this.getContentPane().add(password);
//3.添加验证码提示
JLabel codeText = new JLabel(new ImageIcon("D:\\PersonalFile\\javaProject\\puzzlegame\\image\\login\\验证码.png"));
codeText.setBounds(133, 256, 50, 30);
this.getContentPane().add(codeText);
//验证码的输入框
code.setBounds(195, 256, 100, 30);
this.getContentPane().add(code);
//获取验证码
String codeStr = CodeUtil.getCode();
//设置内容
rightCode.setText(codeStr);
//绑定鼠标事件
rightCode.addMouseListener(this);
//位置和宽高
rightCode.setBounds(300, 256, 50, 30);
//添加到界面
this.getContentPane().add(rightCode);
//4.添加登录按钮
login.setBounds(123, 310, 128, 47);
login.setIcon(new ImageIcon("D:\\PersonalFile\\javaProject\\puzzlegame\\image\\login\\登录按钮.png"));
//去除按钮的边框
login.setBorderPainted(false);
//去除按钮的背景
login.setContentAreaFilled(false);
//给登录按钮绑定鼠标事件
login.addMouseListener(this);
//把按钮添加到背景中
this.getContentPane().add(login);
//5.添加注册按钮
register.setBounds(256, 310, 128, 47);
register.setIcon(new ImageIcon("D:\\PersonalFile\\javaProject\\puzzlegame\\image\\login\\注册按钮.png"));
//去除按钮的边框
register.setBorderPainted(false);
//去除按钮的背景
register.setContentAreaFilled(false);
//给注册按钮绑定鼠标事件
register.addMouseListener(this);
//把按钮添加到背景中
this.getContentPane().add(register);
//7.添加背景图片
JLabel background = new JLabel(new ImageIcon("D:\\PersonalFile\\javaProject\\puzzlegame\\image\\login\\background.png"));
background.setBounds(0, 0, 470, 390);
this.getContentPane().add(background);
}
//初始化界面(窗口)
public void initJFrame() {
this.setSize(488, 430);//设置宽高
this.setTitle("Joe拼图游戏 V1.0登录");//设置标题
this.setDefaultCloseOperation(3);//设置关闭模式
this.setLocationRelativeTo(null);//居中
this.setAlwaysOnTop(true);//置顶
this.setLayout(null);//取消内部默认布局
}
//鼠标点击
@Override
public void mouseClicked(MouseEvent e) {
//登录按钮
if (e.getSource() == login) {
System.out.println("点击了登录按钮");
//获取两个文本输入框中的内容
String usernameInput = username.getText();
String passwordInput = password.getText();
//获取用户输入的验证码
String codeInput = code.getText();
//创建一个User对象
User userInfo = new User(usernameInput, passwordInput);
System.out.println("用户输入的用户名为" + usernameInput);
System.out.println("用户输入的密码为" + passwordInput);
//输入内容为空(如果没有输入,代码中获取的是长度为0的字符串,不是null)
if (codeInput.length() == 0) {
//调用showJDialog方法并展示弹框
showJDialog("验证码不能为空");
} else if (usernameInput.length() == 0 || passwordInput.length() == 0) {
//校验用户名和密码是否为空
System.out.println("用户名或者密码为空");
//调用showJDialog方法并展示弹框
showJDialog("用户名或者密码为空");
} else if (!codeInput.equalsIgnoreCase(rightCode.getText())) {
showJDialog("验证码输入错误");
} else if (contains(userInfo)) {
System.out.println("用户名和密码正确可以开始玩游戏了");
//关闭当前登录界面
this.setVisible(false);
//打开游戏的主界面
//需要把当前登录的用户名传递给游戏界面
new GameJFrame();
} else {
System.out.println("用户名或密码错误");
showJDialog("用户名或密码错误");
}
} else if (e.getSource() == register) {
System.out.println("点击了注册按钮");
} else if (e.getSource() == rightCode) {
System.out.println("更换验证码");
//获取一个新的验证码
String code = CodeUtil.getCode();
rightCode.setText(code);
}
}
public void showJDialog(String content) {
//创建一个弹框对象
JDialog jDialog = new JDialog();
//给弹框设置大小
jDialog.setSize(200, 150);
//让弹框置顶
jDialog.setAlwaysOnTop(true);
//让弹框居中
jDialog.setLocationRelativeTo(null);
//弹框不关闭永远无法操作下面的界面
jDialog.setModal(true);
//创建Jlabel对象管理文字并添加到弹框当中
JLabel warning = new JLabel(content);
warning.setBounds(0, 0, 200, 150);
jDialog.getContentPane().add(warning);
//让弹框展示出来
jDialog.setVisible(true);
}
//按下不松
@Override
public void mousePressed(MouseEvent e) {
if (e.getSource() == login) {
login.setIcon(new ImageIcon("D:\\PersonalFile\\javaProject\\puzzlegame\\image\\login\\登录按下.png"));
} else if (e.getSource() == register) {
register.setIcon(new ImageIcon("D:\\PersonalFile\\javaProject\\puzzlegame\\image\\login\\注册按下.png"));
}
}
//松开按钮
@Override
public void mouseReleased(MouseEvent e) {
if (e.getSource() == login) {
login.setIcon(new ImageIcon("D:\\PersonalFile\\javaProject\\puzzlegame\\image\\login\\登录按钮.png"));
} else if (e.getSource() == register) {
register.setIcon(new ImageIcon("D:\\PersonalFile\\javaProject\\puzzlegame\\image\\login\\注册按钮.png"));
}
}
//鼠标划入
@Override
public void mouseEntered(MouseEvent e) {
}
//鼠标划出
@Override
public void mouseExited(MouseEvent e) {
}
//判断用户在集合中是否存在
public boolean contains(User userInput){
for (int i = 0; i < allUsers.size(); i++) {
User rightUser = allUsers.get(i);
if(userInput.getUsername().equals(rightUser.getUsername()) && userInput.getPassword().equals(rightUser.getPassword())){
//有相同的代表存在,返回true,后面的不需要再比了
return true;
}
}
//循环结束之后还没有找到就表示不存在
return false;
}
}
搭建游戏主界面 (含胜利界面)
在这个类的搭建中,我们将实现游戏的核心功能以及游戏菜单的制作
难度有点大,代码量也很大,代码中有详细的注释,如果没有头绪可以仔细阅读一遍代码
实现代码:
package com.joe.ui;
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 {
int[][] newArr = new int[4][4];//方便initImages()方法中能使用这个二维数组
//创建一个顺序二维数组,用来判断游戏胜利
int[][] winArr = new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
int x; int y;//记录空格位置的二位索引值(地址)
int step = 0;//创建一个数字记录游戏步数
//创建一个JMenuItem选项的条目对象
JMenuItem jMenuItem1 = new JMenuItem("重新游戏");
JMenuItem jMenuItem2 = new JMenuItem("重新登录");
JMenuItem jMenuItem3 = new JMenuItem("关闭游戏");
JMenuItem jMenuItem4 = new JMenuItem("简介");
JMenuItem jMenuItem5 = new JMenuItem("动物");
JMenuItem jMenuItem6 = new JMenuItem("美女");
JMenuItem jMenuItem7 = new JMenuItem("运动");
JMenuItem jMenuItem8 = new JMenuItem("礼物");
//默认图片
String type = "animal";
int typeNum = 4;
//type 可以改变,因为它是一个变量,指向不同的字符串对象时只是改变了引用。
//path 不会自动更新,因为它是一个不可变字符串的组合,字符串一旦创建就不会自动反映其他变量的变化,必须手动更新。
//path 也是变量:它也是指向一个字符串对象。但它可能是用其他不可变对象(如字符串字面量)组合生成的。
String path = "..\\puzzlegame\\image\\"+type+"\\" + type + typeNum + "\\";
String path2 = "..\\puzzlegame\\image\\";
//创建一个Random类
Random r = new Random();
//无参构造方法
public GameJFrame(){
//初始化界面
initJFrame();
//初始化菜单
initJMenuBar();
//初始化数据(打乱数组)
initData();
//初始化图片(把打乱的数组安插进图片以及胜利图片、游戏步数展示)
initImages();
System.out.println(x+" "+y);
//让界面显示出来--#必须在最后一行书写
this.setVisible(true);
}
//打乱数据并添加到二维数组中
private void initData() {
//新建一个数组,填入16个数字
int[] arr = {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 < arr.length; i++) {
//接收随机变量
int index = r.nextInt(arr.length);
int temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
//按照四个一组的方法添加到二维数组当中
//创建一个二维数组
//定义一个计数器
int count = 0;
for (int i = 0; i < newArr.length; i++) {
for (int j = 0; j < newArr[i].length; j++) {
if (arr[count] == 0){
x = i;
y = j;
}
newArr[i][j] = arr[count];
count++;
}
}
}
//加载图片
private void initImages() {
//清空之前的图片
getContentPane().removeAll();
//判断胜利
if (winJudgment()){
//展示胜图片
JLabel winLabel = new JLabel(new ImageIcon(path2+"win.png"));
winLabel.setBounds(203,283,197,73);
getContentPane().add(winLabel);
}
//展示游戏步数
JLabel stepLabel = new JLabel("步数:" + step);
stepLabel.setBounds(50,30,100,20);
getContentPane().add(stepLabel);
//方法内越往上,显示的图层就越往上
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 4; i++) {
//接收打乱的数组值
int num = newArr[j][i];
//创建一个图片描述对象
//创建一个存储容器的对象,用来存储图片
JLabel jLabel1 = new JLabel(new ImageIcon(path + num + ".jpg"));
//设置图片放置坐标
jLabel1.setBounds(105 * i + 84,105*j + 134,105,105);
//给图片添加边框
//传入Border类型,其是个接口类
jLabel1.setBorder(new BevelBorder(0));
//将JLabel添加到界面(获取隐藏容器)
this.getContentPane().add(jLabel1);
}
}
//添加背景图片
JLabel jLabel = new JLabel(new ImageIcon(path2+"background.png"));
//设置背景图片位置
jLabel.setBounds(40,40,508,560);
//把背景图片添加到容器中
getContentPane().add(jLabel);
//刷新图片
getContentPane().repaint();
}
//创建菜单栏
private void initJMenuBar() {
//创建一个菜单栏对象
JMenuBar jMenuBar = new JMenuBar();
//创建JMenu选项对象(功能,关于作者)
JMenu jMenu1 = new JMenu("功能");
JMenu jMenu2 = new JMenu("关于作者");
JMenu jMenu3 = new JMenu("更换图片");
//将条目对象添加到选项中
jMenu1.add(jMenu3);
jMenu1.add(jMenuItem1);
jMenu1.add(jMenuItem2);
jMenu1.add(jMenuItem3);
jMenu2.add(jMenuItem4);
jMenu3.add(jMenuItem5);
jMenu3.add(jMenuItem6);
jMenu3.add(jMenuItem7);
jMenu3.add(jMenuItem8);
//再将选项对象添加到菜单中
jMenuBar.add(jMenu1);
jMenuBar.add(jMenu2);
//给整个界面设置菜单
this.setJMenuBar(jMenuBar);
}
//判断游戏是否胜利
private boolean winJudgment(){
//遍历newArr
for (int i = 0; i < newArr.length; i++) {
for (int j = 0; j < newArr[i].length; j++) {
if (newArr[i][j] != winArr[i][j]){
//存在不相等的情况
return false;
}
}
}
//完全匹配,游戏胜利
return true;
}
//设置界面
private void initJFrame() {
//设置界面宽高
this.setSize(603,680);
//设置标题
this.setTitle("Joe拼图单机版 v1.0");
//设置居中显示
this.setLocationRelativeTo(null);
//让界面总是在最上方显示
this.setAlwaysOnTop(true);
//界面关闭操作——当有一个界面点击关闭时结束运行
//(因为开发为一个窗口出现其他窗口隐藏)
this.setDefaultCloseOperation(3);
//取消隐藏容器默认居中放置
this.setLayout(null);
//添加键盘监听
addKeyListener(this);
//添加动作监听
jMenuItem1.addActionListener(this);
jMenuItem2.addActionListener(this);
jMenuItem3.addActionListener(this);
jMenuItem4.addActionListener(this);
jMenuItem5.addActionListener(this);
jMenuItem6.addActionListener(this);
jMenuItem7.addActionListener(this);
jMenuItem8.addActionListener(this);
}
@Override
public void keyTyped(KeyEvent e) {
}
//按下键盘
@Override
public void keyPressed(KeyEvent e) {
//按下图片的操作
//接收按下的键值
int code = e.getKeyCode();
if (code == 65){
//清空图片
getContentPane().removeAll();
//创建容器和图片,把图片放进容器
JLabel all = new JLabel(new ImageIcon(path + "all.jpg"));
//设置容器位置和大小
all.setBounds(83,134,420,420);
//把容器放进窗口
getContentPane().add(all);
//添加背景
JLabel jLabel = new JLabel(new ImageIcon("..\\puzzlegame\\image\\background.png"));
//设置背景图片位置
jLabel.setBounds(40,40,508,560);
//把背景图片添加到容器中
getContentPane().add(jLabel);
//刷新界面
getContentPane().repaint();
}
}
//松开键盘
@Override
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
if (code == 65) {
//展示完整图片后要回到原界面
initImages();
}
//如果胜利则不在执行
if (winJudgment()){
return;
}
if (code == 38){
if (x == 3){
//移动至尽头
return;
}
System.out.println("向上移动");
newArr[x][y] = newArr[x+1][y];
newArr[x+1][y] = 0;
x++;
step++;//得先添加步数再显示
initImages();
} else if (code == 40) {
if (x == 0){
//移动至尽头
return;
}
System.out.println("向下移动");
newArr[x][y] = newArr[x-1][y];
newArr[x-1][y] = 0;
x--;
step++;
initImages();
} else if (code == 37) {
if (y == 3){
//移动至尽头
return;
}
System.out.println("向左移动");
newArr[x][y] = newArr[x][y+1];
newArr[x][y+1] = 0;
y++;
step++;
initImages();
} else if (code == 39) {
if (y == 0){
//移动至尽头
return;
}
System.out.println("向右移动");
newArr[x][y] = newArr[x][y-1];
newArr[x][y-1] = 0;
y--;
step++;
initImages();
} else if (code == 87) {
//把数组顺序排列整齐
newArr = new int[][]{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,0}
};
x = 3;
y = 3;
initImages();
}
}
@Override
public void actionPerformed(ActionEvent e) {
//获取调用的对象
Object source = e.getSource();
if (source == jMenuItem1){
System.out.println("重新游戏");
//打乱数字
initData();
//重置步数
step = 0;
//重新加载图片
initImages();
} else if (source == jMenuItem2) {
System.out.println("重新登录");
//关闭当前对象
setVisible(false);
//创建一个登陆界面的对象
new LoginJFrame();
} else if (source == jMenuItem3) {
System.out.println("关闭游戏");
//直接关闭虚拟机
System.exit(0);
} else if (source == jMenuItem4) {
System.out.println("作者简介");
//创建一个弹窗对象
JDialog jDialog = new JDialog();
//创建容器和图片,把图片放进容器中
JLabel jLabel = new JLabel(new ImageIcon(path2+"about.png"));
//设置容器位置和大小
jLabel.setBounds(0,0,258,258);
//把容器放进弹窗中
jDialog.getContentPane().add(jLabel);
//设置弹窗大小
jDialog.setSize(344,344);
//置顶弹窗
jDialog.setAlwaysOnTop(true);
//居中放置
jDialog.setLocationRelativeTo(null);
//弹窗不关闭则无法进入其他操作
jDialog.setModal(true);
//显示弹窗
jDialog.setVisible(true);
} else if (source == jMenuItem5){
System.out.println("动物");
//修改路径值
type = "animal";
typeNum = r.nextInt(8)+1;
System.out.println(typeNum);
path = "..\\puzzlegame\\image\\" + type + "\\" + type + typeNum + "\\";
//重开
//打乱数字
initData();
//重置步数
step = 0;
//重新加载图片
initImages();
} else if (source == jMenuItem6) {
System.out.println("美女");
//修改路径值
type = "girl";
typeNum = r.nextInt(13)+1;
System.out.println(typeNum);
path = "..\\puzzlegame\\image\\" + type + "\\" + type + typeNum + "\\";
//重开
//打乱数字
initData();
//重置步数
step = 0;
//重新加载图片
initImages();
} else if (source == jMenuItem7) {
System.out.println("运动");
//修改路径值
type = "sport";
typeNum = r.nextInt(10)+1;
System.out.println(typeNum);
path = "..\\puzzlegame\\image\\" + type + "\\" + type + typeNum + "\\";
//重开
//打乱数字
initData();
//重置步数
step = 0;
//重新加载图片
initImages();
} else if (source == jMenuItem8) {
System.out.println("礼物");
//修改路径值
type = "present";
typeNum = r.nextInt(1)+1;
System.out.println(typeNum);
path = "..\\puzzlegame\\image\\" + type + "\\" + type + typeNum + "\\";
//重开
//打乱数字
initData();
//重置步数
step = 0;
//重新加载图片
initImages();
}
}
}
这样我们的游戏就完成制作啦!
但是在最后我们再做一个小拓展与提示点
关于String变量
在上述代码中,我们用String变量去浅入图片路径,改变图片的选择
如果我们通过菜单栏去更改图片,需要在动作监听的重写方法里重新写一遍path变量的赋值
因为path是String类型变量,字符串一旦赋值,不可修改,我们之所以能对其进行所谓的修改,只是其又创建了一个新的String对象,如下图所示:
为什么 type 可以被重新赋值而 path 不行呢?
- type 可以改变,因为它是一个变量,指向不同的字符串对象时只是改变了引用。
- path 不会自动更新,因为它是一个不可变字符串的组合,字符串一旦创建就不会自动反映其他变量的变化,必须手动更新。
- path 也是变量:它也是指向一个字符串对象。但它可能是用其他不可变对象(如字符串字面量)组合生成的。
因此,我们需要在动作监听的重写方法里重新写一遍path变量的赋值,这样路径才会改变,不然一直都会是成员位置定义的默认路径,点击更换图片后得不到想要的反应
总结
- 在这篇文章中,我们实现了如何使用Java开发一个拼图小游戏。
- 通过详细的需求分析和功能描述,我们逐步构建了游戏的各个界面,包括登录界面、游戏主界面、游戏菜单和胜利界面。文章不仅涵盖了游戏开发的框架搭建,还详细介绍了编码的过程和关键步骤。
- 从准备工具到实现程序的入口,再到创建用户类和工具类,本文全面展示了如何将游戏的各个功能模块逐一实现。
- 通过本项目,我们练习了Java编程中的关键技能。
心得体会
在编写这篇文章的过程中,我对Java编程有了更深刻的理解。拼图小游戏的开发不仅加深了我对Java语言的掌握,也提升了我在需求分析、框架搭建和功能实现方面的能力。每一步的编码和测试都是对编程技能的挑战和提升。
通过这个项目,我们认识到系统化地进行需求分析和功能规划的重要性。合理的框架搭建和清晰的编码顺序是成功实现功能的关键。此外,用户界面的设计也极大地影响了游戏的整体体验。这个项目不仅是一个编程练习,也是一个展示如何将复杂问题拆解并逐步解决的实践。
总的来说,这次拼图小游戏的开发经验让我们在实践中积累了宝贵的技能,并为未来的编程挑战奠定了坚实的基础。