一、团队介绍
团队名称:眼镜蛇快速行动小组
组员 | 职务 | 负责模块 |
孔德丞 | 组长 | 游戏逻辑设计 |
洪圣哲 | 组员 | 游戏ui设计 |
李云飞 | 组员 | 游戏登陆设计 |
蔡岳恒 | 组员 | 游戏注册设计 |
二、项目介绍
功能简介
本组的选题是PuzzleGame(拼图游戏),是一个益智的小游戏,可以实现登录,注册,选择游戏模式,可以对用户进行多个存档读档。首先玩家需要先注册账号进行登录,玩家可以挑选游戏风格,通过键盘可以查看该局游戏的还原图片,系统还可以实现判断是否已经完成拼图,并提供了作弊键,一键完成拼图。
参考项目:Java Puzzle game - creating Java puzzle game clone
git地址:一路向北/ping
功能架构图
三、前期调查
根据网上的拼图小游戏界面为例:
-
开始界面:游戏加载完毕点击开始游戏
-
游戏过程:通过键盘键盘控制拼图方块移动完成拼图游戏
-
游戏内功能:可以对游戏重新开始、背景更改、整齐排序和乱序排序等
四、面对对象设计类图
-
GameInfo类图:存储游戏数据的javabean类,包含选择游戏图片,游戏步数,二维数组体现图片位置,以及确保对象在序列化和反序列化过程中能够正确地被处理。
GameInfo |
- long serialVersionUID = 122L - int [][]date - int x=0,y=0 - String path
|
+ GameInfo(int[][] date, int x, int y, String path, int step) + getter/setter + tostring |
-
User 类图:存储用户信息,包括用户名,密码
User |
- String username - String password; |
+ User(String username, String password) + getter/setter + tostring |
-
GameJFrame类图:对游戏ui进行显示并对游戏逻辑进行实现
GameJFrame |
- JMenuItem replayItem - JMenuItem reLoginItem - JMenuItem closeItem - JMenuItem accountItem - JMenuItem girl - JMenuItem animal - JMenuItem sport - JMenu saveJMenu - JMenu loadJMenu |
+ initData() 图片初始化 + initImage() 图片美化及胜利判断 + initJMenuBar() ui界面设计 + initJFrame() ui界面设计 + keyPressed(KeyEvent e) 键盘按压监听 + keyReleased(KeyEvent e) 键盘松开监听 + victory() 胜利判断 + actionPerformed(ActionEvent e) 动作监听 |
-
LoginJFrame类图:用于用户登录及登录ui设计
LoginJFrame |
- ArrayList<User> allUsers; - JButton login - JButton register - JTextField username - JPasswordField password - JTextField code -JLabel rightCode |
+ LoginJFrame() 初始化操作 + readUserInfo() 从文件读取信息 + initView() 初始化界面各个部分 + initJFrame() 登录ui设计 + mouseClicked(MouseEvent e) 鼠标点击监听 + mouseReleased(MouseEvent e) 鼠标松开监听 + showJDialog(String content) 展示弹窗 + mousePressed(MouseEvent e) |
-
RegisterJFrame类图:用于用户注册及注册ui设计
RegisterJFrame |
- ArrayList<User> allUsers; - JTextField username - JTextField password - JTextField rePassword - JButton submit - JButton reset |
+ RegisterJFrame(ArrayList<User> allUsers) 初始化窗体 + containsUsername(String username) 判断用户是否存在 + mousePressed(MouseEvent e) 鼠标按压监听 + mouseReleased(MouseEvent e) 鼠标松开监听 + initView() 注册ui设计 + initFrame() 窗体设置 + showDialog(String content) 展示弹窗 |
五、项目运行截图和代码展示
-
登录界面
-
注册界面
-
游戏界面
-
功能界面
六、项目关键代码
-
注册关键代码
1、在mouseClicked方法中,对用户输入的用户名和密码进行了格式校验,并且检查是否已存在相同的用户名,最终将用户信息添加到allUsers中,并写入文件中存储。
@Override
public void mouseClicked(MouseEvent e) {
if(e.getSource() == submit){
//点击了注册按钮
//1.用户名、密码不能为空
if(username.getText().length() == 0 || password.getText().length() == 0 || rePassword.getText().length() == 0){
showDialog("用户名和密码不能为空");
}
//2.判断两次输入是否一致
if(!password.getText().equals(rePassword.getText())){
showDialog("两次密码输入不一致");
return;
}
//3.判断用户名和密码格式是否正确
if(!username.getText().matches("[a-zA-Z0-9]{4,16}")){
showDialog("用户名不符合规则");
return;
}
if(!password.getText().matches("\\S*(?=\\S{6,})(?=\\S*[a-z])\\S*")){
showDialog("密码不符合规则,至少包含1个小写字母,1个数字,长度至少6位");
return;
}
//4.判断用户名是否已经重复
if(containsUsername(username.getText())){
showDialog("用户名已经存在,请重新输入");
return;
}
//5.添加用户
allUsers.add(new User(username.getText(),password.getText()));
//写入文件
FileUtil.writeLines(allUsers,"D:\\ideacode\\ping\\puzzlegame\\userinfo.txt","UTF-8");
//7.提示注册成功
showDialog("注册成功");
// Dialog.setLocationRelativeTo(null);
this.setVisible(false);
new LoginJFrame();
} else if (e.getSource() == reset) {
//点击了重置按钮
//要清空三个输入框
username.setText("");
password.setText("");
rePassword.setText("");
}
}
2、containsUsername方法用于判定用户输入的用户名是否已存在于用户信息列表中。
public boolean containsUsername(String username){
for (User u : allUsers) {
if(u.getUsername().equals(username)){
return true;
}
}
return false;
}
3、initView方法初始化了注册界面的各个组件,包括用户名、密码和重复密码的文本框,注册按钮和重置按钮等。
private void initView() {
//添加注册用户名的文本
//添加注册用户名的输入框
//添加注册密码的文本
//添加密码输入框
//添加再次输入密码的文本
//注册的按钮
//重置的按钮
//背景图片
this.getContentPane().add(usernameText);
this.getContentPane().add(passwordText);
this.getContentPane().add(rePasswordText);
this.getContentPane().add(username);
this.getContentPane().add(password);
this.getContentPane().add(rePassword);
this.getContentPane().add(submit);
this.getContentPane().add(reset);
this.getContentPane().add(background);
}
-
登录关键代码
1、readUserInfo方法用于从本地文件中读取用户信息并将其存储到allUsers集合中。
private void readUserInfo() {
//1.读取数据
List<String> userInfoStrList = FileUtil.readUtf8Lines("D:\\code\\ping\\puzzlegame\\userinfo.txt");
//2.遍历集合获取用户信息并创建User对象
for (String str : userInfoStrList) {
//username=zhangsan&password=123;
String[] userInfoArr = str.split("&");
//0 username=zhangsan 1 password=123
String[] arr1 = userInfoArr[0].split("=");
String[] arr2 = userInfoArr[1].split("=");
User u = new User(arr1[1], arr2[1]);
allUsers.add(u);
}
System.out.println(allUsers);
}
2、initJFrame方法设置了窗体的基本属性,包括大小、标题、关闭模式、居中和置顶。
public void initJFrame() {
this.setSize(488, 430);//设置宽高
this.setTitle("拼图游戏 V1.0登录");//设置标题
this.setDefaultCloseOperation(3);//设置关闭模式
this.setLocationRelativeTo(null);//居中
this.setAlwaysOnTop(true);//置顶
this.setLayout(null);//取消内部默认布局
}
3、mouseClicked方法中对鼠标点击事件进行了处理,包括登录按钮、注册按钮和验证码的逻辑。其中涉及了用户名和密码的校验,验证码的验证,以及判断用户是否存在于用户集合中,适当展示弹框应对不同的操作结果。
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);
if (codeInput.length() == 0) {
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);
}
}
4、 showJDialog方法用于展示弹框信息,包括设置弹框的文字内容、大小、位置和模态等属性。
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);
}
5、contains方法用于判断用户输入的用户名和密码是否存在于allUsers集合中。
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;
}
-
游戏关键代码
1、说明:实现 KeyListener 接口,用于处理按键的按下和释放事件,以移动图块并触发其他动作,如解谜或显示完整图片
public void keyReleased(KeyEvent e) {
int code = e.getKeyCode();
if (code == 37) {
System.out.println("向左");
if (y == 3) {
return;
}
arr[x][y] = arr[x][y + 1];
arr[x][y + 1] = 0;
y = y + 1;
step++;
initImage();
}
if (code == 38) {
System.out.println("向上");
if (x == 3) {
return;
}
arr[x][y] = arr[x + 1][y];
arr[x + 1][y] = 0;
x = x + 1;
step++;
initImage();
}
if (code == 39) {
System.out.println("向右");
if (y == 0) {
return;
}
arr[x][y] = arr[x][y - 1];
arr[x][y - 1] = 0;
y = y - 1;
step++;
initImage();
}
if (code == 40) {
System.out.println("向下");
if (x == 0) {
return;
}
arr[x][y] = arr[x - 1][y];
arr[x - 1][y] = 0;
x = x - 1;
step++;
initImage();
} else if (code == 65) {
initImage();
} else if (code == 87) {
arr = new int[][]{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 0}
};
x = 3;
y = 3;
initImage();
}
}
2、定义用户与菜单项交互时要采取的动作,如重新开始游戏、重新登录、关闭、更换图片、保存和加载游戏状态等。
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == replayItem) {
initData();
initImage();
} else if (e.getSource() == reLoginItem) {
// 处理用户重新登录逻辑
}
// ... 处理其他菜单项动作
}
3、检查当前图块排列是否与获胜状态相匹配。
public boolean victory() {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if (arr[i][j] != data[i][j]) {
return false;
}
}
}
return true;
}
七、项目代码扫描结果及改造
使用阿里巴巴静态扫描工具对我们的项目进行扫描
修改后
八、项目总结
这次课设最大的难度在于理清思路,首先组长设计功能并思考实现方式就花了很多时间,并且还要把思路传达给各个组员,所以我们组需要频繁地讨论。最终项目的目标还是成功达到,成果也符合了预期。不足之处在于有些更复杂也更困难的功能没有实现,例如用户无法自己上传喜欢的拼图,游戏没有分简单、困难的模式,这需要实现图片自动随机切割,比较困难。游戏图形弹窗等也较为简单。总的来说游戏的基本功能都已经实现,进一步完成的任务就是要增加一些功能使其更加完善、更加美观。最后,这次课设巩固了全体组员的 Java 基础和进阶知识,大幅度加强了编码能力,并且培养了集体荣誉感。